diff --git a/README.md b/README.md index 4df6f2b7..e0a7fd58 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,8 @@ information on what to include when reporting a bug. ## Changelog - Added `glfwGetError` function for querying the last error code (#970) +- Added `glfwRequestWindowAttention` function that request attention to the + non-focused or minimized window - Added `glfwGetKeyScancode` function that allows retrieving platform dependent scancodes for keys (#830) - Added `glfwSetWindowMaximizeCallback` and `GLFWwindowmaximizefun` for diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index f0426ffb..fb202209 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -2784,6 +2784,26 @@ GLFWAPI void glfwHideWindow(GLFWwindow* window); */ GLFWAPI void glfwFocusWindow(GLFWwindow* window); +/*! @brief Request attention to the specified window. + * + * This function makes the specified window to request attention. + * + * @param[in] window The window to request attention. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @macos The attention request will be made for the application and + * not the window passed in the argument. + * + * @thread_safety This function must only be called from the main thread. + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI void glfwRequestWindowAttention(GLFWwindow* window); + /*! @brief Returns the monitor that the window uses for full screen mode. * * This function returns the handle of the monitor that the specified window is diff --git a/src/cocoa_window.m b/src/cocoa_window.m index d2aab85f..d2b207bb 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1277,6 +1277,11 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) [window->ns.object orderOut:nil]; } +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) +{ + [NSApp requestUserAttention:NSInformationalRequest]; +} + void _glfwPlatformFocusWindow(_GLFWwindow* window) { // Make us the active application diff --git a/src/internal.h b/src/internal.h index b7c35be9..0772d8ee 100644 --- a/src/internal.h +++ b/src/internal.h @@ -630,6 +630,7 @@ void _glfwPlatformIconifyWindow(_GLFWwindow* window); void _glfwPlatformRestoreWindow(_GLFWwindow* window); void _glfwPlatformMaximizeWindow(_GLFWwindow* window); void _glfwPlatformShowWindow(_GLFWwindow* window); +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window); void _glfwPlatformHideWindow(_GLFWwindow* window); void _glfwPlatformFocusWindow(_GLFWwindow* window); void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); diff --git a/src/mir_window.c b/src/mir_window.c index e380f407..aefb8933 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -570,6 +570,10 @@ void _glfwPlatformShowWindow(_GLFWwindow* window) mir_window_spec_release(spec); } +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) +{ +} + void _glfwPlatformFocusWindow(_GLFWwindow* window) { _glfwInputError(GLFW_PLATFORM_ERROR, diff --git a/src/null_window.c b/src/null_window.c index 7f0101d4..137f80c8 100644 --- a/src/null_window.c +++ b/src/null_window.c @@ -172,6 +172,11 @@ void _glfwPlatformShowWindow(_GLFWwindow* window) { } + +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) +{ +} + void _glfwPlatformUnhideWindow(_GLFWwindow* window) { } diff --git a/src/win32_window.c b/src/win32_window.c index 363ef0f3..6d691e19 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1316,6 +1316,11 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) ShowWindow(window->win32.handle, SW_HIDE); } +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) +{ + FlashWindow(window->win32.handle, TRUE); +} + void _glfwPlatformFocusWindow(_GLFWwindow* window) { BringWindowToTop(window->win32.handle); diff --git a/src/window.c b/src/window.c index bf98723e..546d233d 100644 --- a/src/window.c +++ b/src/window.c @@ -675,6 +675,16 @@ GLFWAPI void glfwShowWindow(GLFWwindow* handle) _glfwPlatformFocusWindow(window); } +GLFWAPI void glfwRequestWindowAttention(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + _glfwPlatformRequestWindowAttention(window); +} + GLFWAPI void glfwHideWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; diff --git a/src/wl_window.c b/src/wl_window.c index e6c55452..9dace92a 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -599,6 +599,10 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) } } +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) +{ +} + void _glfwPlatformFocusWindow(_GLFWwindow* window) { _glfwInputError(GLFW_PLATFORM_ERROR, diff --git a/src/x11_init.c b/src/x11_init.c index 1767b695..a52216f0 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -438,6 +438,8 @@ static void detectEWMH(void) getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_VERT"); _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ = getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ"); + _glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_DEMANDS_ATTENTION"); _glfw.x11.NET_WM_FULLSCREEN_MONITORS = getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS"); _glfw.x11.NET_WM_WINDOW_TYPE = diff --git a/src/x11_platform.h b/src/x11_platform.h index bafe88f4..a0037c88 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -193,6 +193,7 @@ typedef struct _GLFWlibraryX11 Atom NET_WM_STATE_FULLSCREEN; Atom NET_WM_STATE_MAXIMIZED_VERT; Atom NET_WM_STATE_MAXIMIZED_HORZ; + Atom NET_WM_STATE_DEMANDS_ATTENTION; Atom NET_WM_BYPASS_COMPOSITOR; Atom NET_WM_FULLSCREEN_MONITORS; Atom NET_ACTIVE_WINDOW; diff --git a/src/x11_window.c b/src/x11_window.c index e1c2a3e3..fca3270e 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2077,6 +2077,21 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) XFlush(_glfw.x11.display); } +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) +{ + XEvent xev; + + memset(&xev, 0, sizeof(xev)); + xev.type = ClientMessage; + xev.xclient.window = window->x11.handle; + xev.xclient.message_type = _glfw.x11.NET_WM_STATE; + xev.xclient.format = 32; + xev.xclient.data.l[0] = _NET_WM_STATE_ADD; + xev.xclient.data.l[1] = _glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION; + + XSendEvent(_glfw.x11.display, DefaultRootWindow(_glfw.x11.display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); +} + void _glfwPlatformFocusWindow(_GLFWwindow* window) { if (_glfw.x11.NET_ACTIVE_WINDOW)