From 8017945551233d61b289945b9c6ef71e33d91bb1 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 15 May 2025 09:35:42 +0530 Subject: [PATCH] Wayland: Add support for the xdg-toplevel-tag protocol Now you can use --name or its alias --os-window-tag to set the tag. --- docs/changelog.rst | 3 +++ glfw/glfw3.h | 1 + glfw/internal.h | 2 +- glfw/source-info.json | 1 + glfw/window.c | 4 ++++ glfw/wl_init.c | 5 +++++ glfw/wl_platform.h | 4 +++- glfw/wl_window.c | 4 +++- kitty/simple_cli_definitions.py | 15 ++++++++------- 9 files changed, 29 insertions(+), 10 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 75d39a35a..f1a14f05c 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -123,6 +123,9 @@ Detailed list of changes - Panel kitten: A new ``center-sized`` value for :option:`--edge ` to allow easily creating sized and centered panels +- Wayland: The `kitty --name` flag now sets the XDG *window tag* on compositors + that support the `xdg-toplevel-tag `__ protocol. + 0.42.0 [2025-05-11] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/glfw/glfw3.h b/glfw/glfw3.h index 79a14f9cc..9ed81564d 100644 --- a/glfw/glfw3.h +++ b/glfw/glfw3.h @@ -1056,6 +1056,7 @@ typedef enum { #define GLFW_WAYLAND_APP_ID 0x00025001 #define GLFW_WAYLAND_BGCOLOR 0x00025002 +#define GLFW_WAYLAND_WINDOW_TAG 0x00025003 /*! @} */ #define GLFW_NO_API 0 diff --git a/glfw/internal.h b/glfw/internal.h index f476d650f..69d4ab963 100644 --- a/glfw/internal.h +++ b/glfw/internal.h @@ -331,7 +331,7 @@ struct _GLFWwndconfig char instanceName[256]; } x11; struct { - char appId[256]; + char appId[256], windowTag[256]; uint32_t bgcolor; } wl; }; diff --git a/glfw/source-info.json b/glfw/source-info.json index 876a04e9f..766ca1015 100644 --- a/glfw/source-info.json +++ b/glfw/source-info.json @@ -86,6 +86,7 @@ "unstable/idle-inhibit/idle-inhibit-unstable-v1.xml", "staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml", "staging/xdg-system-bell/xdg-system-bell-v1.xml", + "staging/xdg-toplevel-tag/xdg-toplevel-tag-v1.xml", "kwin-blur-v1.xml", "wlr-layer-shell-unstable-v1.xml" diff --git a/glfw/window.c b/glfw/window.c index be5bcfe4e..56b4e5447 100644 --- a/glfw/window.c +++ b/glfw/window.c @@ -495,6 +495,10 @@ GLFWAPI void glfwWindowHintString(int hint, const char* value) strncpy(_glfw.hints.window.wl.appId, value, sizeof(_glfw.hints.window.wl.appId) - 1); return; + case GLFW_WAYLAND_WINDOW_TAG: + strncpy(_glfw.hints.window.wl.windowTag, value, + sizeof(_glfw.hints.window.wl.windowTag) - 1); + return; } _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint string 0x%08X", hint); diff --git a/glfw/wl_init.c b/glfw/wl_init.c index 5bbca1d7f..122ed879f 100644 --- a/glfw/wl_init.c +++ b/glfw/wl_init.c @@ -605,6 +605,8 @@ static void registryHandleGlobal(void* data UNUSED, } else if (is(xdg_system_bell_v1)) { _glfw.wl.xdg_system_bell_v1 = wl_registry_bind(registry, name, &xdg_system_bell_v1_interface, 1); + } else if (is(xdg_toplevel_tag_manager_v1)) { + _glfw.wl.xdg_toplevel_tag_manager_v1 = wl_registry_bind(registry, name, &xdg_toplevel_tag_manager_v1_interface, 1); } #undef is } @@ -716,6 +718,7 @@ get_compositor_missing_capabilities(void) { C(cursor_shape, wp_cursor_shape_manager_v1); C(layer_shell, zwlr_layer_shell_v1); C(single_pixel_buffer, wp_single_pixel_buffer_manager_v1); C(preferred_scale, has_preferred_buffer_scale); C(idle_inhibit, idle_inhibit_manager); C(icon, xdg_toplevel_icon_manager_v1); C(bell, xdg_system_bell_v1); + C(window-tag, xdg_toplevel_tag_manager_v1); if (_glfw.wl.xdg_wm_base_version < 6) p += snprintf(p, sizeof(buf) - (p - buf), "%s ", "window-state-suspended"); if (_glfw.wl.xdg_wm_base_version < 5) p += snprintf(p, sizeof(buf) - (p - buf), "%s ", "window-capabilities"); #undef C @@ -894,6 +897,8 @@ void _glfwPlatformTerminate(void) xdg_toplevel_icon_manager_v1_destroy(_glfw.wl.xdg_toplevel_icon_manager_v1); if (_glfw.wl.xdg_system_bell_v1) xdg_system_bell_v1_destroy(_glfw.wl.xdg_system_bell_v1); + if (_glfw.wl.xdg_toplevel_tag_manager_v1) + xdg_toplevel_tag_manager_v1_destroy(_glfw.wl.xdg_toplevel_tag_manager_v1); if (_glfw.wl.wp_single_pixel_buffer_manager_v1) wp_single_pixel_buffer_manager_v1_destroy(_glfw.wl.wp_single_pixel_buffer_manager_v1); if (_glfw.wl.wp_cursor_shape_manager_v1) diff --git a/glfw/wl_platform.h b/glfw/wl_platform.h index 0b4a3a9bf..ddf763794 100644 --- a/glfw/wl_platform.h +++ b/glfw/wl_platform.h @@ -68,6 +68,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR #include "wayland-idle-inhibit-unstable-v1-client-protocol.h" #include "wayland-xdg-toplevel-icon-v1-client-protocol.h" #include "wayland-xdg-system-bell-v1-client-protocol.h" +#include "wayland-xdg-toplevel-tag-v1-client-protocol.h" #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) #define _glfw_dlclose(handle) dlclose(handle) @@ -210,7 +211,7 @@ typedef struct _GLFWwindowWayland double cursorPosX, cursorPosY, allCursorPosX, allCursorPosY; char* title; - char appId[256]; + char appId[256], windowTag[256]; // We need to track the monitors the window spans on to calculate the // optimal scaling factor. @@ -340,6 +341,7 @@ typedef struct _GLFWlibraryWayland struct xdg_activation_v1* xdg_activation_v1; struct xdg_toplevel_icon_manager_v1* xdg_toplevel_icon_manager_v1; struct xdg_system_bell_v1* xdg_system_bell_v1; + struct xdg_toplevel_tag_manager_v1* xdg_toplevel_tag_manager_v1; struct wp_cursor_shape_manager_v1* wp_cursor_shape_manager_v1; struct wp_cursor_shape_device_v1* wp_cursor_shape_device_v1; struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1; diff --git a/glfw/wl_window.c b/glfw/wl_window.c index e75232545..1d08293ca 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -1198,8 +1198,10 @@ create_window_desktop_surface(_GLFWwindow* window) zxdg_toplevel_decoration_v1_add_listener(window->wl.xdg.decoration, &xdgDecorationListener, window); } - if (strlen(window->wl.appId)) + if (window->wl.appId[0]) xdg_toplevel_set_app_id(window->wl.xdg.toplevel, window->wl.appId); + if (window->wl.windowTag[0] && _glfw.wl.xdg_toplevel_tag_manager_v1) + xdg_toplevel_tag_manager_v1_set_toplevel_tag(_glfw.wl.xdg_toplevel_tag_manager_v1, window->wl.xdg.toplevel, window->wl.windowTag); if (window->wl.title) xdg_toplevel_set_title(window->wl.xdg.toplevel, window->wl.title); diff --git a/kitty/simple_cli_definitions.py b/kitty/simple_cli_definitions.py index 86a34651e..e2ae26395 100644 --- a/kitty/simple_cli_definitions.py +++ b/kitty/simple_cli_definitions.py @@ -375,13 +375,13 @@ def kitty_options_spec() -> str: dest=cls default={appname} condition=not is_macos -Set the class part of the :italic:`WM_CLASS` window property. On Wayland, it -sets the app id. +Set the :italic:`application id` on Wayland. On X11 set the class part of the :italic:`WM_CLASS` window property. ---name +--name --os-window-tag condition=not is_macos -Set the name part of the :italic:`WM_CLASS` property. Defaults to using the +On Wayland, set the :italic:`window tag`. +On X11, set the name part of the :italic:`WM_CLASS` property, when unset, defaults to using the value from :option:`{appname} --class`. @@ -650,12 +650,13 @@ Use the special value :code:`list` to get a list of available outputs. dest=cls default={cls} condition=not is_macos -Set the class part of the :italic:`WM_CLASS` window property. On Wayland, it sets the app id. +Set the :italic:`application id` on Wayland. On X11 set the class part of the :italic:`WM_CLASS` window property. ---name +--name --os-window-tag condition=not is_macos -Set the name part of the :italic:`WM_CLASS` property (defaults to using the value from :option:`{appname} --class`) +On X11 sets the name part of the :italic:`WM_CLASS` property on X11, +when unspecified uses the value from :option:`{appname} --class` on X11. --focus-policy