diff --git a/glfw/wl_init.c b/glfw/wl_init.c index 6bd8244b2..162df0431 100644 --- a/glfw/wl_init.c +++ b/glfw/wl_init.c @@ -99,7 +99,7 @@ static void pointerHandleEnter(void* data UNUSED, return; } window->wl.decorations.focus = focus; - _glfw.wl.serial = serial; + _glfw.wl.serial = serial; _glfw.wl.input_serial = serial; _glfw.wl.pointerFocus = window; window->wl.hovered = true; @@ -311,7 +311,7 @@ static void pointerHandleButton(void* data UNUSED, if (window->wl.decorations.focus != CENTRAL_WINDOW) return; - _glfw.wl.serial = serial; + _glfw.wl.serial = serial; _glfw.wl.input_serial = serial; /* Makes left, right and middle 0, 1 and 2. Overall order follows evdev * codes. */ @@ -463,7 +463,7 @@ static void keyboardHandleEnter(void* data UNUSED, return; } - _glfw.wl.serial = serial; + _glfw.wl.serial = serial; _glfw.wl.input_serial = serial; _glfw.wl.keyboardFocusId = window->id; _glfwInputWindowFocus(window, true); uint32_t* key; @@ -516,7 +516,7 @@ static void keyboardHandleKey(void* data UNUSED, return; int action = state == WL_KEYBOARD_KEY_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE; - _glfw.wl.serial = serial; + _glfw.wl.serial = serial; _glfw.wl.input_serial = serial; glfw_xkb_handle_key_event(window, &_glfw.wl.xkb, key, action); if (action == GLFW_PRESS && _glfw.wl.keyboardRepeatRate > 0 && glfw_xkb_should_repeat(&_glfw.wl.xkb, key)) @@ -539,7 +539,7 @@ static void keyboardHandleModifiers(void* data UNUSED, uint32_t modsLocked, uint32_t group) { - _glfw.wl.serial = serial; + _glfw.wl.serial = serial; _glfw.wl.input_serial = serial; glfw_xkb_update_modifiers(&_glfw.wl.xkb, modsDepressed, modsLatched, modsLocked, 0, 0, group); } diff --git a/glfw/wl_platform.h b/glfw/wl_platform.h index 0bd59383c..a32f45ed6 100644 --- a/glfw/wl_platform.h +++ b/glfw/wl_platform.h @@ -293,7 +293,7 @@ typedef struct _GLFWlibraryWayland struct wl_surface* cursorSurface; GLFWCursorShape cursorPreviousShape; - uint32_t serial; + uint32_t serial, input_serial; int32_t keyboardRepeatRate; monotonic_t keyboardRepeatDelay; diff --git a/glfw/wl_window.c b/glfw/wl_window.c index 2ec6a70fb..6def91bee 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -1160,12 +1160,17 @@ request_attention(GLFWwindow *window, const char *token, void *data UNUSED) { if (window && token && token[0]) xdg_activation_v1_activate(_glfw.wl.xdg_activation_v1, token, ((_GLFWwindow*)window)->wl.surface); } -void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) { +static bool +has_activation_in_flight(_GLFWwindow* window, GLFWactivationcallback callback) { for (size_t i = 0; i < _glfw.wl.activation_requests.sz; i++) { glfw_wl_xdg_activation_request *r = _glfw.wl.activation_requests.array + i; - if (r->window_id == window->id && r->callback == request_attention) return; + if (r->window_id == window->id && r->callback == callback) return true; } - get_activation_token(window, 0, request_attention, NULL); + return false; +} + +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) { + if (!has_activation_in_flight(window, request_attention)) get_activation_token(window, 0, request_attention, NULL); } int _glfwPlatformWindowBell(_GLFWwindow* window UNUSED) @@ -1174,10 +1179,21 @@ int _glfwPlatformWindowBell(_GLFWwindow* window UNUSED) return false; } +static void +focus_window(GLFWwindow *window, const char *token, void *data UNUSED) { + if (!window) return; + if (token && token[0]) xdg_activation_v1_activate(_glfw.wl.xdg_activation_v1, token, ((_GLFWwindow*)window)->wl.surface); + else { + _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Window focus request via xdg-activation protocol was denied by the compositor. Use a better compositor."); + } +} + void _glfwPlatformFocusWindow(_GLFWwindow* window UNUSED) { - _glfwInputError(GLFW_FEATURE_UNAVAILABLE, - "Wayland: The platform does not support setting the input focus"); + // Attempt to focus the window by using the activation protocol, whether it works + // is entirely compositor dependent and as we all know Wayland and its ecosystem is + // the product of morons. + if (_glfw.wl.input_serial && !has_activation_in_flight(window, focus_window)) get_activation_token(window, _glfw.wl.input_serial, focus_window, NULL); } void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,