From 6b8c79748a8eb3ebd06907b9c564b6b936eb635f Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Tue, 24 Oct 2023 13:49:15 -0400 Subject: [PATCH] xwayland: set _NET_WORKAREA property based on usable area XWayland clients use the _NET_WORKAREA root window property to determine how much of the screen is not covered by panels/docks. The property is used for example by Qt to determine areas of the screen that popup menus should not overlap (see QScreen::availableVirtualGeometry). Depends on wlroots MR: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4406 v2: prevent calling wlr_xwayland_set_workareas() too early v3: fix segfault at exit (server->xwayland == NULL) --- include/xwayland.h | 2 ++ src/output.c | 7 ++++ src/xwayland.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+) diff --git a/include/xwayland.h b/include/xwayland.h index 76e48ca5..129a0321 100644 --- a/include/xwayland.h +++ b/include/xwayland.h @@ -58,5 +58,7 @@ void xwayland_server_init(struct server *server, struct wlr_compositor *compositor); void xwayland_server_finish(struct server *server); +void xwayland_update_workarea(struct server *server); + #endif /* HAVE_XWAYLAND */ #endif /* LABWC_XWAYLAND_H */ diff --git a/src/output.c b/src/output.c index b12c32fa..34748113 100644 --- a/src/output.c +++ b/src/output.c @@ -24,6 +24,7 @@ #include "node.h" #include "regions.h" #include "view.h" +#include "xwayland.h" static void output_frame_notify(struct wl_listener *listener, void *data) @@ -610,6 +611,9 @@ output_update_usable_area(struct output *output) { if (update_usable_area(output)) { regions_update_geometry(output); +#if HAVE_XWAYLAND + xwayland_update_workarea(output->server); +#endif desktop_arrange_all_views(output->server); } } @@ -629,6 +633,9 @@ output_update_all_usable_areas(struct server *server, bool layout_changed) } } if (usable_area_changed || layout_changed) { +#if HAVE_XWAYLAND + xwayland_update_workarea(server); +#endif desktop_arrange_all_views(server); } } diff --git a/src/xwayland.c b/src/xwayland.c index e92ad87b..2719102a 100644 --- a/src/xwayland.c +++ b/src/xwayland.c @@ -839,6 +839,7 @@ handle_ready(struct wl_listener *listener, void *data) struct server *server = wl_container_of(listener, server, xwayland_ready); wlr_xwayland_set_seat(server->xwayland, server->seat.seat); + xwayland_update_workarea(server); } void @@ -928,3 +929,82 @@ xwayland_server_finish(struct server *server) server->xwayland = NULL; wlr_xwayland_destroy(xwayland); } + +void +xwayland_update_workarea(struct server *server) +{ + /* + * Do nothing if called during destroy or before xwayland is ready. + * This function will be called again from the ready signal handler. + */ + if (!server->xwayland || !server->xwayland->xwm) { + return; + } + + struct wlr_box lb; + wlr_output_layout_get_box(server->output_layout, NULL, &lb); + + /* Compute outer edges of layout (excluding negative regions) */ + int layout_left = MAX(0, lb.x); + int layout_right = MAX(0, lb.x + lb.width); + int layout_top = MAX(0, lb.y); + int layout_bottom = MAX(0, lb.y + lb.height); + + /* Workarea is initially the entire layout */ + int workarea_left = layout_left; + int workarea_right = layout_right; + int workarea_top = layout_top; + int workarea_bottom = layout_bottom; + + struct output *output; + wl_list_for_each(output, &server->outputs, link) { + if (!output_is_usable(output)) { + continue; + } + + struct wlr_box ob; + wlr_output_layout_get_box(server->output_layout, + output->wlr_output, &ob); + + /* Compute edges of output */ + int output_left = ob.x; + int output_right = ob.x + ob.width; + int output_top = ob.y; + int output_bottom = ob.y + ob.height; + + /* Compute edges of usable area */ + int usable_left = output_left + output->usable_area.x; + int usable_right = usable_left + output->usable_area.width; + int usable_top = output_top + output->usable_area.y; + int usable_bottom = usable_top + output->usable_area.height; + + /* + * Only adjust workarea edges for output edges that are + * aligned with outer edges of layout + */ + if (output_left == layout_left) { + workarea_left = MAX(workarea_left, usable_left); + } + if (output_right == layout_right) { + workarea_right = MIN(workarea_right, usable_right); + } + if (output_top == layout_top) { + workarea_top = MAX(workarea_top, usable_top); + } + if (output_bottom == layout_bottom) { + workarea_bottom = MIN(workarea_bottom, usable_bottom); + } + } + + /* + * Set _NET_WORKAREA property. We don't report virtual desktops + * to XWayland, so we set only one workarea. + */ + struct wlr_box workarea = { + .x = workarea_left, + .y = workarea_top, + .width = workarea_right - workarea_left, + .height = workarea_bottom - workarea_top, + }; + wlr_xwayland_set_workareas(server->xwayland, &workarea, 1); +}