diff --git a/README.md b/README.md index fe365cb0..cc11851d 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,8 @@ The following dependencies are needed by the examples and test programs: - Bugfix: The debug context attribute was set from `GL_ARB_debug_output` even when a debug context had not been requested - Bugfix: The particles example was not linked against the threading library + - Added `glfwPostEmptyEvent` for allowing secondary threads to cause + `glfwWaitEvents` to return - [Cocoa] Added `_GLFW_USE_RETINA` to control whether windows will use the full resolution on Retina displays - [Cocoa] Bugfix: Using a 1x1 cursor for hidden mode caused some screen diff --git a/docs/news.dox b/docs/news.dox index b02861ec..0be9cd06 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -13,6 +13,13 @@ GLFW now provides a callback for receiving the paths of files dropped onto GLFW windows. The callback is set with the @ref glfwSetDropCallback function. +@subsection news_31_emptyevent Empty event support + +GLFW now provides the @ref glfwPostEmptyEvent function for posting an empty +event from a secondary thread to the main thread event queue, causing @ref +glfwWaitEvents to return. + + @section news_30 New features in version 3.0 @subsection news_30_cmake CMake build system diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 28244370..df6ca00d 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1745,6 +1745,10 @@ GLFWAPI void glfwPollEvents(void); * [window refresh callback](@ref GLFWwindowrefreshfun) to redraw the contents * of your window when necessary during the operation. * + * @remarks If no windows exist, this function returns immediately. For + * synchronization of threads in applications that do not create windows, use + * your threading library of choice. + * * @note This function may only be called from the main thread. * * @note This function may not be called from a callback. @@ -1758,6 +1762,23 @@ GLFWAPI void glfwPollEvents(void); */ GLFWAPI void glfwWaitEvents(void); +/*! @brief Posts an empty event to the event queue. + * + * This function posts an empty event from the current thread to the main + * thread event queue, causing @ref glfwWaitEvents to return. + * + * @remarks If no windows exist, this function returns immediately. For + * synchronization of threads in applications that do not create windows, use + * your threading library of choice. + * + * @remarks This function may be called from secondary threads. + * + * @sa glfwWaitEvents + * + * @ingroup window + */ +GLFWAPI void glfwPostEmptyEvent(void); + /*! @brief Returns the value of an input option for the specified window. * * @param[in] window The window to query. diff --git a/src/cocoa_window.m b/src/cocoa_window.m index e59a5964..6b05baca 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1147,6 +1147,20 @@ void _glfwPlatformWaitEvents(void) _glfwPlatformPollEvents(); } +void _glfwPlatformPostEmptyEvent(void) +{ + NSEvent* event = [NSEvent otherEventWithType:NSApplicationDefined + location:NSMakePoint(0, 0) + modifierFlags:0 + timestamp:0 + windowNumber:0 + context:nil + subtype:0 + data1:0 + data2:0]; + [NSApp postEvent:event atStart:YES]; +} + void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) { setModeCursor(window); diff --git a/src/internal.h b/src/internal.h index 171aa650..8c4d11ea 100644 --- a/src/internal.h +++ b/src/internal.h @@ -539,6 +539,11 @@ void _glfwPlatformPollEvents(void); */ void _glfwPlatformWaitEvents(void); +/*! @copydoc glfwPostEmptyEvent + * @ingroup platform + */ +void _glfwPlatformPostEmptyEvent(void); + /*! @copydoc glfwMakeContextCurrent * @ingroup platform */ diff --git a/src/win32_window.c b/src/win32_window.c index 882d56ce..b6085381 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1181,6 +1181,12 @@ void _glfwPlatformWaitEvents(void) _glfwPlatformPollEvents(); } +void _glfwPlatformPostEmptyEvent(void) +{ + _GLFWwindow* window = _glfw.windowListHead; + PostMessage(window->win32.handle, WM_NULL, 0, 0); +} + void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos) { POINT pos = { (int) xpos, (int) ypos }; diff --git a/src/window.c b/src/window.c index cecfd5ed..0c7eb014 100644 --- a/src/window.c +++ b/src/window.c @@ -669,6 +669,20 @@ GLFWAPI void glfwPollEvents(void) GLFWAPI void glfwWaitEvents(void) { _GLFW_REQUIRE_INIT(); + + if (!_glfw.windowListHead) + return; + _glfwPlatformWaitEvents(); } +GLFWAPI void glfwPostEmptyEvent(void) +{ + _GLFW_REQUIRE_INIT(); + + if (!_glfw.windowListHead) + return; + + _glfwPlatformPostEmptyEvent(); +} + diff --git a/src/x11_window.c b/src/x11_window.c index eeb82474..ec0c005e 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1305,6 +1305,21 @@ void _glfwPlatformWaitEvents(void) _glfwPlatformPollEvents(); } +void _glfwPlatformPostEmptyEvent(void) +{ + XEvent event; + _GLFWwindow* window = _glfw.windowListHead; + + memset(&event, 0, sizeof(event)); + event.type = ClientMessage; + event.xclient.window = window->x11.handle; + event.xclient.format = 32; // Data is 32-bit longs + event.xclient.message_type = _glfw.x11._NULL; + + XSendEvent(_glfw.x11.display, window->x11.handle, False, 0, &event); + XFlush(_glfw.x11.display); +} + void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) { // Store the new position so it can be recognized later