From 4faab834f9e72b861b8fddbd20f104790c18db94 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Thu, 12 Mar 2026 13:08:18 +0100 Subject: [PATCH] xwayland: make X11 always-on-top request opt-in Fixes: #3441 --- docs/labwc-config.5.scd | 7 +++++++ include/window-rules.h | 1 + src/config/rcxml.c | 2 ++ src/view.c | 3 +++ src/window-rules.c | 4 ++++ src/xwayland.c | 12 ++++++++++-- 6 files changed, 27 insertions(+), 2 deletions(-) diff --git a/docs/labwc-config.5.scd b/docs/labwc-config.5.scd index ea740693..03d5fc24 100644 --- a/docs/labwc-config.5.scd +++ b/docs/labwc-config.5.scd @@ -1354,6 +1354,13 @@ situation. *ignoreConfigureRequest* prevents a X11 window to position and size itself. +** [yes|no|default] + *allowAlwaysOnTop* allows a X11 window to control its always-on-top + state ('above' in X11 terms). + + Note: X11 window always-on-top requests are disallowed by default. + This window rule offers a means of allowing it. + ** [yes|no|default] *fixedPosition* disallows interactive move/resize and prevents re-positioning in response to changes in reserved output space, which diff --git a/include/window-rules.h b/include/window-rules.h index 1bee4c09..624f3b85 100644 --- a/include/window-rules.h +++ b/include/window-rules.h @@ -40,6 +40,7 @@ struct window_rule { enum property ignore_configure_request; enum property fixed_position; enum property icon_prefer_client; + enum property allow_always_on_top; struct wl_list link; /* struct rcxml.window_rules */ }; diff --git a/src/config/rcxml.c b/src/config/rcxml.c index 95285776..45093781 100644 --- a/src/config/rcxml.c +++ b/src/config/rcxml.c @@ -300,6 +300,8 @@ fill_window_rule(xmlNode *node) set_property(content, &window_rule->ignore_configure_request); } else if (!strcasecmp(key, "fixedPosition")) { set_property(content, &window_rule->fixed_position); + } else if (!strcasecmp(key, "allowAlwaysOnTop")) { + set_property(content, &window_rule->allow_always_on_top); } } diff --git a/src/view.c b/src/view.c index 0333d6e6..7eb381de 100644 --- a/src/view.c +++ b/src/view.c @@ -1543,6 +1543,9 @@ void view_set_layer(struct view *view, enum view_layer layer) { assert(view); + if (view->layer == layer) { + return; + } view->layer = layer; wlr_scene_node_reparent(&view->scene_tree->node, view->workspace->view_trees[layer]); diff --git a/src/window-rules.c b/src/window-rules.c index 0b8f1101..bfeacfe7 100644 --- a/src/window-rules.c +++ b/src/window-rules.c @@ -110,6 +110,10 @@ window_rules_get_property(struct view *view, const char *property) && !strcasecmp(property, "iconPreferClient")) { return rule->icon_prefer_client; } + if (rule->allow_always_on_top + && !strcasecmp(property, "allowAlwaysOnTop")) { + return rule->allow_always_on_top; + } } } return LAB_PROP_UNSPECIFIED; diff --git a/src/xwayland.c b/src/xwayland.c index 6050c21b..d16e41ac 100644 --- a/src/xwayland.c +++ b/src/xwayland.c @@ -431,6 +431,11 @@ handle_request_above(struct wl_listener *listener, void *data) wl_container_of(listener, xwayland_view, request_above); struct view *view = &xwayland_view->base; + if (window_rules_get_property(view, "allowAlwaysOnTop") != LAB_PROP_TRUE) { + wlr_log(WLR_INFO, "X11 client side always on top request rejected"); + return; + } + view_set_layer(view, xwayland_view->xwayland_surface->above ? VIEW_LAYER_ALWAYS_ON_TOP : VIEW_LAYER_NORMAL); } @@ -727,8 +732,11 @@ handle_map_request(struct wl_listener *listener, void *data) axis |= VIEW_AXIS_VERTICAL; } view_maximize(view, axis); - view_set_layer(view, xsurface->above - ? VIEW_LAYER_ALWAYS_ON_TOP : VIEW_LAYER_NORMAL); + + if (window_rules_get_property(view, "allowAlwaysOnTop") == LAB_PROP_TRUE) { + view_set_layer(view, xsurface->above + ? VIEW_LAYER_ALWAYS_ON_TOP : VIEW_LAYER_NORMAL); + } /* * We could also call set_initial_position() here, but it's not * really necessary until the view is actually mapped (and at