Skip to content

Commit

Permalink
screencast: implement restore token
Browse files Browse the repository at this point in the history
  • Loading branch information
columbarius committed Jan 16, 2022
1 parent 599a480 commit 2a399db
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 41 deletions.
11 changes: 10 additions & 1 deletion include/screencast_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

// this seems to be right based on
// https://github.com/flatpak/xdg-desktop-portal/blob/309a1fc0cf2fb32cceb91dbc666d20cf0a3202c2/src/screen-cast.c#L955
#define XDP_CAST_PROTO_VER 3
#define XDP_CAST_PROTO_VER 4
#define XDP_CAST_DATA_VER 1

enum cursor_modes {
HIDDEN = 1,
Expand Down Expand Up @@ -121,6 +122,14 @@ struct xdpw_screencast_instance {
struct fps_limit_state fps_limit;
};

struct xdpw_screencast_session_data {
uint32_t version;
struct xdpw_screencast_instance *screencast_instance;
char *output_name;
uint32_t cursor_mode;
uint32_t persist_mode;
};

struct xdpw_wlr_output {
struct wl_list link;
uint32_t id;
Expand Down
2 changes: 1 addition & 1 deletion include/xdpw.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ struct xdpw_session {
struct wl_list link;
sd_bus_slot *slot;
char *session_handle;
struct xdpw_screencast_instance *screencast_instance;
struct xdpw_screencast_session_data screencast_data;
};

typedef void (*xdpw_event_loop_timer_func_t)(void *data);
Expand Down
3 changes: 2 additions & 1 deletion src/core/session.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ void xdpw_session_destroy(struct xdpw_session *sess) {
if (!sess) {
return;
}
struct xdpw_screencast_instance *cast = sess->screencast_instance;
struct xdpw_screencast_instance *cast = sess->screencast_data.screencast_instance;
if (cast) {
assert(cast->refcount > 0);
--cast->refcount;
Expand All @@ -71,6 +71,7 @@ void xdpw_session_destroy(struct xdpw_session *sess) {
cast->quit = true;
}
}
free(sess->screencast_data.output_name);

sd_bus_slot_unref(sess->slot);
wl_list_remove(&sess->link);
Expand Down
150 changes: 112 additions & 38 deletions src/screencast/screencast.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,21 +94,29 @@ void xdpw_screencast_instance_destroy(struct xdpw_screencast_instance *cast) {
free(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) {

struct xdpw_wlr_output *output, *tmp_o;
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",
output->make, output->model, output->id, output->name);
}

struct xdpw_wlr_output *out;
out = xdpw_wlr_output_chooser(ctx);
struct xdpw_wlr_output *out = NULL;
if (sess->screencast_data.output_name) {
out = xdpw_wlr_output_find_by_name(&ctx->output_list, sess->screencast_data.output_name);
}
if (!out) {
out = xdpw_wlr_output_chooser(ctx);
}
if (!out) {
logprint(ERROR, "wlroots: no output found");
return false;
}

// default to embedded cursor mode if not specified
bool with_cursor = sess->screencast_data.cursor_mode & HIDDEN ? false : true;

struct xdpw_screencast_instance *cast, *tmp_c;
wl_list_for_each_reverse_safe(cast, tmp_c, &ctx->screencast_instances, link) {
logprint(INFO, "xdpw: existing screencast instance: %d %s cursor",
Expand All @@ -122,21 +130,21 @@ bool setup_outputs(struct xdpw_screencast_context *ctx, struct xdpw_session *ses
"but is already scheduled for destruction, skipping");
}
else {
sess->screencast_instance = cast;
sess->screencast_data.screencast_instance = cast;
++cast->refcount;
}
logprint(INFO, "xdpw: screencast instance %p now has %d references",
cast, cast->refcount);
}
}

if (!sess->screencast_instance) {
sess->screencast_instance = calloc(1, sizeof(struct xdpw_screencast_instance));
xdpw_screencast_instance_init(ctx, sess->screencast_instance,
if (!sess->screencast_data.screencast_instance) {
sess->screencast_data.screencast_instance = calloc(1, sizeof(struct xdpw_screencast_instance));
xdpw_screencast_instance_init(ctx, sess->screencast_data.screencast_instance,
out, with_cursor);
}
logprint(INFO, "wlroots: output: %s",
sess->screencast_instance->target_output->name);
sess->screencast_data.output_name = strdup(sess->screencast_data.screencast_instance->target_output->name);
logprint(INFO, "wlroots: output: %s", sess->screencast_data.output_name);

return true;

Expand Down Expand Up @@ -252,9 +260,6 @@ static int method_screencast_select_sources(sd_bus_message *msg, void *data,

logprint(INFO, "dbus: select sources method invoked");

// default to embedded cursor mode if not specified
bool cursor_embedded = true;

char *request_handle, *session_handle, *app_id;
ret = sd_bus_message_read(msg, "oos", &request_handle, &session_handle, &app_id);
if (ret < 0) {
Expand All @@ -269,6 +274,19 @@ static int method_screencast_select_sources(sd_bus_message *msg, void *data,
logprint(INFO, "dbus: session_handle: %s", session_handle);
logprint(INFO, "dbus: app_id: %s", app_id);

sess = NULL;
wl_list_for_each_reverse_safe(sess, tmp_s, &state->xdpw_sessions, link) {
if (strcmp(sess->session_handle, session_handle) == 0) {
logprint(DEBUG, "dbus: select sources: found matching session %s", sess->session_handle);
break;
}
}

if (!sess) {
logprint(WARN, "dbus: select sources: no matching session %s found", sess->session_handle);
goto error;
}

char *key;
int innerRet = 0;
while ((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
Expand All @@ -290,16 +308,59 @@ static int method_screencast_select_sources(sd_bus_message *msg, void *data,
}
logprint(INFO, "dbus: option types:%x", mask);
} else if (strcmp(key, "cursor_mode") == 0) {
uint32_t cursor_mode;
sd_bus_message_read(msg, "v", "u", &cursor_mode);
if (cursor_mode & HIDDEN) {
cursor_embedded = false;
}
if (cursor_mode & METADATA) {
sd_bus_message_read(msg, "v", "u", &sess->screencast_data.cursor_mode);
if (sess->screencast_data.cursor_mode & METADATA) {
logprint(ERROR, "dbus: unsupported cursor mode requested, cancelling");
goto error;
}
logprint(INFO, "dbus: option cursor_mode:%x", cursor_mode);
logprint(INFO, "dbus: option cursor_mode:%x", sess->screencast_data.cursor_mode);
} else if (strcmp(key, "restore_data") == 0) {
logprint(INFO, "dbus: restore data available");
char *portal_vendor;
uint32_t restore_data_version;
innerRet = sd_bus_message_enter_container(msg, 'v', "(suv)");
if (innerRet < 0) {
return innerRet;
}
if (strcmp(portal_vendor, "wlroots") != 0) {
sd_bus_message_read(msg, "v", "su", &portal_vendor, &restore_data_version);
logprint(INFO, "dbus: skipping restore_data from another vendor (%s)", portal_vendor);
continue;
}
innerRet = sd_bus_message_enter_container(msg, 'v', "a{sv}");
if (innerRet < 0) {
return innerRet;
}
innerRet = sd_bus_message_enter_container(msg, 'a', "{sv}");
if (innerRet < 0) {
return innerRet;
}
logprint(INFO, "dbus: restoring session from data");
int rdRet;
char *rdKey;
while ((innerRet = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
rdRet = sd_bus_message_read(msg, "s", &rdKey);
if (rdRet < 0) {
return rdRet;
}
if (strcmp(rdKey, "output_name") == 0) {
char *output_name;
sd_bus_message_read(msg, "v", "s", &output_name);
if (output_name) {
sess->screencast_data.output_name = strdup(output_name);
}
logprint(INFO, "dbus: option restore_data.output_name:%s", sess->screencast_data.output_name);
} else {
logprint(WARN, "dbus: unknown option %s", rdKey);
sd_bus_message_skip(msg, "v");
}
}
if (innerRet < 0) {
return innerRet;
}
} else if (strcmp(key, "persist_mode") == 0) {
sd_bus_message_read(msg, "v", "u", &sess->screencast_data.persist_mode);
logprint(INFO, "dbus: option persist_mode:%u", sess->screencast_data.persist_mode);
} else {
logprint(WARN, "dbus: unknown option %s", key);
sd_bus_message_skip(msg, "v");
Expand All @@ -319,12 +380,7 @@ static int method_screencast_select_sources(sd_bus_message *msg, void *data,
}

bool output_selection_canceled = 1;
wl_list_for_each_reverse_safe(sess, tmp_s, &state->xdpw_sessions, link) {
if (strcmp(sess->session_handle, session_handle) == 0) {
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);

ret = sd_bus_message_new_method_return(msg, &reply);
if (ret < 0) {
Expand All @@ -346,11 +402,8 @@ static int method_screencast_select_sources(sd_bus_message *msg, void *data,
return 0;

error:
wl_list_for_each_reverse_safe(sess, tmp_s, &state->xdpw_sessions, link) {
if (strcmp(sess->session_handle, session_handle) == 0) {
logprint(DEBUG, "dbus: select sources error: destroying matching session %s", sess->session_handle);
xdpw_session_destroy(sess);
}
if (sess) {
xdpw_session_destroy(sess);
}

ret = sd_bus_message_new_method_return(msg, &reply);
Expand Down Expand Up @@ -419,14 +472,15 @@ static int method_screencast_start(sd_bus_message *msg, void *data,
wl_list_for_each_reverse_safe(sess, tmp_s, &state->xdpw_sessions, link) {
if (strcmp(sess->session_handle, session_handle) == 0) {
logprint(DEBUG, "dbus: start: found matching session %s", sess->session_handle);
cast = sess->screencast_instance;
cast = sess->screencast_data.screencast_instance;
break;
}
}
if (!cast) {
return -1;
}

if (!cast->initialized) {

start_screencast(cast);
}

Expand All @@ -444,12 +498,32 @@ static int method_screencast_start(sd_bus_message *msg, void *data,
}

logprint(DEBUG, "dbus: start: returning node %d", (int)cast->node_id);
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.width, cast->screencopy_frame.height,
"source_type", "u", 1 << MONITOR);
logprint(ERROR, "dbus: start: returning output (%s)", sess->screencast_data.output_name);
logprint(ERROR, "dbus: start: returning output (%s)", cast->target_output->name);
switch (sess->screencast_data.persist_mode) {
case 1:
case 2:
logprint(DEBUG, "Persistmode");
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_SUCCESS, 3,
"streams", "a(ua{sv})", 1,
cast->node_id, 3,
"position", "(ii)", 0, 0,
"size", "(ii)", cast->screencopy_frame.width, cast->screencopy_frame.height,
"source_type", "u", 1 << MONITOR,
"persist_mode", "u", sess->screencast_data.persist_mode,
"restore_data", "(suv)",
"wlroots", XDP_CAST_DATA_VER,
"a{sv}", 1, "output_name", "s", sess->screencast_data.output_name);
break;
default:
logprint(DEBUG, "No persistmode");
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.width, cast->screencopy_frame.height,
"source_type", "u", 1 << MONITOR);
}

if (ret < 0) {
return ret;
Expand Down

0 comments on commit 2a399db

Please sign in to comment.