From b4b1cdeb27fa7b3beb1181de38e8913f93772173 Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Wed, 24 Jun 2026 10:20:39 -0400 Subject: [PATCH] wayland: Add support for the toplevel tag protocol Uses the same ID string as the session manager protocol. --- src/video/wayland/SDL_waylandvideo.c | 8 +++ src/video/wayland/SDL_waylandvideo.h | 1 + src/video/wayland/SDL_waylandwindow.c | 19 +++-- wayland-protocols/xdg-toplevel-tag-v1.xml | 85 +++++++++++++++++++++++ 4 files changed, 106 insertions(+), 7 deletions(-) create mode 100644 wayland-protocols/xdg-toplevel-tag-v1.xml diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index a912b1d96d..9404947f5e 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -71,6 +71,7 @@ #include "pointer-gestures-unstable-v1-client-protocol.h" #include "single-pixel-buffer-v1-client-protocol.h" #include "xdg-session-management-v1-client-protocol.h" +#include "xdg-toplevel-tag-v1-client-protocol.h" #ifdef HAVE_LIBDECOR_H #include @@ -1511,6 +1512,8 @@ static void handle_registry_global(void *data, struct wl_registry *registry, uin d->single_pixel_buffer_manager = wl_registry_bind(d->registry, id, &wp_single_pixel_buffer_manager_v1_interface, 1); } else if (SDL_strcmp(interface, xdg_session_manager_v1_interface.name) == 0) { d->xdg_session_manager = wl_registry_bind(d->registry, id, &xdg_session_manager_v1_interface, 1); + } else if (SDL_strcmp(interface, xdg_toplevel_tag_manager_v1_interface.name) == 0) { + d->xdg_toplevel_tag_manager = wl_registry_bind(d->registry, id, &xdg_toplevel_tag_manager_v1_interface, 1); } #ifdef SDL_WL_FIXES_VERSION else if (SDL_strcmp(interface, wl_fixes_interface.name) == 0) { @@ -1935,6 +1938,11 @@ static void Wayland_VideoCleanup(SDL_VideoDevice *_this) data->xdg_session_manager = NULL; } + if (data->xdg_toplevel_tag_manager) { + xdg_toplevel_tag_manager_v1_destroy(data->xdg_toplevel_tag_manager); + data->xdg_toplevel_tag_manager = NULL; + } + if (data->subcompositor) { wl_subcompositor_destroy(data->subcompositor); data->subcompositor = NULL; diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h index 6be3f3835f..f06895aa40 100644 --- a/src/video/wayland/SDL_waylandvideo.h +++ b/src/video/wayland/SDL_waylandvideo.h @@ -88,6 +88,7 @@ struct SDL_VideoData struct zwp_pointer_gestures_v1 *zwp_pointer_gestures; struct wp_single_pixel_buffer_manager_v1 *single_pixel_buffer_manager; struct xdg_session_manager_v1 *xdg_session_manager; + struct xdg_toplevel_tag_manager_v1 *xdg_toplevel_tag_manager; struct xdg_session_v1 *xdg_session; struct xkb_context *xkb_context; diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index 6fad2002e0..f5c7b4bb9a 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -50,6 +50,7 @@ #include "xdg-toplevel-icon-v1-client-protocol.h" #include "color-management-v1-client-protocol.h" #include "xdg-session-management-v1-client-protocol.h" +#include "xdg-toplevel-tag-v1-client-protocol.h" #ifdef HAVE_LIBDECOR_H #include @@ -2053,22 +2054,26 @@ bool Wayland_SetWindowModal(SDL_VideoDevice *_this, SDL_Window *window, bool mod static void Wayland_RegisterToplevelForSession(SDL_WindowData *data) { - SDL_VideoDevice *viddev = SDL_GetVideoDevice(); - SDL_VideoData *viddata = viddev->internal; - struct xdg_toplevel *toplevel = GetToplevelForWindow(data); if (!toplevel) { return; } - if (viddata->xdg_session_manager) { - const char *id = SDL_GetStringProperty(data->sdlwindow->props, SDL_PROP_WINDOW_WAYLAND_WINDOW_ID_STRING, NULL); - if (id && *id != '\0') { + const char *id = SDL_GetStringProperty(data->sdlwindow->props, SDL_PROP_WINDOW_WAYLAND_WINDOW_ID_STRING, NULL); + if (id && *id != '\0') { + SDL_VideoDevice *viddev = SDL_GetVideoDevice(); + SDL_VideoData *viddata = viddev->internal; + + if (viddata->xdg_toplevel_tag_manager) { + xdg_toplevel_tag_manager_v1_set_toplevel_tag(viddata->xdg_toplevel_tag_manager, toplevel, id); + } + + if (viddata->xdg_session_manager) { Wayland_CreateSession(viddata); if (viddata->xdg_session) { CHECK_PARAM (true) { - // Windows must not have a duplicate ID string, or a protocol error will result. + // Windows added to a session must not have a duplicate ID string, or a protocol error will result. for (SDL_Window *w = viddev->windows; w; w = w->next) { SDL_WindowData *d = w->internal; if (d->session_id && SDL_strcmp(d->session_id, id) == 0) { diff --git a/wayland-protocols/xdg-toplevel-tag-v1.xml b/wayland-protocols/xdg-toplevel-tag-v1.xml new file mode 100644 index 0000000000..5e20bdf45f --- /dev/null +++ b/wayland-protocols/xdg-toplevel-tag-v1.xml @@ -0,0 +1,85 @@ + + + + Copyright © 2024 Xaver Hugl + + 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. + + + + + In order to make some window properties like position, size, + "always on top" or user defined rules for window behavior persistent, the + compositor needs some way to identify windows even after the application + has been restarted. + This protocol allows clients to make this possible by setting a tag for + toplevels. + + 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. + + + + + Destroy this toplevel tag manager object. This request has no other + effects. + + + + + + Set a tag for a toplevel. The tag may be shown to the user in UI, so + it's preferable for it to be human readable, but it must be suitable + for configuration files and should not be translated. + Suitable tags would for example be "main window", "settings", + "e-mail composer" or similar. + + The tag does not need to be unique across applications, and the client + may set the same tag for multiple windows, for example if the user has + opened the same UI twice. How the potentially resulting conflicts are + handled is compositor policy. + + The client should set the tag as part of the initial commit on the + associated toplevel, but it may set it at any time afterwards as well, + for example if the purpose of the toplevel changes. + + + + + + + + Set a description for a toplevel. This description may be shown to the + user in UI or read by a screen reader for accessibility purposes, and + should be translated. + It is recommended to make the description the translation of the tag. + + The client should set the description as part of the initial commit on + the associated toplevel, but it may set it at any time afterwards as + well, for example if the purpose of the toplevel changes. + + + + + + +