]> git.mdlowis.com Git - proto/labwc.git/commitdiff
xwayland: set _NET_WORKAREA property based on usable area
authorJohn Lindgren <john@jlindgren.net>
Tue, 24 Oct 2023 17:49:15 +0000 (13:49 -0400)
committerJohan Malm <johanmalm@users.noreply.github.com>
Mon, 27 Nov 2023 22:08:43 +0000 (22:08 +0000)
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
src/output.c
src/xwayland.c

index 76e48ca5179a51af157c6079f46a886898bf84f7..129a03215f3d8f600311bce9107abbb912e4056d 100644 (file)
@@ -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 */
index b12c32fa4696623ff22f2d080d3315b053c45c01..3474811364c3a31e8849d25c6030af29ec9d9bc9 100644 (file)
@@ -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);
        }
 }
index e92ad87b4a9234b8b9f69337c51c871b13418a2d..2719102a0ac90f80c74f1c1df58f91481df123bc 100644 (file)
@@ -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);
+}