Add xdg-toplevel-groups for persistent toplevel z-ordering

This new protocol allows clients to set a persistent z-order for their
toplevels, permanently keeping some toplevels above others no matter
which one gets activated by the user.

This paradigm is very commonly used by DAW (Digital Audio Workstation)
and CAD (Computer-aided Design) applications, which utilize a lot of
windows and toolboxes and often have plugins running in separate
processes.

Signed-off-by: Matthias Klumpp <matthias@tenstral.net>
This commit is contained in:
Matthias Klumpp 2026-04-16 20:11:26 +02:00
parent 911ab509ed
commit da68b270d9
3 changed files with 193 additions and 0 deletions

View file

@ -78,6 +78,7 @@ staging_protocols = {
'xdg-session-management': {'v1': ['stable/xdg-shell/xdg-shell.xml']},
'xdg-system-bell': {'v1': []},
'xdg-toplevel-drag': {'v1': ['stable/xdg-shell/xdg-shell.xml']},
'xdg-toplevel-groups': {'v1': ['stable/xdg-shell/xdg-shell.xml']},
'xdg-toplevel-icon': {'v1': ['stable/xdg-shell/xdg-shell.xml']},
'xdg-toplevel-tag': {'v1': ['stable/xdg-shell/xdg-shell.xml']},
'xwayland-shell': {'v1': []},

View file

@ -0,0 +1,4 @@
Toplevel Groups protocol
Maintainers:
Matthias Klumpp <matthias@tenstral.net> (@mak)

View file

@ -0,0 +1,188 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="xdg_toplevel_groups_v1">
<copyright>
Copyright © 2024-2026 Matthias Klumpp
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
</copyright>
<description summary="protocol that allows setting a persistent z-order for toplevel groups">
This protocol provides a way for clients to set a persistent layering order
between their toplevels.
This is useful for clients that want to keep specific toplevels above or below
other toplevels, no matter whether they currently have focus or not, when using
a stacking window manager.
This is useful for multi-window applications, where for example some utility
windows or control windows should float above a main window even if they are
not currently activated.
This document adheres to RFC 2119 when using words like "must",
"should", "may", etc.
Warning! The protocol described in this file is currently in the testing
phase. Backward compatible changes may be added together with the
corresponding interface version bump. Backward incompatible changes can
only be done by creating a new major version of the extension.
</description>
<interface name="xdg_toplevel_group_manager_v1" version="1">
<description summary="manage toplevel groups">
The 'xdg_toplevel_group_manager' interface defines base requests for obtaining and
managing toplevel groups for a client.
A toplevel group is a collection of toplevels that can be layered together.
</description>
<request name="destroy" type="destructor">
<description summary="destroy this object">
This has no effect other than to destroy the 'xdg_toplevel_group_manager' object.
</description>
</request>
<request name="get_group">
<description summary="create a new toplevel group">
Create a new toplevel group.
</description>
<arg name="id" type="new_id" interface="xdg_toplevel_group_v1"/>
</request>
<request name="get_group_from_handle">
<description summary="import a toplevel group based on its handle">
Import a toplevel group based on its handle. This allows clients to share
toplevel groups between each other.
The handle of a group can be obtained from the 'handle' event of the
'xdg_toplevel_group_v1' interface.
The compositor must ensure that the same handle always refers to the
same group.
If the handle is invalid, this request must return a new group.
</description>
<arg name="id" type="new_id" interface="xdg_toplevel_group_v1"/>
<arg name="handle" type="string" summary="the handle of a group"/>
</request>
</interface>
<interface name="xdg_toplevel_group_v1" version="1">
<description summary="a group of toplevels at the same persistent z order">
The 'xdg_toplevel_group' interface represents a group of toplevels that are
layered together at the same persistent z order.
A toplevel can only be part of one group at a time. When a toplevel is added
to a group, it is removed from any previous group it was part of.
</description>
<request name="destroy" type="destructor">
<description summary="delete this object">
Destroys the toplevel group. This request may be sent at any time by the
client.
By destroying the object, all toplevels that were part of this group are
removed from the group and return to their default stacking behavior.
A group is only fully destroyed if all clients that hold a reference to
it have destroyed their reference.
</description>
</request>
<request name="add_toplevel">
<description summary="add a toplevel to this group">
Add a toplevel to this group. This request may be sent at any time by the
client.
The compositor must ensure that the toplevel is added to this group and
removed from any previous group it was part of.
If a toplevel is destroyed, it must automatically be removed from its group
as well by the compositor.
</description>
<arg name="toplevel" type="object" interface="xdg_toplevel" summary="the toplevel to add"/>
</request>
<request name="remove_toplevel">
<description summary="remove a toplevel from this group">
Remove a toplevel from this group. This request may be sent at any time by the
client.
The compositor must ensure that the toplevel is removed from this group and
returns to its default stacking behavior.
If the specified toplevel is not part of this group, this request has no effect.
</description>
<arg name="toplevel" type="object" interface="xdg_toplevel" summary="the toplevel to remove"/>
</request>
<enum name="error">
<entry name="invalid" value="0"
summary="the request was invalid"/>
<entry name="parent_cycle" value="1"
summary="a circular parent chain was detected"/>
</enum>
<request name="set_parent">
<description summary="set a parent group for this group">
Set a parent group for this group. This request may be sent at any time
by the client.
The compositor must ensure that all toplevels from this group are
persistently floating above the parent group.
The compositor must not change other behavior of the grouped toplevels
based on parent-child relationships, e.g. focus behavior or
keyboard interactivity. Toplevels in the parent group must still receive
focus as normal, with the only difference being that toplevels in the
child group are floating above toplevels in the parent group.
If the specified parent group is the same as this group, an 'invalid'
error must be raised.
If null is specified as the parent group, toplevels of this group
return to the default stacking behavior and the parent association
is removed.
If a parent group is destroyed, the compositor must ensure that all
child groups of the destroyed group return to the default stacking
behavior, and that any parent association is automatically removed.
Clients must not create circular parent-child relationships
between groups. If the compositor detects a circular chain, a
'parent_cycle' error must be raised.
</description>
<arg name="parent_group" type="object" interface="xdg_toplevel_group_v1" allow-null="true"
summary="the parent group"/>
</request>
<request name="get_handle">
<description summary="export this group with a handle">
Obtain a handle for this group.
The compositor must ensure that the same handle always refers to the
same group. A handle must be unique to a group and should not be expected
to be persistent.
The handle can be used to import this group in other clients using the
'get_group_from_handle' request of the 'xdg_toplevel_group_manager'
interface.
The compositor must reply with a 'handle' event in response to this request.
</description>
</request>
<event name="handle">
<description summary="a handle for this group">
This event is sent in response to the 'get_handle' request, and contains
a unique handle for this group.
</description>
<arg name="handle" type="string" summary="the handle for this group"/>
</event>
</interface>
</protocol>