From 068280201afdb8d87b1c624d115bed8866c6852e Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Wed, 9 Nov 2022 16:09:43 -0500 Subject: [PATCH] xwayland: Read and publish _NET_WM_STRUT_PARTIAL property This is needed for compositors that want to reserve space for XWayland panels. Such a feature can be useful in a "transitional" setup, where only the X11 window manager and compositor is replaced but other components of an X11 desktop environment are still used. This change simply reads the X11 property; the compositor is free to ignore it. Thus, compositors that don't want to support such a "transitional" feature are not impacted. v2: Update xwayland_surface_associate() --- include/wlr/xwayland/xwayland.h | 7 ++++++ include/xwayland/xwm.h | 1 + xwayland/meson.build | 1 + xwayland/xwm.c | 38 +++++++++++++++++++++++++++++++++ 4 files changed, 47 insertions(+) diff --git a/include/wlr/xwayland/xwayland.h b/include/wlr/xwayland/xwayland.h index 63e64f364..c1dbc3395 100644 --- a/include/wlr/xwayland/xwayland.h +++ b/include/wlr/xwayland/xwayland.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -121,6 +122,11 @@ struct wlr_xwayland_surface { uint32_t decorations; xcb_icccm_wm_hints_t *hints; xcb_size_hints_t *size_hints; + /* + * _NET_WM_STRUT_PARTIAL (used by e.g. XWayland panels; + * right/bottom are translated into root x/y coordinates) + */ + xcb_ewmh_wm_strut_partial_t *strut_partial; bool pinging; struct wl_event_source *ping_timer; @@ -154,6 +160,7 @@ struct wlr_xwayland_surface { struct wl_signal set_window_type; struct wl_signal set_hints; struct wl_signal set_decorations; + struct wl_signal set_strut_partial; struct wl_signal set_override_redirect; struct wl_signal set_geometry; struct wl_signal ping_timeout; diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index c057e1b77..c69504e81 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -34,6 +34,7 @@ enum atom_name { NET_WM_PID, NET_WM_NAME, NET_WM_STATE, + NET_WM_STRUT_PARTIAL, NET_WM_WINDOW_TYPE, WM_TAKE_FOCUS, WINDOW, diff --git a/xwayland/meson.build b/xwayland/meson.build index 5d22584b1..08ad7a392 100644 --- a/xwayland/meson.build +++ b/xwayland/meson.build @@ -2,6 +2,7 @@ xwayland_libs = [] xwayland_required = [ 'xcb', 'xcb-composite', + 'xcb-ewmh', 'xcb-icccm', 'xcb-render', 'xcb-res', diff --git a/xwayland/xwm.c b/xwayland/xwm.c index de9a7a800..11a7d9aa6 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -36,6 +36,7 @@ const char *const atom_map[ATOM_LAST] = { [NET_WM_PID] = "_NET_WM_PID", [NET_WM_NAME] = "_NET_WM_NAME", [NET_WM_STATE] = "_NET_WM_STATE", + [NET_WM_STRUT_PARTIAL] = "_NET_WM_STRUT_PARTIAL", [NET_WM_WINDOW_TYPE] = "_NET_WM_WINDOW_TYPE", [WM_TAKE_FOCUS] = "WM_TAKE_FOCUS", [WINDOW] = "WINDOW", @@ -181,6 +182,7 @@ static struct wlr_xwayland_surface *xwayland_surface_create( wl_signal_init(&surface->events.set_window_type); wl_signal_init(&surface->events.set_hints); wl_signal_init(&surface->events.set_decorations); + wl_signal_init(&surface->events.set_strut_partial); wl_signal_init(&surface->events.set_override_redirect); wl_signal_init(&surface->events.ping_timeout); wl_signal_init(&surface->events.set_geometry); @@ -440,6 +442,7 @@ static void xwayland_surface_destroy(struct wlr_xwayland_surface *xsurface) { free(xsurface->startup_id); free(xsurface->hints); free(xsurface->size_hints); + free(xsurface->strut_partial); free(xsurface); } @@ -761,6 +764,38 @@ static void read_surface_motif_hints(struct wlr_xwm *xwm, } } +static void read_surface_strut_partial(struct wlr_xwm *xwm, + struct wlr_xwayland_surface *xsurface, + xcb_get_property_reply_t *reply) { + if (reply->type != XCB_ATOM_CARDINAL || reply->format != 32 || + xcb_get_property_value_length(reply) != + sizeof(xcb_ewmh_wm_strut_partial_t)) { + return; + } + + free(xsurface->strut_partial); + xsurface->strut_partial = calloc(1, sizeof(xcb_ewmh_wm_strut_partial_t)); + if (xsurface->strut_partial == NULL) { + return; + } + xcb_ewmh_get_wm_strut_partial_from_reply(xsurface->strut_partial, reply); + + /* + * Translate right/bottom into root x/y coordinates here since + * the compositor is ignorant of X11 screen width/height. + * + * (This could result in an incorrect position if the X11 screen + * size changes but _NET_WM_STRUT_PARTIAL doesn't. It's probably + * not worth the additional code to fix this corner case.) + */ + xsurface->strut_partial->right = + xwm->screen->width_in_pixels - xsurface->strut_partial->right; + xsurface->strut_partial->bottom = + xwm->screen->height_in_pixels - xsurface->strut_partial->bottom; + + wl_signal_emit_mutable(&xsurface->events.set_strut_partial, xsurface); +} + static void read_surface_net_wm_state(struct wlr_xwm *xwm, struct wlr_xwayland_surface *xsurface, xcb_get_property_reply_t *reply) { @@ -827,6 +862,8 @@ static void read_surface_property(struct wlr_xwm *xwm, read_surface_normal_hints(xwm, xsurface, reply); } else if (property == xwm->atoms[MOTIF_WM_HINTS]) { read_surface_motif_hints(xwm, xsurface, reply); + } else if (property == xwm->atoms[NET_WM_STRUT_PARTIAL]) { + read_surface_strut_partial(xwm, xsurface, reply); } else if (property == xwm->atoms[WM_WINDOW_ROLE]) { read_surface_role(xwm, xsurface, reply); } else if (property == xwm->atoms[NET_STARTUP_ID]) { @@ -910,6 +947,7 @@ static void xwayland_surface_associate(struct wlr_xwm *xwm, xwm->atoms[MOTIF_WM_HINTS], xwm->atoms[NET_STARTUP_ID], xwm->atoms[NET_WM_STATE], + xwm->atoms[NET_WM_STRUT_PARTIAL], xwm->atoms[NET_WM_WINDOW_TYPE], xwm->atoms[NET_WM_NAME], };