diff --git a/README.md b/README.md index f9469332..7bac5486 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ does not find Doxygen, the documentation will not be generated. `glfwGetInstanceProcAddress`, `glfwGetPhysicalDevicePresentationSupport` and `glfwCreateWindowSurface` for platform independent Vulkan support - Added `glfwMaximizeWindow` and `GLFW_MAXIMIZED` for window maximization + - Added `glfwFocusWindow` for giving windows input focus - Added `glfwSetWindowSizeLimits` and `glfwSetWindowAspectRatio` for setting absolute and relative window size limits - Added `glfwGetKeyName` for querying the layout-specific name of printable diff --git a/docs/news.dox b/docs/news.dox index 601eee48..6bf800ac 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -32,6 +32,11 @@ GLFW now supports window maximization with @ref glfwMaximizeWindow and the [GLFW_MAXIMIZED](@ref window_attribs_wnd) window hint and attribute. +@subsection news_32_focus Window input focus control + +GLFW now supports giving windows input focus with @ref glfwFocusWindow. + + @section news_31 New features in 3.1 These are the release highlights. For a full list of changes see the diff --git a/docs/window.dox b/docs/window.dox index b7c7b731..a40005d9 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -715,6 +715,13 @@ int visible = glfwGetWindowAttrib(window, GLFW_VISIBLE); @subsection window_focus Window input focus +Windows can be given input focus and brought to the front with @ref +glfwFocusWindow. + +@code +glfwFocusWindow(window); +@endcode + If you wish to be notified when a window gains or loses input focus, whether by the user, system or your own code, set a focus callback. diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 41e5f7d8..68d005dd 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -2283,6 +2283,34 @@ GLFWAPI void glfwShowWindow(GLFWwindow* window); */ GLFWAPI void glfwHideWindow(GLFWwindow* window); +/*! @brief Brings the specified window to front and sets input focus. + * + * This function brings the specified window to front and sets input focus. + * The window should already be visible and not iconified. + * + * By default, both windowed and full screen mode windows are focused when + * initially created. Set the [GLFW_FOCUSED](@ref window_hints_wnd) to disable + * this behavior. + * + * __Do not use this function__ to steal focus from other applications unless + * you are certain that is what the user wants. Focus stealing can be + * extremely disruptive. + * + * @param[in] window The window to give input focus. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_focus + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwFocusWindow(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 093d2b0a..1ad9cc1a 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -84,6 +84,7 @@ static GLFWbool enterFullscreenMode(_GLFWwindow* window) bounds.size.height); [window->ns.object setFrame:frame display:YES]; + _glfwPlatformFocusWindow(window); return status; } @@ -1039,6 +1040,16 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window) } void _glfwPlatformShowWindow(_GLFWwindow* window) +{ + [window->ns.object orderFront:nil]; +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) +{ + [window->ns.object orderOut:nil]; +} + +void _glfwPlatformFocusWindow(_GLFWwindow* window) { // Make us the active application // HACK: This has been moved here from initializeAppKit to prevent @@ -1049,16 +1060,6 @@ void _glfwPlatformShowWindow(_GLFWwindow* window) [window->ns.object makeKeyAndOrderFront:nil]; } -void _glfwPlatformUnhideWindow(_GLFWwindow* window) -{ - [window->ns.object orderFront:nil]; -} - -void _glfwPlatformHideWindow(_GLFWwindow* window) -{ - [window->ns.object orderOut:nil]; -} - int _glfwPlatformWindowFocused(_GLFWwindow* window) { return [window->ns.object isKeyWindow]; diff --git a/src/internal.h b/src/internal.h index 358da256..48488233 100644 --- a/src/internal.h +++ b/src/internal.h @@ -684,15 +684,16 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window); */ void _glfwPlatformShowWindow(_GLFWwindow* window); -/*! @ingroup platform - */ -void _glfwPlatformUnhideWindow(_GLFWwindow* window); - /*! @copydoc glfwHideWindow * @ingroup platform */ void _glfwPlatformHideWindow(_GLFWwindow* window); +/*! @copydoc glfwFocusWindow + * @ingroup platform + */ +void _glfwPlatformFocusWindow(_GLFWwindow* window); + /*! @brief Returns whether the window is focused. * @ingroup platform */ diff --git a/src/mir_window.c b/src/mir_window.c index 0642d08d..9d8f1fd3 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -495,7 +495,7 @@ void _glfwPlatformShowWindow(_GLFWwindow* window) mir_surface_spec_release(spec); } -void _glfwPlatformUnhideWindow(_GLFWwindow* window) +void _glfwPlatformFocusWindow(_GLFWwindow* window) { _glfwInputError(GLFW_PLATFORM_ERROR, "Mir: Unsupported function %s", __PRETTY_FUNCTION__); diff --git a/src/win32_window.c b/src/win32_window.c index 5bbd0409..85a72ad9 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1034,14 +1034,6 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window) } void _glfwPlatformShowWindow(_GLFWwindow* window) -{ - ShowWindow(window->win32.handle, SW_SHOW); - BringWindowToTop(window->win32.handle); - SetForegroundWindow(window->win32.handle); - SetFocus(window->win32.handle); -} - -void _glfwPlatformUnhideWindow(_GLFWwindow* window) { ShowWindow(window->win32.handle, SW_SHOW); } @@ -1051,6 +1043,13 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) ShowWindow(window->win32.handle, SW_HIDE); } +void _glfwPlatformFocusWindow(_GLFWwindow* window) +{ + BringWindowToTop(window->win32.handle); + SetForegroundWindow(window->win32.handle); + SetFocus(window->win32.handle); +} + int _glfwPlatformWindowFocused(_GLFWwindow* window) { return window->win32.handle == GetActiveWindow(); diff --git a/src/window.c b/src/window.c index f051370e..daff5486 100644 --- a/src/window.c +++ b/src/window.c @@ -231,10 +231,9 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, { if (wndconfig.visible) { + _glfwPlatformShowWindow(window); if (wndconfig.focused) - _glfwPlatformShowWindow(window); - else - _glfwPlatformUnhideWindow(window); + _glfwPlatformFocusWindow(window); } } @@ -629,6 +628,16 @@ GLFWAPI void glfwHideWindow(GLFWwindow* handle) _glfwPlatformHideWindow(window); } +GLFWAPI void glfwFocusWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window); + + _GLFW_REQUIRE_INIT(); + + _glfwPlatformFocusWindow(window); +} + GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) { _GLFWwindow* window = (_GLFWwindow*) handle; diff --git a/src/wl_window.c b/src/wl_window.c index b3b9bea2..1fe5b86a 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -470,18 +470,18 @@ void _glfwPlatformShowWindow(_GLFWwindow* window) wl_shell_surface_set_toplevel(window->wl.shell_surface); } -void _glfwPlatformUnhideWindow(_GLFWwindow* window) -{ - // TODO - fprintf(stderr, "_glfwPlatformUnhideWindow not implemented yet\n"); -} - void _glfwPlatformHideWindow(_GLFWwindow* window) { wl_surface_attach(window->wl.surface, NULL, 0, 0); wl_surface_commit(window->wl.surface); } +void _glfwPlatformFocusWindow(_GLFWwindow* window) +{ + // TODO + fprintf(stderr, "_glfwPlatformFocusWindow not implemented yet\n"); +} + int _glfwPlatformWindowFocused(_GLFWwindow* window) { // TODO diff --git a/src/x11_window.c b/src/x11_window.c index 2f9130a7..ad007d9f 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -763,19 +763,7 @@ static void enterFullscreenMode(_GLFWwindow* window) 0); } - if (_glfw.x11.NET_ACTIVE_WINDOW) - { - // Ask the window manager to raise and focus the GLFW window - // Only focused windows with the _NET_WM_STATE_FULLSCREEN state end up - // on top of all other windows ("Stacking order" in EWMH spec) - sendEventToWM(window, _glfw.x11.NET_ACTIVE_WINDOW, 1, 0, 0, 0, 0); - } - else - { - XRaiseWindow(_glfw.x11.display, window->x11.handle); - XSetInputFocus(_glfw.x11.display, window->x11.handle, - RevertToParent, CurrentTime); - } + _glfwPlatformFocusWindow(window); if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN) { @@ -1810,12 +1798,6 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window) } void _glfwPlatformShowWindow(_GLFWwindow* window) -{ - XMapRaised(_glfw.x11.display, window->x11.handle); - XFlush(_glfw.x11.display); -} - -void _glfwPlatformUnhideWindow(_GLFWwindow* window) { XMapWindow(_glfw.x11.display, window->x11.handle); XFlush(_glfw.x11.display); @@ -1827,6 +1809,25 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) XFlush(_glfw.x11.display); } +void _glfwPlatformFocusWindow(_GLFWwindow* window) +{ + if (_glfw.x11.NET_ACTIVE_WINDOW) + { + // Ask the window manager to raise and focus the GLFW window + // Only focused windows with the _NET_WM_STATE_FULLSCREEN state end up + // on top of all other windows ("Stacking order" in EWMH spec) + sendEventToWM(window, _glfw.x11.NET_ACTIVE_WINDOW, 1, 0, 0, 0, 0); + } + else + { + XRaiseWindow(_glfw.x11.display, window->x11.handle); + XSetInputFocus(_glfw.x11.display, window->x11.handle, + RevertToParent, CurrentTime); + } + + XFlush(_glfw.x11.display); +} + int _glfwPlatformWindowFocused(_GLFWwindow* window) { Window focused;