From abc1db8505cd495ab6ddde094bc1449ebe47e08d Mon Sep 17 00:00:00 2001 From: GamesTrap Date: Wed, 1 Mar 2023 19:56:11 +0100 Subject: [PATCH] Wayland: Implemented glfwRequestWindowAttention via xdg-activation-v1 protocol --- CONTRIBUTORS.md | 1 + docs/compat.dox | 6 ++++++ src/CMakeLists.txt | 3 +++ src/wl_init.c | 14 ++++++++++++++ src/wl_platform.h | 2 ++ src/wl_window.c | 37 ++++++++++++++++++++++++++++++++++--- 6 files changed, 60 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 47301dae..d7f9174a 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -202,6 +202,7 @@ video tutorials. - Riku Salminen - Brandon Schaefer - Sebastian Schuberth + - Jan Schuerkamp - Christian Sdunek - Matt Sealey - Steve Sexton diff --git a/docs/compat.dox b/docs/compat.dox index 94372197..f58e9e1b 100644 --- a/docs/compat.dox +++ b/docs/compat.dox @@ -141,6 +141,12 @@ This protocol is part of wayland-protocols 1.4, and mandatory at build time. If the running compositor does not support this protocol either, no decorations will be drawn around windows. +GLFW uses the [xdg-activation +protocol](https://cgit.freedesktop.org/wayland/wayland-protocols/tree/staging/xdg-activation/xdg-activation-v1.xml) +to enable attention requests. This protocol is part of +wayland-protocols staging, and mandatory at build time. If the running compositor +does not support this protocol, the attention requests do nothing. + @section compat_glx GLX extensions diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 01f191c9..24f7df8d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -113,6 +113,9 @@ if (GLFW_BUILD_WAYLAND) wayland_generate( "${WAYLAND_PROTOCOLS_BASE}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml" "${GLFW_BINARY_DIR}/src/wayland-idle-inhibit-unstable-v1-client-protocol") + wayland_generate( + "${WAYLAND_PROTOCOLS_BASE}/staging/xdg-activation/xdg-activation-v1.xml" + "${GLFW_BINARY_DIR}/src/wayland-xdg-activation-v1-client-protocol") endif() if (WIN32 AND GLFW_BUILD_SHARED_LIBRARY) diff --git a/src/wl_init.c b/src/wl_init.c index 7a9157a4..9e103ab5 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -48,6 +48,7 @@ #include "wayland-relative-pointer-unstable-v1-client-protocol.h" #include "wayland-pointer-constraints-unstable-v1-client-protocol.h" #include "wayland-idle-inhibit-unstable-v1-client-protocol.h" +#include "wayland-xdg-activation-v1-client-protocol.h" // NOTE: Versions of wayland-scanner prior to 1.17.91 named every global array of // wl_interface pointers 'types', making it impossible to combine several unmodified @@ -82,6 +83,10 @@ #include "wayland-idle-inhibit-unstable-v1-client-protocol-code.h" #undef types +#define types _glfw_xdg_activation_types +#include "wayland-xdg-activation-v1-client-protocol-code.h" +#undef types + static void wmBaseHandlePing(void* userData, struct xdg_wm_base* wmBase, uint32_t serial) @@ -180,6 +185,13 @@ static void registryHandleGlobal(void* userData, &zwp_idle_inhibit_manager_v1_interface, 1); } + else if (strcmp(interface, "xdg_activation_v1") == 0) + { + _glfw.wl.activationManager = + wl_registry_bind(registry, name, + &xdg_activation_v1_interface, + 1); + } } static void registryHandleGlobalRemove(void* userData, @@ -777,6 +789,8 @@ void _glfwTerminateWayland(void) zwp_pointer_constraints_v1_destroy(_glfw.wl.pointerConstraints); if (_glfw.wl.idleInhibitManager) zwp_idle_inhibit_manager_v1_destroy(_glfw.wl.idleInhibitManager); + if (_glfw.wl.activationManager) + xdg_activation_v1_destroy(_glfw.wl.activationManager); if (_glfw.wl.registry) wl_registry_destroy(_glfw.wl.registry); if (_glfw.wl.display) diff --git a/src/wl_platform.h b/src/wl_platform.h index 238e1ed4..865e7e0c 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -272,6 +272,7 @@ typedef struct _GLFWwindowWayland struct zwp_confined_pointer_v1* confinedPointer; struct zwp_idle_inhibitor_v1* idleInhibitor; + struct xdg_activation_token_v1* activationToken; struct { struct wl_buffer* buffer; @@ -300,6 +301,7 @@ typedef struct _GLFWlibraryWayland struct zwp_relative_pointer_manager_v1* relativePointerManager; struct zwp_pointer_constraints_v1* pointerConstraints; struct zwp_idle_inhibit_manager_v1* idleInhibitManager; + struct xdg_activation_v1* activationManager; _GLFWofferWayland* offers; unsigned int offerCount; diff --git a/src/wl_window.c b/src/wl_window.c index a227c16f..46a62a07 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -50,6 +50,7 @@ #include "wayland-relative-pointer-unstable-v1-client-protocol.h" #include "wayland-pointer-constraints-unstable-v1-client-protocol.h" #include "wayland-idle-inhibit-unstable-v1-client-protocol.h" +#include "wayland-xdg-activation-v1-client-protocol.h" #define GLFW_BORDER_SIZE 4 #define GLFW_CAPTION_HEIGHT 24 @@ -1854,6 +1855,9 @@ void _glfwDestroyWindowWayland(_GLFWwindow* window) if (window == _glfw.wl.keyboardFocus) _glfw.wl.keyboardFocus = NULL; + if (window->wl.activationToken) + xdg_activation_token_v1_destroy(window->wl.activationToken); + if (window->wl.idleInhibitor) zwp_idle_inhibitor_v1_destroy(window->wl.idleInhibitor); @@ -2085,11 +2089,38 @@ void _glfwHideWindowWayland(_GLFWwindow* window) } } +static void xdgActivationHandleDone(void* userData, + struct xdg_activation_token_v1* activationToken, + const char* token) +{ + _GLFWwindow* window = userData; + + if(activationToken != window->wl.activationToken) + return; + + xdg_activation_v1_activate(_glfw.wl.activationManager, token, window->wl.surface); + xdg_activation_token_v1_destroy(window->wl.activationToken); + window->wl.activationToken = NULL; +} + +static const struct xdg_activation_token_v1_listener xdgActivationListener = +{ + xdgActivationHandleDone +}; + void _glfwRequestWindowAttentionWayland(_GLFWwindow* window) { - // TODO - _glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, - "Wayland: Window attention request not implemented yet"); + if(!_glfw.wl.activationManager) + return; + + //We're about to overwrite this with a new request + if(window->wl.activationToken) + xdg_activation_token_v1_destroy(window->wl.activationToken); + + window->wl.activationToken = xdg_activation_v1_get_activation_token(_glfw.wl.activationManager); + xdg_activation_token_v1_add_listener(window->wl.activationToken, &xdgActivationListener, window); + + xdg_activation_token_v1_commit(window->wl.activationToken); } void _glfwFocusWindowWayland(_GLFWwindow* window)