xwayland: make X11 always-on-top request opt-in

Fixes: #3441
This commit is contained in:
Consolatis 2026-03-12 13:08:18 +01:00
parent a3646721bc
commit 4faab834f9
6 changed files with 27 additions and 2 deletions

View file

@ -1354,6 +1354,13 @@ situation.
*ignoreConfigureRequest* prevents a X11 window to position and size
itself.
*<windowRules><windowRule allowAlwaysOnTop="">* [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.
*<windowRules><windowRule fixedPosition="">* [yes|no|default]
*fixedPosition* disallows interactive move/resize and prevents
re-positioning in response to changes in reserved output space, which

View file

@ -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 */
};

View file

@ -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);
}
}

View file

@ -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]);

View file

@ -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;

View file

@ -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