From 2dc95fe02f937d4701f0ae2e0f9067a31bb9f15d Mon Sep 17 00:00:00 2001 From: vaxerski <43317083+vaxerski@users.noreply.github.com> Date: Sat, 3 Dec 2022 22:42:21 +0000 Subject: [PATCH] Allow region sharing --- include/screencast_common.h | 36 ++++++++------ include/wlr_screencast.h | 2 +- src/screencast/screencast.c | 18 +++---- src/screencast/wlr_screencast.c | 84 ++++++++++++++++++++++++++++----- 4 files changed, 105 insertions(+), 35 deletions(-) diff --git a/include/screencast_common.h b/include/screencast_common.h index 7d327a2..344a485 100644 --- a/include/screencast_common.h +++ b/include/screencast_common.h @@ -130,6 +130,27 @@ struct xdpw_screencast_context { struct wl_list screencast_instances; }; +struct xdpw_wlr_output { + struct wl_list link; + uint32_t id; + struct wl_output *output; + struct zxdg_output_v1 *xdg_output; + char *make; + char *model; + char *name; + int width; + int height; + float framerate; +}; + +struct xdpw_share { + struct xdpw_wlr_output *output; + int x; + int y; + int w; + int h; +}; + struct xdpw_screencast_instance { // list struct wl_list link; @@ -154,7 +175,7 @@ struct xdpw_screencast_instance { // wlroots struct zwlr_screencopy_frame_v1 *frame_callback; - struct xdpw_wlr_output *target_output; + struct xdpw_share target; uint32_t max_framerate; struct zwlr_screencopy_frame_v1 *wlr_frame; struct xdpw_screencopy_frame_info screencopy_frame_info[2]; @@ -168,19 +189,6 @@ struct xdpw_screencast_instance { struct fps_limit_state fps_limit; }; -struct xdpw_wlr_output { - struct wl_list link; - uint32_t id; - struct wl_output *output; - struct zxdg_output_v1 *xdg_output; - char *make; - char *model; - char *name; - int width; - int height; - float framerate; -}; - void randname(char *buf); struct gbm_device *xdpw_gbm_device_create(drmDevice *device); struct xdpw_buffer *xdpw_buffer_create(struct xdpw_screencast_instance *cast, diff --git a/include/wlr_screencast.h b/include/wlr_screencast.h index 83eaa49..efd7269 100644 --- a/include/wlr_screencast.h +++ b/include/wlr_screencast.h @@ -25,7 +25,7 @@ struct xdpw_wlr_output *xdpw_wlr_output_find_by_name(struct wl_list *output_list struct xdpw_wlr_output *xdpw_wlr_output_first(struct wl_list *output_list); struct xdpw_wlr_output *xdpw_wlr_output_find(struct xdpw_screencast_context *ctx, struct wl_output *out, uint32_t id); -struct xdpw_wlr_output *xdpw_wlr_output_chooser(struct xdpw_screencast_context *ctx); +struct xdpw_share xdpw_wlr_chooser(struct xdpw_screencast_context *ctx); void xdpw_wlr_frame_finish(struct xdpw_screencast_instance *cast); void xdpw_wlr_frame_start(struct xdpw_screencast_instance *cast); diff --git a/src/screencast/screencast.c b/src/screencast/screencast.c index 04a5676..f662cd9 100644 --- a/src/screencast/screencast.c +++ b/src/screencast/screencast.c @@ -48,7 +48,7 @@ void exec_with_shell(char *command) { } void xdpw_screencast_instance_init(struct xdpw_screencast_context *ctx, - struct xdpw_screencast_instance *cast, struct xdpw_wlr_output *out, bool with_cursor) { + struct xdpw_screencast_instance *cast, struct xdpw_share out, bool with_cursor) { // only run exec_before if there's no other instance running that already ran it if (wl_list_empty(&ctx->screencast_instances)) { @@ -60,12 +60,12 @@ void xdpw_screencast_instance_init(struct xdpw_screencast_context *ctx, } cast->ctx = ctx; - cast->target_output = out; + cast->target = out; if (ctx->state->config->screencast_conf.max_fps > 0) { - cast->max_framerate = ctx->state->config->screencast_conf.max_fps < (uint32_t)out->framerate ? - ctx->state->config->screencast_conf.max_fps : (uint32_t)out->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 { - cast->max_framerate = (uint32_t)out->framerate; + cast->max_framerate = (uint32_t)out.output->framerate; } cast->framerate = cast->max_framerate; cast->with_cursor = with_cursor; @@ -116,9 +116,9 @@ bool setup_outputs(struct xdpw_screencast_context *ctx, struct xdpw_session *ses output->make, output->model, output->id, output->name); } - struct xdpw_wlr_output *out; - out = xdpw_wlr_output_chooser(ctx); - if (!out) { + struct xdpw_share out; + out = xdpw_wlr_chooser(ctx); + if (!out.output) { logprint(ERROR, "wlroots: no output found"); return false; } @@ -153,7 +153,7 @@ bool setup_outputs(struct xdpw_screencast_context *ctx, struct xdpw_session *ses out, with_cursor); } logprint(INFO, "wlroots: output: %s", - sess->screencast_instance->target_output->name); + sess->screencast_instance->target.output->name); return true; diff --git a/src/screencast/wlr_screencast.c b/src/screencast/wlr_screencast.c index cbf347d..a5ccddd 100644 --- a/src/screencast/wlr_screencast.c +++ b/src/screencast/wlr_screencast.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "screencast.h" #include "pipewire_screencast.h" @@ -249,8 +250,16 @@ static const struct zwlr_screencopy_frame_v1_listener wlr_frame_listener = { }; void xdpw_wlr_register_cb(struct xdpw_screencast_instance *cast) { - cast->frame_callback = zwlr_screencopy_manager_v1_capture_output( - cast->ctx->screencopy_manager, cast->with_cursor, cast->target_output->output); + + if (cast->target.x != -1 && cast->target.y != -1 && cast->target.w != -1 && cast->target.h != -1) { + // capture region + cast->frame_callback = zwlr_screencopy_manager_v1_capture_output_region( + cast->ctx->screencopy_manager, cast->with_cursor, cast->target.output->output, cast->target.x, + cast->target.y, cast->target.w, cast->target.h); + } else { + cast->frame_callback = zwlr_screencopy_manager_v1_capture_output( + cast->ctx->screencopy_manager, cast->with_cursor, cast->target.output->output); + } zwlr_screencopy_frame_v1_add_listener(cast->frame_callback, &wlr_frame_listener, cast); @@ -333,8 +342,8 @@ static void wlr_init_xdg_outputs(struct xdpw_screencast_context *ctx) { } } -struct xdpw_wlr_output *xdpw_wlr_output_chooser(struct xdpw_screencast_context *ctx) { - char result[1024]; +struct xdpw_share xdpw_wlr_chooser(struct xdpw_screencast_context *ctx) { + char result[1024]; FILE *fp; char buf[1024]; @@ -351,27 +360,80 @@ struct xdpw_wlr_output *xdpw_wlr_output_chooser(struct xdpw_screencast_context * pclose(fp); // great, let's parse it. - - // TODO: window & region + + struct xdpw_share res = {NULL, -1, -1, -1, -1}; + + // TODO: window & region if (strncmp(result, "screen:", 7) == 0) { - // find + // find output char* display_name = malloc(strlen(result) - 7); strncpy(display_name, result + 7, strlen(result) - 8); display_name[strlen(result) - 8] = 0; struct xdpw_wlr_output* out; + bool found = false; wl_list_for_each(out, &ctx->output_list, link) { if (strcmp(out->name, display_name) == 0) { + found = true; break; } } free(display_name); - return out; + if (!found) + return res; + + res.output = out; + return res; + } else if (strncmp(result, "region:", 7) == 0) { + // find output + int atPos = 0; + for (int i = 0; i < (int)strlen(result); ++i) { + if (result[i] == '@'){ + atPos = i; + break; + } + } + + char *display_name = malloc(atPos - 6); + strncpy(display_name, result + 7, atPos - 7); + display_name[atPos - 7] = 0; + + struct xdpw_wlr_output *out; + wl_list_for_each(out, &ctx->output_list, link) { + if (strcmp(out->name, display_name) == 0) { + break; + } + } + + // then get coords + int coordno = 0; + int coords[4] = {-1, -1, -1, -1}; + int coordbegin = 7 + strlen(display_name) + 1; + for (int i = 7 + strlen(display_name) + 1; i < (int)strlen(result); ++i) { + if (result[i] == ',' || result[i] == '@' || i + 1 == (int)strlen(result)) { + char* entire = malloc(i - coordbegin + 1); + strncpy(entire, result + coordbegin, i - coordbegin); + entire[i - coordbegin] = 0; + coords[coordno] = strtol(entire, NULL, 10); + free(entire); + + coordno++; + coordbegin = i + 1; + i++; + } + } + + free(display_name); + + struct xdpw_share res2 = {out, coords[0], coords[1], coords[2], coords[3]}; + return res2; } else { - return NULL; - } + return res; + } + + return res; } struct xdpw_wlr_output *xdpw_wlr_output_first(struct wl_list *output_list) { @@ -644,7 +706,7 @@ static void wlr_registry_handle_remove(void *data, struct wl_registry *reg, logprint(DEBUG, "wlroots: output removed (%s)", output->name); struct xdpw_screencast_instance *cast, *tmp; wl_list_for_each_safe(cast, tmp, &ctx->screencast_instances, link) { - if (cast->target_output == output) { + if (cast->target.output == output) { // screencopy might be in process for this instance wlr_frame_free(cast); // instance might be waiting for wakeup by the frame limiter