From c156b50e4c61f8d9d32d137f252190ead4d6f1a4 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Thu, 16 Jun 2016 13:09:28 +0200 Subject: [PATCH] Add glfwSetWindowMaximizeCallback Fixes #778. --- README.md | 2 ++ docs/news.dox | 5 +++++ docs/window.dox | 51 +++++++++++++++++++++++++++++++++++++++++++- include/GLFW/glfw3.h | 41 +++++++++++++++++++++++++++++++++++ src/cocoa_platform.h | 2 ++ src/cocoa_window.m | 7 ++++++ src/internal.h | 9 ++++++++ src/win32_platform.h | 1 + src/win32_window.c | 31 ++++++++++++--------------- src/window.c | 17 +++++++++++++++ src/x11_platform.h | 2 ++ src/x11_window.c | 35 +++++++++++++++++++++--------- tests/events.c | 11 +++++++++- tests/iconify.c | 10 ++++++++- 14 files changed, 194 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 024c5ec0..dc480f0b 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,8 @@ information on what to include when reporting a bug. - Added `glfwGetKeyScancode` function that allows retrieving platform dependent scancodes for keys (#830) +- Added `glfwSetWindowMaximizeCallback` and `GLFWwindowmaximizefun` for + receiving window maximization events (#778) - Bugfix: Calling `glfwMaximizeWindow` on a full screen window was not ignored - Bugfix: `GLFW_INCLUDE_VULKAN` could not be combined with the corresponding OpenGL and OpenGL ES header macros diff --git a/docs/news.dox b/docs/news.dox index 4e8266ea..1e92eb4f 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -4,6 +4,11 @@ @section news_33 New features in 3.3 +@subsection news_33_maximize Window maximization callback + +GLFW now supports window maximization notifications with @ref +glfwSetWindowMaximizeCallback. + @subsection news_33_keyscancode Platform-specific key scancode query diff --git a/docs/window.dox b/docs/window.dox index 25e2a5ea..1ad09742 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -730,7 +730,8 @@ glfwIconifyWindow(window); When a full screen window is iconified, the original video mode of its monitor is restored until the user or application restores the window. -Iconified windows can be restored with @ref glfwRestoreWindow. +Iconified windows can be restored with @ref glfwRestoreWindow. This function +also restores windows from maximization. @code glfwRestoreWindow(window); @@ -769,6 +770,54 @@ int iconified = glfwGetWindowAttrib(window, GLFW_ICONIFIED); @endcode +@subsection window_maximize Window maximization + +Windows can be maximized (i.e. zoomed) with @ref glfwMaximizeWindow. + +@code +glfwMaximizeWindow(window); +@endcode + +Full screen windows cannot be maximized and passing a full screen window to this +function does nothing. + +Maximized windows can be restored with @ref glfwRestoreWindow. This function +also restores windows from iconification. + +@code +glfwRestoreWindow(window); +@endcode + +If you wish to be notified when a window is maximized or restored, whether by +the user, system or your own code, set a maximize callback. + +@code +glfwSetWindowMaximizeCallback(window, window_maximize_callback); +@endcode + +The callback function receives changes in the maximization state of the window. + +@code +void window_maximize_callback(GLFWwindow* window, int maximized) +{ + if (maximized) + { + // The window was maximized + } + else + { + // The window was restored + } +} +@endcode + +You can also get the current maximization state with @ref glfwGetWindowAttrib. + +@code +int maximized = glfwGetWindowAttrib(window, GLFW_MAXIMIZED); +@endcode + + @subsection window_hide Window visibility Windowed mode windows can be hidden with @ref glfwHideWindow. diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 156c1f44..3e23968e 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -921,6 +921,24 @@ typedef void (* GLFWwindowfocusfun)(GLFWwindow*,int); */ typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int); +/*! @brief The function signature for window maximize/restore callbacks. + * + * This is the function signature for window maximize/restore callback + * functions. + * + * @param[in] window The window that was maximized or restored. + * @param[in] iconified `GLFW_TRUE` if the window was maximized, or + * `GLFW_FALSE` if it was restored. + * + * @sa @ref window_maximize + * @sa glfwSetWindowMaximizeCallback + * + * @since Added in version 3.3. + * + * @ingroup window + */ +typedef void (* GLFWwindowmaximizefun)(GLFWwindow*,int); + /*! @brief The function signature for framebuffer resize callbacks. * * This is the function signature for framebuffer resize callback @@ -2705,6 +2723,29 @@ GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwi */ GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* window, GLFWwindowiconifyfun cbfun); +/*! @brief Sets the maximize callback for the specified window. + * + * This function sets the maximization callback of the specified window, which + * is called when the window is maximized or restored. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_maximize + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* window, GLFWwindowmaximizefun cbfun); + /*! @brief Sets the framebuffer resize callback for the specified window. * * This function sets the framebuffer resize callback of the specified window, diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index 1534b567..d76d7de7 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -75,6 +75,8 @@ typedef struct _GLFWwindowNS id delegate; id view; + GLFWbool maximized; + // The total sum of the distances the cursor has been warped // since the last cursor motion event was processed // This is kept to counteract Cocoa doing the same internally diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 940d7fb0..57032b56 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -238,6 +238,13 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; if (_glfw.ns.disabledCursorWindow == window) centerCursor(window); + const int maximized = [window->ns.object isZoomed]; + if (window->ns.maximized != maximized) + { + window->ns.maximized = maximized; + _glfwInputWindowMaximize(window, maximized); + } + const NSRect contentRect = [window->ns.view frame]; const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect]; diff --git a/src/internal.h b/src/internal.h index 72f690b8..4d92c554 100644 --- a/src/internal.h +++ b/src/internal.h @@ -378,6 +378,7 @@ struct _GLFWwindow GLFWwindowrefreshfun refresh; GLFWwindowfocusfun focus; GLFWwindowiconifyfun iconify; + GLFWwindowmaximizefun maximize; GLFWframebuffersizefun fbsize; GLFWmousebuttonfun mouseButton; GLFWcursorposfun cursorPos; @@ -856,6 +857,14 @@ void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height); */ void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified); +/*! @brief Notifies shared code of a window maximization event. + * @param[in] window The window that received the event. + * @param[in] maximized `GLFW_TRUE` if the window was maximized, or + * `GLFW_FALSE` if it was restored. + * @ingroup event + */ +void _glfwInputWindowMaximize(_GLFWwindow* window, GLFWbool maximized); + /*! @brief Notifies shared code of a window damage event. * @param[in] window The window that received the event. */ diff --git a/src/win32_platform.h b/src/win32_platform.h index 58088544..162ea4dd 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -235,6 +235,7 @@ typedef struct _GLFWwindowWin32 GLFWbool cursorTracked; GLFWbool iconified; + GLFWbool maximized; // The last received cursor position, regardless of source int lastCursorPosX, lastCursorPosY; diff --git a/src/win32_window.c b/src/win32_window.c index ed67780e..db24c75d 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -693,36 +693,33 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_SIZE: { - const GLFWbool iconified = - !window->win32.iconified && wParam == SIZE_MINIMIZED; - const GLFWbool restored = - window->win32.iconified && - (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED); + const GLFWbool iconified = wParam == SIZE_MINIMIZED; + const GLFWbool maximized = wParam == SIZE_MAXIMIZED || + (window->win32.maximized && + wParam != SIZE_RESTORED); if (_glfw.win32.disabledCursorWindow == window) updateClipRect(window); - if (iconified) - _glfwInputWindowIconify(window, GLFW_TRUE); - else if (restored) - _glfwInputWindowIconify(window, GLFW_FALSE); + if (window->win32.iconified != iconified) + _glfwInputWindowIconify(window, iconified); + + if (window->win32.maximized != maximized) + _glfwInputWindowMaximize(window, maximized); _glfwInputFramebufferSize(window, LOWORD(lParam), HIWORD(lParam)); _glfwInputWindowSize(window, LOWORD(lParam), HIWORD(lParam)); - if (iconified) + if (window->monitor && window->win32.iconified != iconified) { - window->win32.iconified = GLFW_TRUE; - if (window->monitor) + if (iconified) releaseMonitor(window); - } - else if (restored) - { - window->win32.iconified = GLFW_FALSE; - if (window->monitor) + else acquireMonitor(window); } + window->win32.iconified = iconified; + window->win32.maximized = maximized; return 0; } diff --git a/src/window.c b/src/window.c index fe741dc6..0917336a 100644 --- a/src/window.c +++ b/src/window.c @@ -86,6 +86,12 @@ void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified) window->callbacks.iconify((GLFWwindow*) window, iconified); } +void _glfwInputWindowMaximize(_GLFWwindow* window, GLFWbool maximized) +{ + if (window->callbacks.maximize) + window->callbacks.maximize((GLFWwindow*) window, maximized); +} + void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height) { if (window->callbacks.fbsize) @@ -856,6 +862,17 @@ GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* handle, return cbfun; } +GLFWAPI GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* handle, + GLFWwindowmaximizefun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.maximize, cbfun); + return cbfun; +} + GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* handle, GLFWframebuffersizefun cbfun) { diff --git a/src/x11_platform.h b/src/x11_platform.h index 2a65eda9..754d7990 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -112,6 +112,8 @@ typedef struct _GLFWwindowX11 XIC ic; GLFWbool overrideRedirect; + GLFWbool iconified; + GLFWbool maximized; // Cached position and size used to filter out duplicate events int width, height; diff --git a/src/x11_window.c b/src/x11_window.c index 3b418eb0..cbb039ad 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -559,6 +559,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, { states[count++] = _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT; states[count++] = _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ; + window->x11.maximized = GLFW_TRUE; } } @@ -1415,23 +1416,37 @@ static void processEvent(XEvent *event) case PropertyNotify: { - if (event->xproperty.atom == _glfw.x11.WM_STATE && - event->xproperty.state == PropertyNewValue) + if (event->xproperty.state != PropertyNewValue) + return; + + if (event->xproperty.atom == _glfw.x11.WM_STATE) { const int state = getWindowState(window); - if (state == IconicState) + if (state != IconicState && state != NormalState) + return; + + const GLFWbool iconified = (state == IconicState); + if (window->x11.iconified != iconified) { if (window->monitor) - releaseMonitor(window); + { + if (iconified) + releaseMonitor(window); + else + acquireMonitor(window); + } - _glfwInputWindowIconify(window, GLFW_TRUE); + window->x11.iconified = iconified; + _glfwInputWindowIconify(window, iconified); } - else if (state == NormalState) + } + else if (event->xproperty.atom == _glfw.x11.NET_WM_STATE) + { + const GLFWbool maximized = _glfwPlatformWindowMaximized(window); + if (window->x11.maximized != maximized) { - if (window->monitor) - acquireMonitor(window); - - _glfwInputWindowIconify(window, GLFW_FALSE); + window->x11.maximized = maximized; + _glfwInputWindowMaximize(window, maximized); } } diff --git a/tests/events.c b/tests/events.c index 674b584e..b0b34e4f 100644 --- a/tests/events.c +++ b/tests/events.c @@ -322,7 +322,15 @@ static void window_iconify_callback(GLFWwindow* window, int iconified) Slot* slot = glfwGetWindowUserPointer(window); printf("%08x to %i at %0.3f: Window was %s\n", counter++, slot->number, glfwGetTime(), - iconified ? "iconified" : "restored"); + iconified ? "iconified" : "uniconified"); +} + +static void window_maximize_callback(GLFWwindow* window, int maximized) +{ + Slot* slot = glfwGetWindowUserPointer(window); + printf("%08x to %i at %0.3f: Window was %s\n", + counter++, slot->number, glfwGetTime(), + maximized ? "maximized" : "unmaximized"); } static void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) @@ -580,6 +588,7 @@ int main(int argc, char** argv) glfwSetWindowRefreshCallback(slots[i].window, window_refresh_callback); glfwSetWindowFocusCallback(slots[i].window, window_focus_callback); glfwSetWindowIconifyCallback(slots[i].window, window_iconify_callback); + glfwSetWindowMaximizeCallback(slots[i].window, window_maximize_callback); glfwSetMouseButtonCallback(slots[i].window, mouse_button_callback); glfwSetCursorPosCallback(slots[i].window, cursor_position_callback); glfwSetCursorEnterCallback(slots[i].window, cursor_enter_callback); diff --git a/tests/iconify.c b/tests/iconify.c index b7c74236..ba6425c4 100644 --- a/tests/iconify.c +++ b/tests/iconify.c @@ -131,7 +131,14 @@ static void window_iconify_callback(GLFWwindow* window, int iconified) { printf("%0.2f Window %s\n", glfwGetTime(), - iconified ? "iconified" : "restored"); + iconified ? "iconified" : "uniconified"); +} + +static void window_maximize_callback(GLFWwindow* window, int maximized) +{ + printf("%0.2f Window %s\n", + glfwGetTime(), + maximized ? "maximized" : "unmaximized"); } static void window_refresh_callback(GLFWwindow* window) @@ -266,6 +273,7 @@ int main(int argc, char** argv) glfwSetWindowSizeCallback(windows[i], window_size_callback); glfwSetWindowFocusCallback(windows[i], window_focus_callback); glfwSetWindowIconifyCallback(windows[i], window_iconify_callback); + glfwSetWindowMaximizeCallback(windows[i], window_maximize_callback); glfwSetWindowRefreshCallback(windows[i], window_refresh_callback); window_refresh_callback(windows[i]);