mirror of
https://github.com/hyprwm/xdg-desktop-portal-hyprland.git
synced 2024-11-25 07:35:57 +01:00
feat: add session restore
This commit is contained in:
parent
e48165c563
commit
ab8d54f6f6
8 changed files with 250 additions and 93 deletions
|
@ -4,15 +4,17 @@
|
||||||
#include <gbm.h>
|
#include <gbm.h>
|
||||||
#include <pipewire/pipewire.h>
|
#include <pipewire/pipewire.h>
|
||||||
#include <spa/param/video/format-utils.h>
|
#include <spa/param/video/format-utils.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <wayland-client-protocol.h>
|
#include <wayland-client-protocol.h>
|
||||||
#include <xf86drm.h>
|
#include <xf86drm.h>
|
||||||
|
|
||||||
#include "fps_limit.h"
|
#include "fps_limit.h"
|
||||||
#include "hyprland-toplevel-export-v1-client-protocol.h"
|
#include "hyprland-toplevel-export-v1-client-protocol.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
// this seems to be right based on
|
// this seems to be right based on
|
||||||
// https://github.com/flatpak/xdg-desktop-portal/blob/309a1fc0cf2fb32cceb91dbc666d20cf0a3202c2/src/screen-cast.c#L955
|
// https://github.com/flatpak/xdg-desktop-portal/blob/309a1fc0cf2fb32cceb91dbc666d20cf0a3202c2/src/screen-cast.c#L955
|
||||||
#define XDP_CAST_PROTO_VER 2
|
#define XDP_CAST_PROTO_VER 3
|
||||||
|
|
||||||
enum cursor_modes {
|
enum cursor_modes {
|
||||||
HIDDEN = 1,
|
HIDDEN = 1,
|
||||||
|
@ -157,6 +159,14 @@ struct xdpw_share {
|
||||||
int window_handle;
|
int window_handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct xdph_restore_token {
|
||||||
|
char *token;
|
||||||
|
char *outputPort; // NULL if not set
|
||||||
|
uint64_t windowHandle; // 0 if not set
|
||||||
|
struct wl_list link;
|
||||||
|
bool withCursor;
|
||||||
|
};
|
||||||
|
|
||||||
struct xdpw_screencast_instance {
|
struct xdpw_screencast_instance {
|
||||||
// list
|
// list
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
|
@ -199,13 +209,20 @@ struct xdpw_screencast_instance {
|
||||||
struct fps_limit_state fps_limit;
|
struct fps_limit_state fps_limit;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SToplevelEntry {
|
||||||
|
struct zwlr_foreign_toplevel_handle_v1 *handle;
|
||||||
|
char name[256];
|
||||||
|
char clazz[256];
|
||||||
|
struct wl_list link;
|
||||||
|
};
|
||||||
|
|
||||||
void randname(char *buf);
|
void randname(char *buf);
|
||||||
struct gbm_device *xdpw_gbm_device_create(drmDevice *device);
|
struct gbm_device *xdpw_gbm_device_create(drmDevice *device);
|
||||||
struct xdpw_buffer *xdpw_buffer_create(struct xdpw_screencast_instance *cast,
|
struct xdpw_buffer *xdpw_buffer_create(struct xdpw_screencast_instance *cast, enum buffer_type buffer_type,
|
||||||
enum buffer_type buffer_type, struct xdpw_screencopy_frame_info *frame_info);
|
struct xdpw_screencopy_frame_info *frame_info);
|
||||||
void xdpw_buffer_destroy(struct xdpw_buffer *buffer);
|
void xdpw_buffer_destroy(struct xdpw_buffer *buffer);
|
||||||
bool wlr_query_dmabuf_modifiers(struct xdpw_screencast_context *ctx, uint32_t drm_format,
|
bool wlr_query_dmabuf_modifiers(struct xdpw_screencast_context *ctx, uint32_t drm_format, uint32_t num_modifiers, uint64_t *modifiers,
|
||||||
uint32_t num_modifiers, uint64_t *modifiers, uint32_t *max_modifiers);
|
uint32_t *max_modifiers);
|
||||||
enum wl_shm_format xdpw_format_wl_shm_from_drm_fourcc(uint32_t format);
|
enum wl_shm_format xdpw_format_wl_shm_from_drm_fourcc(uint32_t format);
|
||||||
uint32_t xdpw_format_drm_fourcc_from_wl_shm(enum wl_shm_format format);
|
uint32_t xdpw_format_drm_fourcc_from_wl_shm(enum wl_shm_format format);
|
||||||
enum spa_video_format xdpw_format_pw_from_drm_fourcc(uint32_t format);
|
enum spa_video_format xdpw_format_pw_from_drm_fourcc(uint32_t format);
|
||||||
|
|
6
include/utils.h
Normal file
6
include/utils.h
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
char *getFormat(const char *fmt, ...);
|
|
@ -30,6 +30,11 @@ struct xdpw_state {
|
||||||
struct wl_list timers;
|
struct wl_list timers;
|
||||||
struct xdpw_timer *next_timer;
|
struct xdpw_timer *next_timer;
|
||||||
struct globalShortcutsInstance shortcutsInstance;
|
struct globalShortcutsInstance shortcutsInstance;
|
||||||
|
|
||||||
|
// saved instances of screencast
|
||||||
|
// TODO: persist in storage
|
||||||
|
uint64_t lastRestoreToken;
|
||||||
|
struct wl_list restore_tokens; // xdph_restore_token
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xdpw_request {
|
struct xdpw_request {
|
||||||
|
@ -42,6 +47,7 @@ struct xdpw_session {
|
||||||
char *session_handle;
|
char *session_handle;
|
||||||
char *app_id;
|
char *app_id;
|
||||||
struct xdpw_screencast_instance *screencast_instance;
|
struct xdpw_screencast_instance *screencast_instance;
|
||||||
|
bool persist;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*xdpw_event_loop_timer_func_t)(void *data);
|
typedef void (*xdpw_event_loop_timer_func_t)(void *data);
|
||||||
|
|
|
@ -30,6 +30,7 @@ wayland_protos = dependency('wayland-protocols', version: '>=1.24')
|
||||||
iniparser = dependency('inih')
|
iniparser = dependency('inih')
|
||||||
gbm = dependency('gbm')
|
gbm = dependency('gbm')
|
||||||
drm = dependency('libdrm')
|
drm = dependency('libdrm')
|
||||||
|
uuid = dependency('uuid')
|
||||||
|
|
||||||
epoll = dependency('', required: false)
|
epoll = dependency('', required: false)
|
||||||
if (not cc.has_function('timerfd_create', prefix: '#include <sys/timerfd.h>') or
|
if (not cc.has_function('timerfd_create', prefix: '#include <sys/timerfd.h>') or
|
||||||
|
@ -78,6 +79,7 @@ xdpw_files = files([
|
||||||
'src/core/session.c',
|
'src/core/session.c',
|
||||||
'src/core/timer.c',
|
'src/core/timer.c',
|
||||||
'src/core/timespec_util.c',
|
'src/core/timespec_util.c',
|
||||||
|
'src/core/utils.c',
|
||||||
'src/screenshot/screenshot.c',
|
'src/screenshot/screenshot.c',
|
||||||
'src/screencast/screencast.c',
|
'src/screencast/screencast.c',
|
||||||
'src/screencast/screencast_common.c',
|
'src/screencast/screencast_common.c',
|
||||||
|
@ -99,6 +101,7 @@ executable(
|
||||||
gbm,
|
gbm,
|
||||||
drm,
|
drm,
|
||||||
epoll,
|
epoll,
|
||||||
|
uuid,
|
||||||
],
|
],
|
||||||
include_directories: [inc],
|
include_directories: [inc],
|
||||||
install: true,
|
install: true,
|
||||||
|
|
|
@ -122,6 +122,7 @@ int main(int argc, char *argv[]) {
|
||||||
};
|
};
|
||||||
|
|
||||||
wl_list_init(&state.xdpw_sessions);
|
wl_list_init(&state.xdpw_sessions);
|
||||||
|
wl_list_init(&state.restore_tokens);
|
||||||
|
|
||||||
initShortcutsInstance(&state, &state.shortcutsInstance);
|
initShortcutsInstance(&state, &state.shortcutsInstance);
|
||||||
|
|
||||||
|
|
12
src/core/utils.c
Normal file
12
src/core/utils.c
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
char *getFormat(const char *fmt, ...) {
|
||||||
|
char *outputStr = NULL;
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
vasprintf(&outputStr, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
return outputStr;
|
||||||
|
}
|
|
@ -7,9 +7,11 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <uuid/uuid.h>
|
||||||
|
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "pipewire_screencast.h"
|
#include "pipewire_screencast.h"
|
||||||
|
@ -47,8 +49,8 @@ void exec_with_shell(char *command) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void xdpw_screencast_instance_init(struct xdpw_screencast_context *ctx,
|
void xdpw_screencast_instance_init(struct xdpw_screencast_context *ctx, struct xdpw_screencast_instance *cast, struct xdpw_share out,
|
||||||
struct xdpw_screencast_instance *cast, struct xdpw_share out, bool with_cursor) {
|
bool with_cursor) {
|
||||||
// only run exec_before if there's no other instance running that already ran it
|
// only run exec_before if there's no other instance running that already ran it
|
||||||
if (wl_list_empty(&ctx->screencast_instances)) {
|
if (wl_list_empty(&ctx->screencast_instances)) {
|
||||||
char *exec_before = ctx->state->config->screencast_conf.exec_before;
|
char *exec_before = ctx->state->config->screencast_conf.exec_before;
|
||||||
|
@ -64,7 +66,9 @@ void xdpw_screencast_instance_init(struct xdpw_screencast_context *ctx,
|
||||||
cast->max_framerate = 60; // dirty
|
cast->max_framerate = 60; // dirty
|
||||||
} else {
|
} else {
|
||||||
if (ctx->state->config->screencast_conf.max_fps > 0) {
|
if (ctx->state->config->screencast_conf.max_fps > 0) {
|
||||||
cast->max_framerate = ctx->state->config->screencast_conf.max_fps < (uint32_t)out.output->framerate ? ctx->state->config->screencast_conf.max_fps : (uint32_t)out.output->framerate;
|
cast->max_framerate = ctx->state->config->screencast_conf.max_fps < (uint32_t)out.output->framerate
|
||||||
|
? ctx->state->config->screencast_conf.max_fps
|
||||||
|
: (uint32_t)out.output->framerate;
|
||||||
} else {
|
} else {
|
||||||
cast->max_framerate = (uint32_t)out.output->framerate;
|
cast->max_framerate = (uint32_t)out.output->framerate;
|
||||||
}
|
}
|
||||||
|
@ -79,8 +83,7 @@ void xdpw_screencast_instance_init(struct xdpw_screencast_context *ctx,
|
||||||
wl_list_init(&cast->buffer_list);
|
wl_list_init(&cast->buffer_list);
|
||||||
logprint(INFO, "xdpw: screencast instance %p has %d references", cast, cast->refcount);
|
logprint(INFO, "xdpw: screencast instance %p has %d references", cast, cast->refcount);
|
||||||
wl_list_insert(&ctx->screencast_instances, &cast->link);
|
wl_list_insert(&ctx->screencast_instances, &cast->link);
|
||||||
logprint(INFO, "xdpw: %d active screencast instances",
|
logprint(INFO, "xdpw: %d active screencast instances", wl_list_length(&ctx->screencast_instances));
|
||||||
wl_list_length(&ctx->screencast_instances));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void xdpw_screencast_instance_destroy(struct xdpw_screencast_instance *cast) {
|
void xdpw_screencast_instance_destroy(struct xdpw_screencast_instance *cast) {
|
||||||
|
@ -111,15 +114,46 @@ void xdpw_screencast_instance_teardown(struct xdpw_screencast_instance *cast) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setup_outputs(struct xdpw_screencast_context *ctx, struct xdpw_session *sess, bool with_cursor) {
|
bool setup_outputs(struct xdpw_screencast_context *ctx, struct xdpw_session *sess, bool with_cursor, struct xdph_restore_token *token) {
|
||||||
struct xdpw_wlr_output *output, *tmp_o;
|
struct xdpw_wlr_output *output, *tmp_o;
|
||||||
wl_list_for_each_reverse_safe(output, tmp_o, &ctx->output_list, link) {
|
wl_list_for_each_reverse_safe(output, tmp_o, &ctx->output_list, link) {
|
||||||
logprint(INFO, "wlroots: capturable output: %s model: %s: id: %i name: %s",
|
logprint(INFO, "wlroots: capturable output: %s model: %s: id: %i name: %s", output->make, output->model, output->id, output->name);
|
||||||
output->make, output->model, output->id, output->name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct xdpw_share out;
|
struct xdpw_share out;
|
||||||
out = xdpw_wlr_chooser(ctx);
|
out.window_handle = -1;
|
||||||
|
out.x = -1;
|
||||||
|
out.y = -1;
|
||||||
|
out.w = -1;
|
||||||
|
out.h = -1;
|
||||||
|
out.output = NULL;
|
||||||
|
bool tokenSuccess = false;
|
||||||
|
|
||||||
|
if (token) {
|
||||||
|
// attempt to restore
|
||||||
|
if (token->outputPort) {
|
||||||
|
struct xdpw_wlr_output *output;
|
||||||
|
wl_list_for_each(output, &ctx->output_list, link) {
|
||||||
|
if (strcmp(output->name, token->outputPort) == 0) {
|
||||||
|
out.output = output;
|
||||||
|
tokenSuccess = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (token->windowHandle > 0) {
|
||||||
|
struct SToplevelEntry *current;
|
||||||
|
wl_list_for_each(current, &ctx->toplevel_resource_list, link) {
|
||||||
|
if (((uint64_t)current->handle & 0xFFFFFFFF) == token->windowHandle) {
|
||||||
|
out.window_handle = token->windowHandle;
|
||||||
|
tokenSuccess = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tokenSuccess) out = xdpw_wlr_chooser(ctx);
|
||||||
|
|
||||||
if (!out.output && out.window_handle == -1) {
|
if (!out.output && out.window_handle == -1) {
|
||||||
logprint(ERROR, "wlroots: no output / window found");
|
logprint(ERROR, "wlroots: no output / window found");
|
||||||
return false;
|
return false;
|
||||||
|
@ -127,36 +161,34 @@ bool setup_outputs(struct xdpw_screencast_context *ctx, struct xdpw_session *ses
|
||||||
|
|
||||||
// Disable screencast sharing to avoid sharing between dmabuf and shm capable clients
|
// Disable screencast sharing to avoid sharing between dmabuf and shm capable clients
|
||||||
/*
|
/*
|
||||||
struct xdpw_screencast_instance *cast, *tmp_c;
|
struct xdpw_screencast_instance *cast, *tmp_c;
|
||||||
wl_list_for_each_reverse_safe(cast, tmp_c, &ctx->screencast_instances, link) {
|
wl_list_for_each_reverse_safe(cast, tmp_c, &ctx->screencast_instances, link) {
|
||||||
logprint(INFO, "xdpw: existing screencast instance: %d %s cursor",
|
logprint(INFO, "xdpw: existing screencast instance: %d %s cursor",
|
||||||
cast->target_output->id,
|
cast->target_output->id,
|
||||||
cast->with_cursor ? "with" : "without");
|
cast->with_cursor ? "with" : "without");
|
||||||
|
|
||||||
if (cast->target_output->id == out->id && cast->with_cursor == with_cursor) {
|
if (cast->target_output->id == out->id && cast->with_cursor == with_cursor) {
|
||||||
if (cast->refcount == 0) {
|
if (cast->refcount == 0) {
|
||||||
logprint(DEBUG,
|
logprint(DEBUG,
|
||||||
"xdpw: matching cast instance found, "
|
"xdpw: matching cast instance found, "
|
||||||
"but is already scheduled for destruction, skipping");
|
"but is already scheduled for destruction, skipping");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sess->screencast_instance = cast;
|
sess->screencast_instance = cast;
|
||||||
++cast->refcount;
|
++cast->refcount;
|
||||||
}
|
}
|
||||||
logprint(INFO, "xdpw: screencast instance %p now has %d references",
|
logprint(INFO, "xdpw: screencast instance %p now has %d references",
|
||||||
cast, cast->refcount);
|
cast, cast->refcount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!sess->screencast_instance) {
|
if (!sess->screencast_instance) {
|
||||||
sess->screencast_instance = calloc(1, sizeof(struct xdpw_screencast_instance));
|
sess->screencast_instance = calloc(1, sizeof(struct xdpw_screencast_instance));
|
||||||
xdpw_screencast_instance_init(ctx, sess->screencast_instance,
|
xdpw_screencast_instance_init(ctx, sess->screencast_instance, out, with_cursor);
|
||||||
out, with_cursor);
|
|
||||||
}
|
}
|
||||||
if (out.output) {
|
if (out.output) {
|
||||||
logprint(INFO, "wlroots: output: %s",
|
logprint(INFO, "wlroots: output: %s", sess->screencast_instance->target.output->name);
|
||||||
sess->screencast_instance->target.output->name);
|
|
||||||
} else {
|
} else {
|
||||||
logprint(INFO, "hyprland: window handle %d", sess->screencast_instance->target.window_handle);
|
logprint(INFO, "hyprland: window handle %d", sess->screencast_instance->target.window_handle);
|
||||||
}
|
}
|
||||||
|
@ -173,9 +205,8 @@ static int start_screencast(struct xdpw_screencast_instance *cast) {
|
||||||
wl_display_dispatch(cast->ctx->state->wl_display);
|
wl_display_dispatch(cast->ctx->state->wl_display);
|
||||||
wl_display_roundtrip(cast->ctx->state->wl_display);
|
wl_display_roundtrip(cast->ctx->state->wl_display);
|
||||||
|
|
||||||
if (cast->screencopy_frame_info[WL_SHM].format == DRM_FORMAT_INVALID ||
|
if (cast->screencopy_frame_info[WL_SHM].format == DRM_FORMAT_INVALID /*||
|
||||||
(cast->ctx->state->screencast_version >= 3 &&
|
(cast->ctx->state->screencast_version >= 3 && cast->screencopy_frame_info[DMABUF].format == DRM_FORMAT_INVALID)*/) {
|
||||||
cast->screencopy_frame_info[DMABUF].format == DRM_FORMAT_INVALID)) {
|
|
||||||
logprint(INFO, "wlroots: unable to receive a valid format from wlr_screencopy");
|
logprint(INFO, "wlroots: unable to receive a valid format from wlr_screencopy");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -186,8 +217,42 @@ static int start_screencast(struct xdpw_screencast_instance *cast) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int method_screencast_create_session(sd_bus_message *msg, void *data,
|
static struct xdph_restore_token *findRestoreToken(char *token, struct xdpw_state *state) {
|
||||||
sd_bus_error *ret_error) {
|
struct xdph_restore_token *current;
|
||||||
|
wl_list_for_each(current, &state->restore_tokens, link) {
|
||||||
|
if (strcmp(current->token, token) == 0) {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct xdph_restore_token *getRestoreToken(char *sessionToken, struct xdpw_state *state, char *outputSelected, uint64_t windowSelected,
|
||||||
|
bool withCursor) {
|
||||||
|
state->lastRestoreToken++;
|
||||||
|
uuid_t uuid;
|
||||||
|
uuid_generate_random(uuid);
|
||||||
|
char *uuid_str = malloc(37);
|
||||||
|
uuid_unparse_upper(uuid, uuid_str);
|
||||||
|
while (findRestoreToken(uuid_str, state) != NULL) {
|
||||||
|
uuid_generate_random(uuid);
|
||||||
|
uuid_unparse_upper(uuid, uuid_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct xdph_restore_token *restoreToken = calloc(1, sizeof(struct xdph_restore_token));
|
||||||
|
if (outputSelected) {
|
||||||
|
restoreToken->outputPort = strdup(outputSelected);
|
||||||
|
}
|
||||||
|
restoreToken->windowHandle = windowSelected;
|
||||||
|
|
||||||
|
restoreToken->token = uuid_str;
|
||||||
|
restoreToken->withCursor = withCursor;
|
||||||
|
|
||||||
|
return restoreToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int method_screencast_create_session(sd_bus_message *msg, void *data, sd_bus_error *ret_error) {
|
||||||
struct xdpw_state *state = data;
|
struct xdpw_state *state = data;
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -240,14 +305,12 @@ static int method_screencast_create_session(sd_bus_message *msg, void *data,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct xdpw_request *req =
|
struct xdpw_request *req = xdpw_request_create(sd_bus_message_get_bus(msg), request_handle);
|
||||||
xdpw_request_create(sd_bus_message_get_bus(msg), request_handle);
|
|
||||||
if (req == NULL) {
|
if (req == NULL) {
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct xdpw_session *sess =
|
struct xdpw_session *sess = xdpw_session_create(state, sd_bus_message_get_bus(msg), strdup(session_handle));
|
||||||
xdpw_session_create(state, sd_bus_message_get_bus(msg), strdup(session_handle));
|
|
||||||
if (sess == NULL) {
|
if (sess == NULL) {
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
@ -270,8 +333,7 @@ static int method_screencast_create_session(sd_bus_message *msg, void *data,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int method_screencast_select_sources(sd_bus_message *msg, void *data,
|
static int method_screencast_select_sources(sd_bus_message *msg, void *data, sd_bus_error *ret_error) {
|
||||||
sd_bus_error *ret_error) {
|
|
||||||
struct xdpw_state *state = data;
|
struct xdpw_state *state = data;
|
||||||
struct xdpw_screencast_context *ctx = &state->screencast;
|
struct xdpw_screencast_context *ctx = &state->screencast;
|
||||||
|
|
||||||
|
@ -300,6 +362,10 @@ static int method_screencast_select_sources(sd_bus_message *msg, void *data,
|
||||||
|
|
||||||
char *key;
|
char *key;
|
||||||
int innerRet = 0;
|
int innerRet = 0;
|
||||||
|
uint32_t persist = 0;
|
||||||
|
|
||||||
|
struct xdph_restore_token *foundToken = NULL;
|
||||||
|
|
||||||
while ((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
|
while ((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
|
||||||
innerRet = sd_bus_message_read(msg, "s", &key);
|
innerRet = sd_bus_message_read(msg, "s", &key);
|
||||||
if (innerRet < 0) {
|
if (innerRet < 0) {
|
||||||
|
@ -326,9 +392,57 @@ static int method_screencast_select_sources(sd_bus_message *msg, void *data,
|
||||||
}
|
}
|
||||||
if (cursor_mode & METADATA) {
|
if (cursor_mode & METADATA) {
|
||||||
logprint(ERROR, "dbus: unsupported cursor mode requested, ignoring");
|
logprint(ERROR, "dbus: unsupported cursor mode requested, ignoring");
|
||||||
// goto error;
|
// goto error;
|
||||||
}
|
}
|
||||||
logprint(INFO, "dbus: option cursor_mode:%x", cursor_mode);
|
logprint(INFO, "dbus: option cursor_mode:%x", cursor_mode);
|
||||||
|
} else if (strcmp(key, "restore_token") == 0) {
|
||||||
|
char *restoreToken;
|
||||||
|
sd_bus_message_read(msg, "v", "s", &restoreToken);
|
||||||
|
|
||||||
|
logprint(INFO, "dbus: restore_token %s", restoreToken);
|
||||||
|
|
||||||
|
foundToken = findRestoreToken(restoreToken, state);
|
||||||
|
} else if (strcmp(key, "restore_data") == 0) {
|
||||||
|
logprint(INFO, "dbus: restore_data");
|
||||||
|
innerRet = sd_bus_message_enter_container(msg, 'v', "(suv)");
|
||||||
|
if (innerRet < 0) {
|
||||||
|
logprint(ERROR, "dbus: restore_data malformed container");
|
||||||
|
return innerRet;
|
||||||
|
}
|
||||||
|
innerRet = sd_bus_message_enter_container(msg, 'r', "suv");
|
||||||
|
if (innerRet < 0) {
|
||||||
|
logprint(ERROR, "dbus: error entering struct");
|
||||||
|
return innerRet;
|
||||||
|
}
|
||||||
|
char *issuer;
|
||||||
|
sd_bus_message_read(msg, "s", &issuer);
|
||||||
|
if (strcmp(issuer, "hyprland") != 0) {
|
||||||
|
logprint(INFO, "dbus: skipping unknown issuer (%s)", issuer);
|
||||||
|
sd_bus_message_skip(msg, "uv");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
uint32_t ver;
|
||||||
|
sd_bus_message_read(msg, "u", &ver);
|
||||||
|
|
||||||
|
if (ver == 1) {
|
||||||
|
char *restoreToken;
|
||||||
|
sd_bus_message_read(msg, "v", "s", &restoreToken);
|
||||||
|
|
||||||
|
logprint(INFO, "dbus: restore_token %s", restoreToken);
|
||||||
|
|
||||||
|
foundToken = findRestoreToken(restoreToken, state);
|
||||||
|
|
||||||
|
if (foundToken)
|
||||||
|
logprint(INFO, "xdph: found token %s", restoreToken);
|
||||||
|
else
|
||||||
|
logprint(INFO, "xdph: token not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
sd_bus_message_exit_container(msg);
|
||||||
|
sd_bus_message_exit_container(msg);
|
||||||
|
} else if (strcmp(key, "persist_mode") == 0) {
|
||||||
|
sd_bus_message_read(msg, "v", "u", &persist);
|
||||||
|
logprint(INFO, "dbus: persist %d", persist);
|
||||||
} else {
|
} else {
|
||||||
logprint(WARN, "dbus: unknown option %s", key);
|
logprint(WARN, "dbus: unknown option %s", key);
|
||||||
sd_bus_message_skip(msg, "v");
|
sd_bus_message_skip(msg, "v");
|
||||||
|
@ -351,7 +465,17 @@ static int method_screencast_select_sources(sd_bus_message *msg, void *data,
|
||||||
wl_list_for_each_reverse_safe(sess, tmp_s, &state->xdpw_sessions, link) {
|
wl_list_for_each_reverse_safe(sess, tmp_s, &state->xdpw_sessions, link) {
|
||||||
if (strcmp(sess->session_handle, session_handle) == 0) {
|
if (strcmp(sess->session_handle, session_handle) == 0) {
|
||||||
logprint(DEBUG, "dbus: select sources: found matching session %s", sess->session_handle);
|
logprint(DEBUG, "dbus: select sources: found matching session %s", sess->session_handle);
|
||||||
output_selection_canceled = !setup_outputs(ctx, sess, cursor_embedded);
|
|
||||||
|
output_selection_canceled = !setup_outputs(ctx, sess, cursor_embedded, foundToken);
|
||||||
|
|
||||||
|
sess->persist = persist;
|
||||||
|
|
||||||
|
// foundToken has been used, if it existed
|
||||||
|
if (foundToken) {
|
||||||
|
wl_list_remove(&foundToken->link);
|
||||||
|
free(foundToken);
|
||||||
|
foundToken = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,8 +522,7 @@ error:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int method_screencast_start(sd_bus_message *msg, void *data,
|
static int method_screencast_start(sd_bus_message *msg, void *data, sd_bus_error *ret_error) {
|
||||||
sd_bus_error *ret_error) {
|
|
||||||
struct xdpw_state *state = data;
|
struct xdpw_state *state = data;
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -470,6 +593,17 @@ static int method_screencast_start(sd_bus_message *msg, void *data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create token
|
||||||
|
struct xdph_restore_token *restoreToken = NULL;
|
||||||
|
if (sess->persist) {
|
||||||
|
restoreToken = getRestoreToken(session_handle, state, cast->target.output ? cast->target.output->name : NULL,
|
||||||
|
cast->target.window_handle < 1 ? 0 : cast->target.window_handle, cast->with_cursor);
|
||||||
|
|
||||||
|
wl_list_insert(&state->restore_tokens, &restoreToken->link);
|
||||||
|
|
||||||
|
logprint(INFO, "xdph: registered restoreToken with token %s", restoreToken->token);
|
||||||
|
}
|
||||||
|
|
||||||
sd_bus_message *reply = NULL;
|
sd_bus_message *reply = NULL;
|
||||||
ret = sd_bus_message_new_method_return(msg, &reply);
|
ret = sd_bus_message_new_method_return(msg, &reply);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -477,11 +611,15 @@ static int method_screencast_start(sd_bus_message *msg, void *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
logprint(DEBUG, "dbus: start: returning node %d", (int)cast->node_id);
|
logprint(DEBUG, "dbus: start: returning node %d", (int)cast->node_id);
|
||||||
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_SUCCESS, 1,
|
if (restoreToken)
|
||||||
"streams", "a(ua{sv})", 1,
|
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_SUCCESS, 3, "streams", "a(ua{sv})", 1, cast->node_id, 3, "position", "(ii)", 0,
|
||||||
cast->node_id, 2,
|
0, "size", "(ii)", cast->screencopy_frame_info[WL_SHM].width, cast->screencopy_frame_info[WL_SHM].height,
|
||||||
"position", "(ii)", 0, 0,
|
"source_type", "u", (cast->target.output ? (1 << MONITOR) : (1 << WINDOW)), "persist_mode", "u", sess->persist,
|
||||||
"size", "(ii)", cast->screencopy_frame_info[WL_SHM].width, cast->screencopy_frame_info[WL_SHM].height);
|
"restore_data", "(suv)", "hyprland", 1, "s", restoreToken->token);
|
||||||
|
else
|
||||||
|
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_SUCCESS, 1, "streams", "a(ua{sv})", 1, cast->node_id, 3, "position", "(ii)", 0,
|
||||||
|
0, "size", "(ii)", cast->screencopy_frame_info[WL_SHM].width, cast->screencopy_frame_info[WL_SHM].height,
|
||||||
|
"source_type", "u", (cast->target.output ? (1 << MONITOR) : (1 << WINDOW)));
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -498,21 +636,12 @@ static int method_screencast_start(sd_bus_message *msg, void *data,
|
||||||
|
|
||||||
static const sd_bus_vtable screencast_vtable[] = {
|
static const sd_bus_vtable screencast_vtable[] = {
|
||||||
SD_BUS_VTABLE_START(0),
|
SD_BUS_VTABLE_START(0),
|
||||||
SD_BUS_METHOD("CreateSession", "oosa{sv}", "ua{sv}",
|
SD_BUS_METHOD("CreateSession", "oosa{sv}", "ua{sv}", method_screencast_create_session, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
method_screencast_create_session, SD_BUS_VTABLE_UNPRIVILEGED),
|
SD_BUS_METHOD("SelectSources", "oosa{sv}", "ua{sv}", method_screencast_select_sources, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
SD_BUS_METHOD("SelectSources", "oosa{sv}", "ua{sv}",
|
SD_BUS_METHOD("Start", "oossa{sv}", "ua{sv}", method_screencast_start, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
method_screencast_select_sources, SD_BUS_VTABLE_UNPRIVILEGED),
|
SD_BUS_PROPERTY("AvailableSourceTypes", "u", NULL, offsetof(struct xdpw_state, screencast_source_types), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_METHOD("Start", "oossa{sv}", "ua{sv}",
|
SD_BUS_PROPERTY("AvailableCursorModes", "u", NULL, offsetof(struct xdpw_state, screencast_cursor_modes), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
method_screencast_start, SD_BUS_VTABLE_UNPRIVILEGED),
|
SD_BUS_PROPERTY("version", "u", NULL, offsetof(struct xdpw_state, screencast_version), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("AvailableSourceTypes", "u", NULL,
|
|
||||||
offsetof(struct xdpw_state, screencast_source_types),
|
|
||||||
SD_BUS_VTABLE_PROPERTY_CONST),
|
|
||||||
SD_BUS_PROPERTY("AvailableCursorModes", "u", NULL,
|
|
||||||
offsetof(struct xdpw_state, screencast_cursor_modes),
|
|
||||||
SD_BUS_VTABLE_PROPERTY_CONST),
|
|
||||||
SD_BUS_PROPERTY("version", "u", NULL,
|
|
||||||
offsetof(struct xdpw_state, screencast_version),
|
|
||||||
SD_BUS_VTABLE_PROPERTY_CONST),
|
|
||||||
SD_BUS_VTABLE_END};
|
SD_BUS_VTABLE_END};
|
||||||
|
|
||||||
int xdpw_screencast_init(struct xdpw_state *state) {
|
int xdpw_screencast_init(struct xdpw_state *state) {
|
||||||
|
@ -533,8 +662,7 @@ int xdpw_screencast_init(struct xdpw_state *state) {
|
||||||
goto fail_screencopy;
|
goto fail_screencopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sd_bus_add_object_vtable(state->bus, &slot, object_path, interface_name,
|
return sd_bus_add_object_vtable(state->bus, &slot, object_path, interface_name, screencast_vtable, state);
|
||||||
screencast_vtable, state);
|
|
||||||
|
|
||||||
fail_screencopy:
|
fail_screencopy:
|
||||||
xdpw_wlr_screencopy_finish(&state->screencast);
|
xdpw_wlr_screencopy_finish(&state->screencast);
|
||||||
|
|
|
@ -26,13 +26,6 @@
|
||||||
#include "xdpw.h"
|
#include "xdpw.h"
|
||||||
//
|
//
|
||||||
|
|
||||||
struct SToplevelEntry {
|
|
||||||
struct zwlr_foreign_toplevel_handle_v1 *handle;
|
|
||||||
char name[256];
|
|
||||||
char clazz[256];
|
|
||||||
struct wl_list link;
|
|
||||||
};
|
|
||||||
|
|
||||||
void handleTitle(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, const char *title) {
|
void handleTitle(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, const char *title) {
|
||||||
struct xdpw_screencast_context *ctx = data;
|
struct xdpw_screencast_context *ctx = data;
|
||||||
|
|
||||||
|
@ -577,6 +570,8 @@ static void wlr_xdg_output_name(void *data, struct zxdg_output_v1 *xdg_output, c
|
||||||
struct xdpw_wlr_output *output = data;
|
struct xdpw_wlr_output *output = data;
|
||||||
|
|
||||||
output->name = strdup(name);
|
output->name = strdup(name);
|
||||||
|
|
||||||
|
logprint(INFO, "Output %lx name: %s", data, name);
|
||||||
};
|
};
|
||||||
|
|
||||||
static void noop() {
|
static void noop() {
|
||||||
|
@ -637,17 +632,6 @@ static inline int vasprintf(char **strp, const char *fmt, va_list ap) {
|
||||||
return str_size;
|
return str_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *getFormat(const char *fmt, ...) {
|
|
||||||
char *outputStr = NULL;
|
|
||||||
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
vasprintf(&outputStr, fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
return outputStr;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *buildWindowList(struct xdpw_screencast_context *ctx) {
|
char *buildWindowList(struct xdpw_screencast_context *ctx) {
|
||||||
char *rolling = calloc(1, 1);
|
char *rolling = calloc(1, 1);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue