From 9ebcfb476432eeb48040804a1365ad20b199cf77 Mon Sep 17 00:00:00 2001 From: Green Lightning Date: Thu, 9 Nov 2017 16:59:40 +0100 Subject: [PATCH] Add window occlusion callback --- docs/window.dox | 33 +++++++++++++++++++++++++++++++++ include/GLFW/glfw3.h | 42 ++++++++++++++++++++++++++++++++++++++++++ src/cocoa_window.m | 5 +++++ src/internal.h | 2 ++ src/window.c | 19 +++++++++++++++++++ tests/events.c | 9 +++++++++ 6 files changed, 110 insertions(+) diff --git a/docs/window.dox b/docs/window.dox index 355a74e83..f35ebc741 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -1120,6 +1120,39 @@ not supported, the application as a whole. Once the user has given it attention, the system will automatically end the request. +@subsection window_occlusion Window occlusion state + +A window may not be visible to the user because it is occluded by other windows. +In contrast to a hidden window it will still be shown in the task bar, dock or +window list. The occluded state can change without any direct interaction with +the window, e.g. if the user moves an overlapping window out of the way. + +If you wish to be notified when a window becomes occluded or when a part of it +becomes visible again, set an occlusion callback. + +@code +glfwSetWindowOcclusionCallback(window, window_occlusion_callback); +@endcode + +The callback function receives changes in the occlusion state of the window. + +@code +void window_occlusion_callback(GLFWwindow* window, int occluded) +{ + if (occluded) + { + // The window became fully occluded by other windows + } + else + { + // The window is no longer fully occluded + } +} +@endcode + +@note This is currently implemented on macOS only. + + @subsection window_refresh Window damage and refresh If you wish to be notified when the contents of a window is damaged and needs diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index a511b94fc..f9a1374a9 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1239,6 +1239,23 @@ typedef void (* GLFWwindowrefreshfun)(GLFWwindow*); */ typedef void (* GLFWwindowfocusfun)(GLFWwindow*,int); +/*! @brief The function signature for window occlusion callbacks. + * + * This is the function signature for window occlusion callback functions. + * + * @param[in] window The window whose occlusion state changed. + * @param[in] occluded `GLFW_TRUE` if the window was occluded, or `GLFW_FALSE` + * if the window is no longer occluded. + * + * @sa @ref window_occlusion + * @sa @ref glfwSetWindowOcclusionCallback + * + * @since Added in version 3.3. + * + * @ingroup window + */ +typedef void (* GLFWwindowocclusionfun)(GLFWwindow*,int); + /*! @brief The function signature for window iconify/restore callbacks. * * This is the function signature for window iconify/restore callback @@ -3543,6 +3560,31 @@ GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* window, GL */ GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwindowfocusfun cbfun); +/*! @brief Sets the occlusion callback for the specified window. + * + * This function sets the occlusion callback of the specified window, which is + * called when the window becomes (fully) occluded by other windows or when (a + * part of) the window becomes visible again because an overlapping window is + * moved away. + * + * @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_occlusion + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI GLFWwindowocclusionfun glfwSetWindowOcclusionCallback(GLFWwindow* window, GLFWwindowocclusionfun cbfun); + /*! @brief Sets the iconify callback for the specified window. * * This function sets the iconification callback of the specified window, which diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 43a38ddad..85713678c 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -329,6 +329,11 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; _glfwInputWindowPos(window, x, y); } +- (void)windowDidChangeOcclusionState:(NSNotification *)notification +{ + _glfwInputWindowOcclusion(window, !([window->ns.object occlusionState] & NSWindowOcclusionStateVisible)); +} + - (void)windowDidMiniaturize:(NSNotification *)notification { if (window->monitor) diff --git a/src/internal.h b/src/internal.h index 7be2b267c..13d46c779 100644 --- a/src/internal.h +++ b/src/internal.h @@ -399,6 +399,7 @@ struct _GLFWwindow GLFWwindowclosefun close; GLFWwindowrefreshfun refresh; GLFWwindowfocusfun focus; + GLFWwindowocclusionfun occlusion; GLFWwindowiconifyfun iconify; GLFWwindowmaximizefun maximize; GLFWframebuffersizefun fbsize; @@ -697,6 +698,7 @@ void _glfwPlatformUnlockMutex(_GLFWmutex* mutex); ////////////////////////////////////////////////////////////////////////// void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused); +void _glfwInputWindowOcclusion(_GLFWwindow* window, GLFWbool occluded); void _glfwInputWindowPos(_GLFWwindow* window, int xpos, int ypos); void _glfwInputWindowSize(_GLFWwindow* window, int width, int height); void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height); diff --git a/src/window.c b/src/window.c index 4e365cb47..1ef160429 100644 --- a/src/window.c +++ b/src/window.c @@ -66,6 +66,14 @@ void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused) } } +// Notifies shared code that a window's occlusion state has changed +// +void _glfwInputWindowOcclusion(_GLFWwindow* window, GLFWbool occluded) +{ + if (window->callbacks.occlusion) + window->callbacks.occlusion((GLFWwindow*) window, occluded); +} + // Notifies shared code that a window has moved // The position is specified in client-area relative screen coordinates // @@ -1025,6 +1033,17 @@ GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* handle, return cbfun; } +GLFWAPI GLFWwindowocclusionfun glfwSetWindowOcclusionCallback(GLFWwindow* handle, + GLFWwindowocclusionfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.occlusion, cbfun); + return cbfun; +} + GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* handle, GLFWwindowiconifyfun cbfun) { diff --git a/tests/events.c b/tests/events.c index 9a0144d79..369c6aa98 100644 --- a/tests/events.c +++ b/tests/events.c @@ -326,6 +326,14 @@ static void window_focus_callback(GLFWwindow* window, int focused) focused ? "focused" : "defocused"); } +static void window_occlusion_callback(GLFWwindow* window, int occluded) +{ + Slot* slot = glfwGetWindowUserPointer(window); + printf("%08x to %i at %0.3f: Window %s\n", + counter++, slot->number, glfwGetTime(), + occluded ? "occluded" : "not occluded"); +} + static void window_iconify_callback(GLFWwindow* window, int iconified) { Slot* slot = glfwGetWindowUserPointer(window); @@ -608,6 +616,7 @@ int main(int argc, char** argv) glfwSetWindowCloseCallback(slots[i].window, window_close_callback); glfwSetWindowRefreshCallback(slots[i].window, window_refresh_callback); glfwSetWindowFocusCallback(slots[i].window, window_focus_callback); + glfwSetWindowOcclusionCallback(slots[i].window, window_occlusion_callback); glfwSetWindowIconifyCallback(slots[i].window, window_iconify_callback); glfwSetWindowMaximizeCallback(slots[i].window, window_maximize_callback); glfwSetMouseButtonCallback(slots[i].window, mouse_button_callback);