From a360198f8f983d7d85990748c411fb7a82654203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 9 Feb 2024 03:55:14 +0100 Subject: [PATCH] Wayland: Implement glfwFocusWindow This implements window focus requests via the xdg-activation-v1 protocol. These requests will likely only work when another window of the same application already has input focus, but that isn't unlike the behavior of other platforms. The GLFW_FEATURE_UNAVAILABLE error has been removed from this function for now. Related to #2284 Related to #2306 Related to #2439 --- README.md | 1 + docs/compat.dox | 5 ++--- include/GLFW/glfw3.h | 8 ++++---- src/wl_window.c | 32 ++++++++++++++++++++++++++++++-- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index fec484e2..b23ca0ed 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,7 @@ information on what to include when reporting a bug. - [Cocoa] Bugfix: Touching event queue from secondary thread before main thread would abort (#1649) - [Wayland] Added support for `glfwRequestWindowAttention` (#2287) + [Wayland] Added support for `glfwFocusWindow` - [Wayland] Added dynamic loading of all Wayland libraries - [Wayland] Bugfix: `CLOCK_MONOTONIC` was not correctly enabled - [X11] Bugfix: Termination would segfault if the IM had been destroyed diff --git a/docs/compat.dox b/docs/compat.dox index ddcd4dbc..66a92614 100644 --- a/docs/compat.dox +++ b/docs/compat.dox @@ -142,9 +142,8 @@ protocols either, no decorations will be drawn around windows. GLFW uses the [xdg-activation protocol](https://wayland.app/protocols/xdg-activation-v1) -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. +to implement window focus and attention requests. If the running compositor +does not support this protocol, window focus and attention requests do nothing. @section compat_glx GLX extensions diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 5e6fad42..6f8c9b41 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -3856,11 +3856,11 @@ GLFWAPI void glfwHideWindow(GLFWwindow* window); * * @param[in] window The window to give input focus. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks). + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @remark @wayland It is not possible for an application to set the input - * focus. This function will emit @ref GLFW_FEATURE_UNAVAILABLE. + * @remark @wayland The compositor will likely ignore focus requests unless + * another window created by the same application already has input focus. * * @thread_safety This function must only be called from the main thread. * diff --git a/src/wl_window.c b/src/wl_window.c index 981f2401..d7f12660 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -2378,8 +2378,36 @@ void _glfwRequestWindowAttentionWayland(_GLFWwindow* window) void _glfwFocusWindowWayland(_GLFWwindow* window) { - _glfwInputError(GLFW_FEATURE_UNAVAILABLE, - "Wayland: The platform does not support setting the input focus"); + if (!_glfw.wl.activationManager) + return; + + 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_set_serial(window->wl.activationToken, + _glfw.wl.serial, + _glfw.wl.seat); + + _GLFWwindow* requester = _glfw.wl.keyboardFocus; + if (requester) + { + xdg_activation_token_v1_set_surface(window->wl.activationToken, + requester->wl.surface); + + if (requester->wl.appId) + { + xdg_activation_token_v1_set_app_id(window->wl.activationToken, + requester->wl.appId); + } + } + + xdg_activation_token_v1_commit(window->wl.activationToken); } void _glfwSetWindowMonitorWayland(_GLFWwindow* window,