From 1eaa02eb18ab783b64dc89f1681909dc30baa805 Mon Sep 17 00:00:00 2001 From: cptpcrd <31829097+cptpcrd@users.noreply.github.com> Date: Sat, 6 Jan 2024 14:20:27 -0500 Subject: [PATCH] screencast: report correct position/size using xdg-output Previously the position reported was hardcoded as (0, 0). This is incorrect; it should be the coordinates of the output being shared. Additionally, the size reported was the buffer size, when it should really be the logical size. Use the xdg-output protocol (where supported) to determine the position and size of the output and return them in the response. If it is not supported by the compositor, omit the position/size. --- include/screencast_common.h | 4 ++ include/wlr_screencast.h | 3 ++ src/screencast/screencast.c | 67 ++++++++++++++++++++++++++--- src/screencast/wlr_screencast.c | 76 +++++++++++++++++++++++++++++++++ 4 files changed, 144 insertions(+), 6 deletions(-) diff --git a/include/screencast_common.h b/include/screencast_common.h index cae85052..d0a50d86 100644 --- a/include/screencast_common.h +++ b/include/screencast_common.h @@ -127,6 +127,7 @@ struct xdpw_screencast_context { struct wl_shm *shm; struct zwp_linux_dmabuf_v1 *linux_dmabuf; struct zwp_linux_dmabuf_feedback_v1 *linux_dmabuf_feedback; + struct zxdg_output_manager_v1 *xdg_output_manager; struct xdpw_dmabuf_feedback_data feedback_data; struct wl_array format_modifier_pairs; @@ -194,9 +195,12 @@ 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 x; + int y; int width; int height; float framerate; diff --git a/include/wlr_screencast.h b/include/wlr_screencast.h index ee784139..d3599b62 100644 --- a/include/wlr_screencast.h +++ b/include/wlr_screencast.h @@ -13,6 +13,9 @@ #define LINUX_DMABUF_VERSION 4 #define LINUX_DMABUF_VERSION_MIN 3 +#define XDG_OUTPUT_VERSION 3 +#define XDG_OUTPUT_VERSION_MIN 1 + struct xdpw_state; int xdpw_wlr_screencopy_init(struct xdpw_state *state); diff --git a/src/screencast/screencast.c b/src/screencast/screencast.c index eb4d8672..1fae2301 100644 --- a/src/screencast/screencast.c +++ b/src/screencast/screencast.c @@ -585,12 +585,67 @@ static int method_screencast_start(sd_bus_message *msg, void *data, if (ret < 0) { return ret; } - ret = sd_bus_message_append(reply, "{sv}", - "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", MONITOR); + ret = sd_bus_message_open_container(reply, 'e', "sv"); + if (ret < 0) { + return ret; + } + ret = sd_bus_message_append(reply, "s", "streams"); + if (ret < 0) { + return ret; + } + ret = sd_bus_message_open_container(reply, 'v', "a(ua{sv})"); + if (ret < 0) { + return ret; + } + ret = sd_bus_message_open_container(reply, 'a', "(ua{sv})"); + if (ret < 0) { + return ret; + } + ret = sd_bus_message_open_container(reply, 'r', "ua{sv}"); + if (ret < 0) { + return ret; + } + ret = sd_bus_message_append(reply, "u", cast->node_id); + if (ret < 0) { + return ret; + } + ret = sd_bus_message_open_container(reply, 'a', "{sv}"); + if (ret < 0) { + return ret; + } + if (cast->target->output->xdg_output) { + ret = sd_bus_message_append(reply, "{sv}", + "position", "(ii)", cast->target->output->x, cast->target->output->y); + if (ret < 0) { + return ret; + } + ret = sd_bus_message_append(reply, "{sv}", + "size", "(ii)", cast->target->output->width, cast->target->output->height); + if (ret < 0) { + return ret; + } + } + ret = sd_bus_message_append(reply, "{sv}", "source_type", "u", MONITOR); + if (ret < 0) { + return ret; + } + ret = sd_bus_message_close_container(reply); + if (ret < 0) { + return ret; + } + ret = sd_bus_message_close_container(reply); + if (ret < 0) { + return ret; + } + ret = sd_bus_message_close_container(reply); + if (ret < 0) { + return ret; + } + ret = sd_bus_message_close_container(reply); + if (ret < 0) { + return ret; + } + ret = sd_bus_message_close_container(reply); if (ret < 0) { return ret; } diff --git a/src/screencast/wlr_screencast.c b/src/screencast/wlr_screencast.c index 6dc595d5..c1fae8e0 100644 --- a/src/screencast/wlr_screencast.c +++ b/src/screencast/wlr_screencast.c @@ -2,6 +2,7 @@ #include "linux-dmabuf-unstable-v1-client-protocol.h" #include "wlr-screencopy-unstable-v1-client-protocol.h" +#include "xdg-output-unstable-v1-client-protocol.h" #include #include #include @@ -306,6 +307,42 @@ static const struct wl_output_listener wlr_output_listener = { .description = wlr_output_handle_description, }; +static void xdg_output_handle_logical_position(void *data, struct zxdg_output_v1 *xdg_output_v1, + int32_t x, int32_t y) { + struct xdpw_wlr_output *output = data; + output->x = x; + output->y = y; +} + +static void xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output_v1, + int32_t width, int32_t height) { + struct xdpw_wlr_output *output = data; + output->width = width; + output->height = height; +} + +static void xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output_v1) { + /* Nothing to do */ +} + +static void xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output_v1, + const char *name) { + /* Nothing to do */ +} + +static void xdg_output_handle_description(void *data, struct zxdg_output_v1 *xdg_output_v1, + const char *description) { + /* Nothing to do */ +} + +static const struct zxdg_output_v1_listener xdg_output_listener = { + .logical_position = xdg_output_handle_logical_position, + .logical_size = xdg_output_handle_logical_size, + .done = xdg_output_handle_done, + .name = xdg_output_handle_name, + .description = xdg_output_handle_description, +}; + static struct xdpw_wlr_output *xdpw_wlr_output_first(struct wl_list *output_list) { struct xdpw_wlr_output *output, *tmp; wl_list_for_each_safe(output, tmp, output_list, link) { @@ -555,6 +592,9 @@ static void wlr_remove_output(struct xdpw_wlr_output *out) { free(out->name); free(out->make); free(out->model); + if (out->xdg_output) { + zxdg_output_v1_destroy(out->xdg_output); + } wl_output_destroy(out->output); wl_list_remove(&out->link); free(out); @@ -737,6 +777,12 @@ static void wlr_registry_handle_add(void *data, struct wl_registry *reg, logprint(DEBUG, "wlroots: |-- registered to interface %s (Version %u)", interface, WL_OUTPUT_VERSION); output->output = wl_registry_bind(reg, id, &wl_output_interface, WL_OUTPUT_VERSION); + if (ctx->xdg_output_manager) { + output->xdg_output = zxdg_output_manager_v1_get_xdg_output( + ctx->xdg_output_manager, output->output); + zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output); + } + wl_output_add_listener(output->output, &wlr_output_listener, output); wl_list_insert(&ctx->output_list, &output->link); } @@ -776,6 +822,17 @@ static void wlr_registry_handle_add(void *data, struct wl_registry *reg, zwp_linux_dmabuf_v1_add_listener(ctx->linux_dmabuf, &linux_dmabuf_listener, ctx); } } + + if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0 + && ver >= XDG_OUTPUT_VERSION_MIN) { + uint32_t version = ver; + if (XDG_OUTPUT_VERSION < ver) { + version = XDG_OUTPUT_VERSION; + } + logprint(DEBUG, "wlroots: |-- registered to interface %s (Version %u)", interface, version); + ctx->xdg_output_manager = wl_registry_bind( + reg, id, &zxdg_output_manager_v1_interface, version); + } } static void wlr_registry_handle_remove(void *data, struct wl_registry *reg, @@ -856,6 +913,19 @@ int xdpw_wlr_screencopy_init(struct xdpw_state *state) { } } + if (ctx->xdg_output_manager) { + struct xdpw_wlr_output *output; + wl_list_for_each(output, &ctx->output_list, link) { + if (!output->xdg_output) { + output->xdg_output = zxdg_output_manager_v1_get_xdg_output( + ctx->xdg_output_manager, output->output); + zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output); + } + } + wl_display_roundtrip(state->wl_display); + logprint(DEBUG, "wayland: xdg_output listeners run"); + } + return 0; } @@ -865,6 +935,9 @@ void xdpw_wlr_screencopy_finish(struct xdpw_screencast_context *ctx) { struct xdpw_wlr_output *output, *tmp_o; wl_list_for_each_safe(output, tmp_o, &ctx->output_list, link) { wl_list_remove(&output->link); + if (output->xdg_output) { + zxdg_output_v1_destroy(output->xdg_output); + } wl_output_destroy(output->output); } @@ -890,6 +963,9 @@ void xdpw_wlr_screencopy_finish(struct xdpw_screencast_context *ctx) { if (ctx->linux_dmabuf) { zwp_linux_dmabuf_v1_destroy(ctx->linux_dmabuf); } + if (ctx->xdg_output_manager) { + zxdg_output_manager_v1_destroy(ctx->xdg_output_manager); + } if (ctx->registry) { wl_registry_destroy(ctx->registry); }