From d1c07976306440b5abd7bafb6e0723e1ffd0e366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 11 Feb 2022 12:37:38 +0100 Subject: [PATCH 01/30] Wayland: Fix multiple copies of single constant (cherry picked from commit a28adba06acc4e5a09e836bd5d4569636c5d3f65) --- src/wl_init.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/wl_init.c b/src/wl_init.c index fa7a5cfe..685cc650 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -1195,14 +1195,15 @@ int _glfwPlatformInit(void) wl_data_device_manager_get_data_device(_glfw.wl.dataDeviceManager, _glfw.wl.seat); wl_data_device_add_listener(_glfw.wl.dataDevice, &dataDeviceListener, NULL); - _glfw.wl.clipboardString = malloc(4096); + + _glfw.wl.clipboardSize = 4096; + _glfw.wl.clipboardString = calloc(_glfw.wl.clipboardSize, 1); if (!_glfw.wl.clipboardString) { _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Unable to allocate clipboard memory"); return GLFW_FALSE; } - _glfw.wl.clipboardSize = 4096; } return GLFW_TRUE; From 7a4813cedd50a6fb29c7493f157b28f2719812ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 11 Feb 2022 12:40:21 +0100 Subject: [PATCH 02/30] Wayland: Remove unnecessary NULL checks It is fine to pass NULL to free. (cherry picked from commit 4a68926bfd999c835009429e6452b2c271252959) --- src/wl_init.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/wl_init.c b/src/wl_init.c index 685cc650..7459953a 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -1294,10 +1294,8 @@ void _glfwPlatformTerminate(void) if (_glfw.wl.cursorTimerfd >= 0) close(_glfw.wl.cursorTimerfd); - if (_glfw.wl.clipboardString) - free(_glfw.wl.clipboardString); - if (_glfw.wl.clipboardSendString) - free(_glfw.wl.clipboardSendString); + free(_glfw.wl.clipboardString); + free(_glfw.wl.clipboardSendString); } const char* _glfwPlatformGetVersionString(void) From 93403243809267204b01dfd1a03aadbc68c8821b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 11 Feb 2022 12:36:35 +0100 Subject: [PATCH 03/30] Wayland: Fix error type for allocation failure (cherry picked from commit 152f50cd0149ace9242971bf1bae3a5abde24951) --- src/wl_init.c | 2 +- src/wl_window.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wl_init.c b/src/wl_init.c index 7459953a..0ec99106 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -1200,7 +1200,7 @@ int _glfwPlatformInit(void) _glfw.wl.clipboardString = calloc(_glfw.wl.clipboardSize, 1); if (!_glfw.wl.clipboardString) { - _glfwInputError(GLFW_PLATFORM_ERROR, + _glfwInputError(GLFW_OUT_OF_MEMORY, "Wayland: Unable to allocate clipboard memory"); return GLFW_FALSE; } diff --git a/src/wl_window.c b/src/wl_window.c index 50e701cd..3273362c 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -1762,7 +1762,7 @@ static GLFWbool growClipboardString(void) clipboard = realloc(clipboard, _glfw.wl.clipboardSize * 2); if (!clipboard) { - _glfwInputError(GLFW_PLATFORM_ERROR, + _glfwInputError(GLFW_OUT_OF_MEMORY, "Wayland: Impossible to grow clipboard string"); return GLFW_FALSE; } From 09470b68c1945e58e982cb96d820fdfe50ab777d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sat, 1 Jan 2022 20:18:33 +0100 Subject: [PATCH 04/30] Wayland: Clean up monitor scale update (cherry picked from commit 20adc18aa587b75867775942d25356014e11fde9) --- src/wl_window.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index 3273362c..33623627 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -404,27 +404,25 @@ static void resizeWindow(_GLFWwindow* window) static void checkScaleChange(_GLFWwindow* window) { - int scale = 1; - int i; - int monitorScale; - // Check if we will be able to set the buffer scale or not. if (_glfw.wl.compositorVersion < 3) return; // Get the scale factor from the highest scale monitor. - for (i = 0; i < window->wl.monitorsCount; ++i) + int maxScale = 1; + + for (int i = 0; i < window->wl.monitorsCount; i++) { - monitorScale = window->wl.monitors[i]->wl.scale; - if (scale < monitorScale) - scale = monitorScale; + const int scale = window->wl.monitors[i]->wl.scale; + if (maxScale < scale) + maxScale = scale; } // Only change the framebuffer size if the scale changed. - if (scale != window->wl.scale) + if (window->wl.scale != maxScale) { - window->wl.scale = scale; - wl_surface_set_buffer_scale(window->wl.surface, scale); + window->wl.scale = maxScale; + wl_surface_set_buffer_scale(window->wl.surface, maxScale); resizeWindow(window); } } From 54f2a865e97165138c514256fc3ac9f821c4b5df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 6 Jan 2022 07:07:53 +0100 Subject: [PATCH 05/30] GLX: Fix context creation failing unnecessarily Regression introduced with 3bb5c459d63d7cf9c990213e39303d9ba5eaebcc. (cherry picked from commit 2e656afc4972827930e845c3124a08c42ac5d564) --- README.md | 1 + src/glx_context.c | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a010ae04..d0deac37 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,7 @@ information on what to include when reporting a bug. - [Wayland] Bugfix: Full screen window creation did not ignore `GLFW_VISIBLE` - [Wayland] Bugfix: Some keys were reported as wrong key or `GLFW_KEY_UNKNOWN` - [Wayland] Bugfix: Text input did not repeat along with key repeat + - [GLX] Bugfix: Context creation failed if GLX 1.4 was not exported by GLX library ## Contact diff --git a/src/glx_context.c b/src/glx_context.c index 4bf0d966..06bc080e 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -309,10 +309,6 @@ GLFWbool _glfwInitGLX(void) _glfw_dlsym(_glfw.glx.handle, "glXCreateWindow"); _glfw.glx.DestroyWindow = _glfw_dlsym(_glfw.glx.handle, "glXDestroyWindow"); - _glfw.glx.GetProcAddress = - _glfw_dlsym(_glfw.glx.handle, "glXGetProcAddress"); - _glfw.glx.GetProcAddressARB = - _glfw_dlsym(_glfw.glx.handle, "glXGetProcAddressARB"); _glfw.glx.GetVisualFromFBConfig = _glfw_dlsym(_glfw.glx.handle, "glXGetVisualFromFBConfig"); @@ -328,8 +324,6 @@ GLFWbool _glfwInitGLX(void) !_glfw.glx.CreateNewContext || !_glfw.glx.CreateWindow || !_glfw.glx.DestroyWindow || - !_glfw.glx.GetProcAddress || - !_glfw.glx.GetProcAddressARB || !_glfw.glx.GetVisualFromFBConfig) { _glfwInputError(GLFW_PLATFORM_ERROR, @@ -337,6 +331,12 @@ GLFWbool _glfwInitGLX(void) return GLFW_FALSE; } + // NOTE: Unlike GLX 1.3 entry points these are not required to be present + _glfw.glx.GetProcAddress = (PFNGLXGETPROCADDRESSPROC) + _glfw_dlsym(_glfw.glx.handle, "glXGetProcAddress"); + _glfw.glx.GetProcAddressARB = (PFNGLXGETPROCADDRESSPROC) + _glfw_dlsym(_glfw.glx.handle, "glXGetProcAddressARB"); + if (!glXQueryExtension(_glfw.x11.display, &_glfw.glx.errorBase, &_glfw.glx.eventBase)) From ca1a98e7a2d4e029fa3ece888221d9c23a093ec3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 1 Feb 2022 22:05:55 +0100 Subject: [PATCH 06/30] X11: Fix event polling when event fd > 1023 This replaces select with poll for checking for data on event file descriptors, as select cannot handle file descriptors larger than 1023. Closes #2024 (cherry picked from commit d3e4fcf8b7608e7b6f6cf1c102b1e28c478f5a6c) --- CONTRIBUTORS.md | 1 + README.md | 2 ++ src/x11_window.c | 30 ++++++++++++------------------ 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 4526e5b2..b35d2428 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -81,6 +81,7 @@ video tutorials. - Paul Holden - Warren Hu - Charles Huber + - illustris - InKryption - IntellectualKitty - Aaron Jacobs diff --git a/README.md b/README.md index d0deac37..da0fc03d 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,8 @@ information on what to include when reporting a bug. - [Cocoa] Bugfix: `kUTTypeURL` was deprecated in macOS 12.0 (#2003) - [X11] Bugfix: Dynamic loading on OpenBSD failed due to soname differences + - [X11] Bugfix: Waiting for events would fail if file descriptor was too large + (#2024) - [Wayland] Added support for key names via xkbcommon - [Wayland] Bugfix: Key repeat could lead to a race condition (#1710) - [Wayland] Bugfix: Activating a window would emit two input focus events diff --git a/src/x11_window.c b/src/x11_window.c index 356572d8..f328c297 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -32,7 +32,7 @@ #include #include -#include +#include #include #include @@ -57,37 +57,31 @@ #define _GLFW_XDND_VERSION 5 -// Wait for data to arrive using select +// Wait for event data to arrive on any relevant file descriptor // This avoids blocking other threads via the per-display Xlib lock that also // covers GLX functions // static GLFWbool waitForEvent(double* timeout) { - fd_set fds; - const int fd = ConnectionNumber(_glfw.x11.display); - int count = fd + 1; - -#if defined(__linux__) - if (_glfw.linjs.inotify > fd) - count = _glfw.linjs.inotify + 1; -#endif for (;;) { - FD_ZERO(&fds); - FD_SET(fd, &fds); + nfds_t count = 1; + struct pollfd fds[2] = + { + { ConnectionNumber(_glfw.x11.display), POLLIN } + }; + #if defined(__linux__) if (_glfw.linjs.inotify > 0) - FD_SET(_glfw.linjs.inotify, &fds); + fds[count++] = (struct pollfd) { _glfw.linjs.inotify, POLLIN }; #endif if (timeout) { - const long seconds = (long) *timeout; - const long microseconds = (long) ((*timeout - seconds) * 1e6); - struct timeval tv = { seconds, microseconds }; + const int milliseconds = (int) (*timeout * 1e3); const uint64_t base = _glfwPlatformGetTimerValue(); - const int result = select(count, &fds, NULL, NULL, &tv); + const int result = poll(fds, count, milliseconds); const int error = errno; *timeout -= (_glfwPlatformGetTimerValue() - base) / @@ -98,7 +92,7 @@ static GLFWbool waitForEvent(double* timeout) if ((result == -1 && error == EINTR) || *timeout <= 0.0) return GLFW_FALSE; } - else if (select(count, &fds, NULL, NULL, NULL) != -1 || errno != EINTR) + else if (poll(fds, count, -1) != -1 || errno != EINTR) return GLFW_TRUE; } } From b4aa5f626f874eedea32ffd10f0f6112258a8050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 18 Feb 2022 15:13:18 +0100 Subject: [PATCH 07/30] X11: Retry poll when failed with EINTR or EAGAIN Both of these errors should just lead to local retry. (cherry picked from commit 92b5c67b50d2bab9401f464d4a40fecfccb09dfb) --- src/x11_window.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/x11_window.c b/src/x11_window.c index f328c297..a7cbb207 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -82,18 +82,26 @@ static GLFWbool waitForEvent(double* timeout) const uint64_t base = _glfwPlatformGetTimerValue(); const int result = poll(fds, count, milliseconds); - const int error = errno; + const int error = errno; // clock_gettime may overwrite our error *timeout -= (_glfwPlatformGetTimerValue() - base) / (double) _glfwPlatformGetTimerFrequency(); if (result > 0) return GLFW_TRUE; - if ((result == -1 && error == EINTR) || *timeout <= 0.0) + else if (result == -1 && error != EINTR && error != EAGAIN) + return GLFW_FALSE; + else if (*timeout <= 0.0) + return GLFW_FALSE; + } + else + { + const int result = poll(fds, count, -1); + if (result > 0) + return GLFW_TRUE; + else if (result == -1 && errno != EINTR && errno != EAGAIN) return GLFW_FALSE; } - else if (poll(fds, count, -1) != -1 || errno != EINTR) - return GLFW_TRUE; } } From 811e6bb01c1cca938613635d250d422b9b530d9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 18 Feb 2022 15:19:16 +0100 Subject: [PATCH 08/30] X11: Fix joystick events causing busy waiting On Linux, the inotify descriptor was included in the set used for select, but could not break the outer loop, leading to busy waiting until timeout or the correct X11 event arrived. This commit adds a new function for waiting just on X11 events. Fixes #1872 (cherry picked from commit 1e987cb92ea646282a2e3f7c085f96ae7eeea425) --- README.md | 1 + src/x11_window.c | 59 +++++++++++++++++++++++++++++------------------- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index da0fc03d..fa846aad 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,7 @@ information on what to include when reporting a bug. - [X11] Bugfix: Dynamic loading on OpenBSD failed due to soname differences - [X11] Bugfix: Waiting for events would fail if file descriptor was too large (#2024) + - [X11] Bugfix: Joystick events could lead to busy-waiting (#1872) - [Wayland] Added support for key names via xkbcommon - [Wayland] Bugfix: Key repeat could lead to a race condition (#1710) - [Wayland] Bugfix: Activating a window would emit two input focus events diff --git a/src/x11_window.c b/src/x11_window.c index a7cbb207..0d49c76c 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -56,26 +56,12 @@ #define _GLFW_XDND_VERSION 5 - -// Wait for event data to arrive on any relevant file descriptor -// This avoids blocking other threads via the per-display Xlib lock that also -// covers GLX functions +// Wait for data to arrive on any of the specified file descriptors // -static GLFWbool waitForEvent(double* timeout) +static GLFWbool waitForData(struct pollfd* fds, nfds_t count, double* timeout) { for (;;) { - nfds_t count = 1; - struct pollfd fds[2] = - { - { ConnectionNumber(_glfw.x11.display), POLLIN } - }; - -#if defined(__linux__) - if (_glfw.linjs.inotify > 0) - fds[count++] = (struct pollfd) { _glfw.linjs.inotify, POLLIN }; -#endif - if (timeout) { const int milliseconds = (int) (*timeout * 1e3); @@ -105,6 +91,33 @@ static GLFWbool waitForEvent(double* timeout) } } +// Wait for event data to arrive on the X11 display socket +// This avoids blocking other threads via the per-display Xlib lock that also +// covers GLX functions +// +static GLFWbool waitForX11Event(double* timeout) +{ + struct pollfd fd = { ConnectionNumber(_glfw.x11.display), POLLIN }; + return waitForData(&fd, 1, timeout); +} + +// Wait for event data to arrive on any event file descriptor +// This avoids blocking other threads via the per-display Xlib lock that also +// covers GLX functions +// +static GLFWbool waitForAnyEvent(double* timeout) +{ + nfds_t count = 1; + struct pollfd fds[2] = { { ConnectionNumber(_glfw.x11.display), POLLIN } }; + +#if defined(__linux__) + if (_glfw.linjs.inotify > 0) + fds[count++] = (struct pollfd) { _glfw.linjs.inotify, POLLIN }; +#endif + + return waitForData(fds, count, timeout); +} + // Waits until a VisibilityNotify event arrives for the specified window or the // timeout period elapses (ICCCM section 4.2.2) // @@ -118,7 +131,7 @@ static GLFWbool waitForVisibilityNotify(_GLFWwindow* window) VisibilityNotify, &dummy)) { - if (!waitForEvent(&timeout)) + if (!waitForX11Event(&timeout)) return GLFW_FALSE; } @@ -973,7 +986,7 @@ static const char* getSelectionString(Atom selection) SelectionNotify, ¬ification)) { - waitForEvent(NULL); + waitForX11Event(NULL); } if (notification.xselection.property == None) @@ -1009,7 +1022,7 @@ static const char* getSelectionString(Atom selection) isSelPropNewValueNotify, (XPointer) ¬ification)) { - waitForEvent(NULL); + waitForX11Event(NULL); } XFree(data); @@ -1940,7 +1953,7 @@ void _glfwPushSelectionToManagerX11(void) } } - waitForEvent(NULL); + waitForX11Event(NULL); } } @@ -2258,7 +2271,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, isFrameExtentsEvent, (XPointer) window)) { - if (!waitForEvent(&timeout)) + if (!waitForX11Event(&timeout)) { _glfwInputError(GLFW_PLATFORM_ERROR, "X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue"); @@ -2785,7 +2798,7 @@ void _glfwPlatformPollEvents(void) void _glfwPlatformWaitEvents(void) { while (!XPending(_glfw.x11.display)) - waitForEvent(NULL); + waitForAnyEvent(NULL); _glfwPlatformPollEvents(); } @@ -2794,7 +2807,7 @@ void _glfwPlatformWaitEventsTimeout(double timeout) { while (!XPending(_glfw.x11.display)) { - if (!waitForEvent(&timeout)) + if (!waitForAnyEvent(&timeout)) break; } From 7f752c17c69ead01ae57fe70e4a49818928160fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 18 Feb 2022 15:20:10 +0100 Subject: [PATCH 09/30] X11: Fix glfwWaitEvents* ignoring joystick events The data available on the X11 connection may be a reply or an internal event for an X11 extension. Previously the check for whether an event was available for us was done outside waitForEvent. This prevented data available on other file descriptors from breaking the outer wait loop. This commit moves the check for whether an event is available into the wait functions, where there is enough knowledge to limit the check to the X11 connection. Related to #932 (cherry picked from commit 87970b7f265bbd39595de6428bbd14047affa753) --- README.md | 1 + src/x11_window.c | 34 +++++++++++++++++++++++----------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index fa846aad..6e150414 100644 --- a/README.md +++ b/README.md @@ -128,6 +128,7 @@ information on what to include when reporting a bug. - [X11] Bugfix: Waiting for events would fail if file descriptor was too large (#2024) - [X11] Bugfix: Joystick events could lead to busy-waiting (#1872) + - [X11] Bugfix: `glfwWaitEvents*` did not continue for joystick events - [Wayland] Added support for key names via xkbcommon - [Wayland] Bugfix: Key repeat could lead to a race condition (#1710) - [Wayland] Bugfix: Activating a window would emit two input focus events diff --git a/src/x11_window.c b/src/x11_window.c index 0d49c76c..94d83334 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -98,7 +98,14 @@ static GLFWbool waitForData(struct pollfd* fds, nfds_t count, double* timeout) static GLFWbool waitForX11Event(double* timeout) { struct pollfd fd = { ConnectionNumber(_glfw.x11.display), POLLIN }; - return waitForData(&fd, 1, timeout); + + while (!XPending(_glfw.x11.display)) + { + if (!waitForData(&fd, 1, timeout)) + return GLFW_FALSE; + } + + return GLFW_TRUE; } // Wait for event data to arrive on any event file descriptor @@ -115,7 +122,19 @@ static GLFWbool waitForAnyEvent(double* timeout) fds[count++] = (struct pollfd) { _glfw.linjs.inotify, POLLIN }; #endif - return waitForData(fds, count, timeout); + while (!XPending(_glfw.x11.display)) + { + if (!waitForData(fds, count, timeout)) + return GLFW_FALSE; + + for (int i = 1; i < count; i++) + { + if (fds[i].revents & POLLIN) + return GLFW_TRUE; + } + } + + return GLFW_TRUE; } // Waits until a VisibilityNotify event arrives for the specified window or the @@ -2797,20 +2816,13 @@ void _glfwPlatformPollEvents(void) void _glfwPlatformWaitEvents(void) { - while (!XPending(_glfw.x11.display)) - waitForAnyEvent(NULL); - + waitForAnyEvent(NULL); _glfwPlatformPollEvents(); } void _glfwPlatformWaitEventsTimeout(double timeout) { - while (!XPending(_glfw.x11.display)) - { - if (!waitForAnyEvent(&timeout)) - break; - } - + waitForAnyEvent(&timeout); _glfwPlatformPollEvents(); } From e219c00d8740e1e7a7e84693d3690c694c7adc88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 18 Feb 2022 15:35:09 +0100 Subject: [PATCH 10/30] Cleanup (cherry picked from commit 363d4714414e53312cd5cb0be230f040580487ad) --- src/x11_window.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/x11_window.c b/src/x11_window.c index 94d83334..6de0bcd4 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2782,8 +2782,6 @@ GLFWbool _glfwPlatformRawMouseMotionSupported(void) void _glfwPlatformPollEvents(void) { - _GLFWwindow* window; - #if defined(__linux__) _glfwDetectJoystickConnectionLinux(); #endif @@ -2796,7 +2794,7 @@ void _glfwPlatformPollEvents(void) processEvent(&event); } - window = _glfw.x11.disabledCursorWindow; + _GLFWwindow* window = _glfw.x11.disabledCursorWindow; if (window) { int width, height; From 5ccc756c560bdf6e17886b903574848e514008d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 18 Feb 2022 14:29:43 +0100 Subject: [PATCH 11/30] X11: Fix empty event race condition with a pipe There is a seemingly unavoidable race condition when waiting for data on the X11 display connection, as long as any other thread is also making Xlib calls. The event data we are waiting for could be read by the other thread as part of looking for the reply to its request, before our poll has begun. This commit replaces the X11 event sent by glfwPostEmptyEvent with writing to an unnamed pipe. The race condition remains if other Xlib calls are made on other threads, but glfwPostEmptyEvent should now be race-free. This commit is based on work by pcwalton, OlivierSohn, kovidgoyal and joaodasilva. Closes #2033 Related to #379 Related to #1281 Related to #1285 (cherry picked from commit cd22e2849512a88d0ab77bc7a3458646625f2c50) --- CONTRIBUTORS.md | 2 ++ README.md | 2 ++ docs/news.dox | 6 ++++++ src/x11_init.c | 43 +++++++++++++++++++++++++++++++++++++++++++ src/x11_platform.h | 1 + src/x11_window.c | 44 +++++++++++++++++++++++++++++++++++--------- 6 files changed, 89 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index b35d2428..c17b7374 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -180,12 +180,14 @@ video tutorials. - Ali Sherief - Yoshiki Shibukawa - Dmitri Shuralyov + - Joao da Silva - Daniel Sieger - Daniel Skorupski - Bradley Smith - Cliff Smolinsky - Patrick Snape - Erlend Sogge Heggen + - Olivier Sohn - Julian Squires - Johannes Stein - Pontus Stenetorp diff --git a/README.md b/README.md index 6e150414..f0c1ac02 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,8 @@ information on what to include when reporting a bug. (#2024) - [X11] Bugfix: Joystick events could lead to busy-waiting (#1872) - [X11] Bugfix: `glfwWaitEvents*` did not continue for joystick events + - [X11] Bugfix: `glfwPostEmptyEvent` could be ignored due to race condition + (#379,#1281,#1285,#2033) - [Wayland] Added support for key names via xkbcommon - [Wayland] Bugfix: Key repeat could lead to a race condition (#1710) - [Wayland] Bugfix: Activating a window would emit two input focus events diff --git a/docs/news.dox b/docs/news.dox index c21a8b8a..b5421c1a 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -306,6 +306,12 @@ GLFW_TRANSPARENT_FRAMEBUFFER on Windows 7 if DWM transparency is off (the Transparency setting under Personalization > Window Color). +@subsubsection emptyevents_33 Empty events on X11 no longer roundtrip to server + +Starting with GLFW 3.3.7, events posted with @ref glfwPostEmptyEvent now use a separate +unnamed pipe instead of sending an X11 client event to the helper window. + + @subsection deprecations_33 Deprecations in version 3.3 @subsubsection charmods_callback_33 Character with modifiers callback diff --git a/src/x11_init.c b/src/x11_init.c index 3bf8b839..5e6071f5 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -36,6 +36,9 @@ #include #include #include +#include +#include +#include // Translate the X11 KeySyms for a key to a GLFW key code @@ -968,6 +971,37 @@ static Window createHelperWindow(void) CWEventMask, &wa); } +// Create the pipe for empty events without assumuing the OS has pipe2(2) +// +static GLFWbool createEmptyEventPipe(void) +{ + if (pipe(_glfw.x11.emptyEventPipe) != 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to create empty event pipe: %s", + strerror(errno)); + return GLFW_FALSE; + } + + for (int i = 0; i < 2; i++) + { + const int sf = fcntl(_glfw.x11.emptyEventPipe[i], F_GETFL, 0); + const int df = fcntl(_glfw.x11.emptyEventPipe[i], F_GETFD, 0); + + if (sf == -1 || df == -1 || + fcntl(_glfw.x11.emptyEventPipe[i], F_SETFL, sf | O_NONBLOCK) == -1 || + fcntl(_glfw.x11.emptyEventPipe[i], F_SETFD, df | FD_CLOEXEC) == -1) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to set flags for empty event pipe: %s", + strerror(errno)); + return GLFW_FALSE; + } + } + + return GLFW_TRUE; +} + // X error handler // static int errorHandler(Display *display, XErrorEvent* event) @@ -1089,6 +1123,9 @@ int _glfwPlatformInit(void) getSystemContentScale(&_glfw.x11.contentScaleX, &_glfw.x11.contentScaleY); + if (!createEmptyEventPipe()) + return GLFW_FALSE; + if (!initExtensions()) return GLFW_FALSE; @@ -1206,6 +1243,12 @@ void _glfwPlatformTerminate(void) #if defined(__linux__) _glfwTerminateJoysticksLinux(); #endif + + if (_glfw.x11.emptyEventPipe[0] || _glfw.x11.emptyEventPipe[1]) + { + close(_glfw.x11.emptyEventPipe[0]); + close(_glfw.x11.emptyEventPipe[1]); + } } const char* _glfwPlatformGetVersionString(void) diff --git a/src/x11_platform.h b/src/x11_platform.h index 37946a29..30c73a88 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -238,6 +238,7 @@ typedef struct _GLFWlibraryX11 double restoreCursorPosX, restoreCursorPosY; // The window whose disabled cursor mode is active _GLFWwindow* disabledCursorWindow; + int emptyEventPipe[2]; // Window manager atoms Atom NET_SUPPORTED; diff --git a/src/x11_window.c b/src/x11_window.c index 6de0bcd4..9f08fc6d 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -114,8 +114,12 @@ static GLFWbool waitForX11Event(double* timeout) // static GLFWbool waitForAnyEvent(double* timeout) { - nfds_t count = 1; - struct pollfd fds[2] = { { ConnectionNumber(_glfw.x11.display), POLLIN } }; + nfds_t count = 2; + struct pollfd fds[3] = + { + { ConnectionNumber(_glfw.x11.display), POLLIN }, + { _glfw.x11.emptyEventPipe[0], POLLIN } + }; #if defined(__linux__) if (_glfw.linjs.inotify > 0) @@ -137,6 +141,32 @@ static GLFWbool waitForAnyEvent(double* timeout) return GLFW_TRUE; } +// Writes a byte to the empty event pipe +// +static void writeEmptyEvent(void) +{ + for (;;) + { + const char byte = 0; + const int result = write(_glfw.x11.emptyEventPipe[1], &byte, 1); + if (result == 1 || (result == -1 && errno != EINTR)) + break; + } +} + +// Drains available data from the empty event pipe +// +static void drainEmptyEvents(void) +{ + for (;;) + { + char dummy[64]; + const int result = read(_glfw.x11.emptyEventPipe[0], dummy, sizeof(dummy)); + if (result == -1 && errno != EINTR) + break; + } +} + // Waits until a VisibilityNotify event arrives for the specified window or the // timeout period elapses (ICCCM section 4.2.2) // @@ -2782,6 +2812,8 @@ GLFWbool _glfwPlatformRawMouseMotionSupported(void) void _glfwPlatformPollEvents(void) { + drainEmptyEvents(); + #if defined(__linux__) _glfwDetectJoystickConnectionLinux(); #endif @@ -2826,13 +2858,7 @@ void _glfwPlatformWaitEventsTimeout(double timeout) void _glfwPlatformPostEmptyEvent(void) { - XEvent event = { ClientMessage }; - event.xclient.window = _glfw.x11.helperWindowHandle; - event.xclient.format = 32; // Data is 32-bit longs - event.xclient.message_type = _glfw.x11.NULL_; - - XSendEvent(_glfw.x11.display, _glfw.x11.helperWindowHandle, False, 0, &event); - XFlush(_glfw.x11.display); + writeEmptyEvent(); } void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) From 9f73e9afa34b1c0902023d5d80be1c0f954135e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 25 Feb 2022 15:05:59 +0100 Subject: [PATCH 12/30] X11: Use lower-latency poll where available This uses ppoll for waiting on file descriptors with a timeout, where that function has been available a while. On NetBSD, which will be getting ppoll in the next release, the equivalent pollts is used. This commit is based on work by OlivierSohn and kovidgoyal. Related to #1281 Related to #1285 (cherry picked from commit 84b0923fe61a12bd0bf9241da102053b906265bd) --- src/x11_window.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/x11_window.c b/src/x11_window.c index 9f08fc6d..a86a8ff1 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -27,12 +27,18 @@ // It is fine to use C99 in this file because it will not be built with VS //======================================================================== +#if defined(__linux__) + #define _GNU_SOURCE +#endif + #include "internal.h" #include #include #include +#include +#include #include #include @@ -64,10 +70,22 @@ static GLFWbool waitForData(struct pollfd* fds, nfds_t count, double* timeout) { if (timeout) { - const int milliseconds = (int) (*timeout * 1e3); const uint64_t base = _glfwPlatformGetTimerValue(); +#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) + const time_t seconds = (time_t) *timeout; + const long nanoseconds = (long) ((*timeout - seconds) * 1e9); + const struct timespec ts = { seconds, nanoseconds }; + const int result = ppoll(fds, count, &ts, NULL); +#elif defined(__NetBSD__) + const time_t seconds = (time_t) *timeout; + const long nanoseconds = (long) ((*timeout - seconds) * 1e9); + const struct timespec ts = { seconds, nanoseconds }; + const int result = pollts(fds, count, &ts, NULL); +#else + const int milliseconds = (int) (*timeout * 1e3); const int result = poll(fds, count, milliseconds); +#endif const int error = errno; // clock_gettime may overwrite our error *timeout -= (_glfwPlatformGetTimerValue() - base) / From 7302a8f5206d0e8aea6b8984da4306b32f469bb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 3 Mar 2022 16:23:00 +0100 Subject: [PATCH 13/30] Wayland: Fix potential incomplete display flushing The flushing of a Wayland display may need to be done in several steps, signalled by it failing with EAGAIN. (cherry picked from commit 3c2913dcb96eed94742826f4276282f4e4a7b01e) --- src/wl_window.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/wl_window.c b/src/wl_window.c index 33623627..51747702 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -831,6 +831,25 @@ static void incrementCursorImage(_GLFWwindow* window) } } +static GLFWbool flushDisplay(void) +{ + while (wl_display_flush(_glfw.wl.display) == -1) + { + if (errno != EAGAIN) + return GLFW_FALSE; + + struct pollfd fd = { wl_display_get_fd(_glfw.wl.display), POLLOUT }; + + while (poll(&fd, 1, -1) == -1) + { + if (errno != EINTR && errno != EAGAIN) + return GLFW_FALSE; + } + } + + return GLFW_TRUE; +} + static void handleEvents(int timeout) { struct pollfd fds[] = @@ -845,7 +864,7 @@ static void handleEvents(int timeout) // If an error other than EAGAIN happens, we have likely been disconnected // from the Wayland session; try to handle that the best we can. - if (wl_display_flush(_glfw.wl.display) < 0 && errno != EAGAIN) + if (!flushDisplay()) { _GLFWwindow* window = _glfw.windowListHead; while (window) From 9dd3f25d6d31af59b2c286b792b684c1cf95e93b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 3 Mar 2022 16:28:44 +0100 Subject: [PATCH 14/30] Wayland: Cancel display fd read before callbacks Cancel the prepared-to-read state on the calling thread before starting to call back to user code. Emitting close requests here is not a good choice but that is for a future commit to address. (cherry picked from commit 203a7c59d25058f7dfd0c7a3b5062de0b87a8517) --- src/wl_window.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wl_window.c b/src/wl_window.c index 51747702..56f74c4d 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -866,6 +866,8 @@ static void handleEvents(int timeout) // from the Wayland session; try to handle that the best we can. if (!flushDisplay()) { + wl_display_cancel_read(_glfw.wl.display); + _GLFWwindow* window = _glfw.windowListHead; while (window) { @@ -873,7 +875,6 @@ static void handleEvents(int timeout) window = window->next; } - wl_display_cancel_read(_glfw.wl.display); return; } From b0af476799adc34805768e25581fffdcd3ad9235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 13 Mar 2022 16:25:19 +0100 Subject: [PATCH 15/30] Wayland: Adopt the poll wrapper from X11 This is adapted to 3.3-stable from bb9d699ae66b2bdc8718995ba13c57c9c8e59602. --- src/wl_window.c | 63 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index 56f74c4d..2f6d17f2 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -39,7 +39,8 @@ #include #include #include - +#include +#include static void shellSurfaceHandlePing(void* data, struct wl_shell_surface* shellSurface, @@ -248,6 +249,53 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image) return buffer; } +// Wait for data to arrive on any of the specified file descriptors +// +static GLFWbool waitForData(struct pollfd* fds, nfds_t count, double* timeout) +{ + for (;;) + { + if (timeout) + { + const uint64_t base = _glfwPlatformGetTimerValue(); + +#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) + const time_t seconds = (time_t) *timeout; + const long nanoseconds = (long) ((*timeout - seconds) * 1e9); + const struct timespec ts = { seconds, nanoseconds }; + const int result = ppoll(fds, count, &ts, NULL); +#elif defined(__NetBSD__) + const time_t seconds = (time_t) *timeout; + const long nanoseconds = (long) ((*timeout - seconds) * 1e9); + const struct timespec ts = { seconds, nanoseconds }; + const int result = pollts(fds, count, &ts, NULL); +#else + const int milliseconds = (int) (*timeout * 1e3); + const int result = poll(fds, count, milliseconds); +#endif + const int error = errno; // clock_gettime may overwrite our error + + *timeout -= (_glfwPlatformGetTimerValue() - base) / + (double) _glfwPlatformGetTimerFrequency(); + + if (result > 0) + return GLFW_TRUE; + else if (result == -1 && error != EINTR && error != EAGAIN) + return GLFW_FALSE; + else if (*timeout <= 0.0) + return GLFW_FALSE; + } + else + { + const int result = poll(fds, count, -1); + if (result > 0) + return GLFW_TRUE; + else if (result == -1 && errno != EINTR && errno != EAGAIN) + return GLFW_FALSE; + } + } +} + static void createDecoration(_GLFWdecorationWayland* decoration, struct wl_surface* parent, struct wl_buffer* buffer, GLFWbool opaque, @@ -850,7 +898,7 @@ static GLFWbool flushDisplay(void) return GLFW_TRUE; } -static void handleEvents(int timeout) +static void handleEvents(double* timeout) { struct pollfd fds[] = { @@ -878,7 +926,7 @@ static void handleEvents(int timeout) return; } - if (poll(fds, 3, timeout) > 0) + if (waitForData(fds, 3, timeout) > 0) { if (fds[0].revents & POLLIN) { @@ -1328,17 +1376,18 @@ GLFWbool _glfwPlatformRawMouseMotionSupported(void) void _glfwPlatformPollEvents(void) { - handleEvents(0); + double timeout = 0.0; + handleEvents(&timeout); } void _glfwPlatformWaitEvents(void) { - handleEvents(-1); + handleEvents(NULL); } void _glfwPlatformWaitEventsTimeout(double timeout) { - handleEvents((int) (timeout * 1e3)); + handleEvents(&timeout); } void _glfwPlatformPostEmptyEvent(void) @@ -1815,7 +1864,7 @@ const char* _glfwPlatformGetClipboardString(void) close(fds[1]); // XXX: this is a huge hack, this function shouldn’t be synchronous! - handleEvents(-1); + handleEvents(NULL); while (1) { From 499a5a7917accece4a9a3590842ccb6067fd8913 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 3 Mar 2022 21:40:00 +0100 Subject: [PATCH 16/30] Formatting (cherry picked from commit 7ce1f3e1cf5eb86a17f0c739cfdbcf4094e8e395) --- src/wl_window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wl_window.c b/src/wl_window.c index 2f6d17f2..2e3c6843 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -1866,7 +1866,7 @@ const char* _glfwPlatformGetClipboardString(void) // XXX: this is a huge hack, this function shouldn’t be synchronous! handleEvents(NULL); - while (1) + for (;;) { // Grow the clipboard if we need to paste something bigger, there is no // shrink operation yet. From eac18b9324d008f8d30ccfec6e28307e0f4f8ba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 3 Mar 2022 21:46:50 +0100 Subject: [PATCH 17/30] Wayland: Fix glfwPostEmptyEvent not always working The display sync requests in glfwPostEmptyEvent could just accumulate as the display was never flushed on secondary threads. This adds a proper flush after each sync request. Fixes #1520 Closes #1521 (cherry picked from commit a32cbf6d4febde6343167f19529b8bde8966670d) --- README.md | 1 + src/wl_window.c | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index f0c1ac02..22d97bde 100644 --- a/README.md +++ b/README.md @@ -141,6 +141,7 @@ information on what to include when reporting a bug. - [Wayland] Bugfix: Full screen window creation did not ignore `GLFW_VISIBLE` - [Wayland] Bugfix: Some keys were reported as wrong key or `GLFW_KEY_UNKNOWN` - [Wayland] Bugfix: Text input did not repeat along with key repeat + - [Wayland] Bugfix: `glfwPostEmptyEvent` sometimes had no effect (#1520,#1521) - [GLX] Bugfix: Context creation failed if GLX 1.4 was not exported by GLX library diff --git a/src/wl_window.c b/src/wl_window.c index 2e3c6843..2b8614dd 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -1393,6 +1393,7 @@ void _glfwPlatformWaitEventsTimeout(double timeout) void _glfwPlatformPostEmptyEvent(void) { wl_display_sync(_glfw.wl.display); + flushDisplay(); } void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) From 9cfd4c49b0cb797bdd7c167c3836ac5cb4b5fe15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 3 Mar 2022 22:41:36 +0100 Subject: [PATCH 18/30] Wayland: Improve event processing with timeout If the polling was interrupted by a signal or by incomplete or unrelated data on any file descriptor, handleEvents could return before the full timeout had elapsed. This retries the Wayland prepare-to-read and poll until the full timeout has elapsed or until any event was processed. Unfortunately, due to how the Wayland client API is designed, this also includes the delete_id for the frame callback created by eglSwapBuffers. This means glfwWaitEvents* are still not fully functional on Wayland. See #1911 for more details. (cherry picked from commit 71742d9a27a88d898ea13fd415fae1650dc2772e) --- src/wl_window.c | 47 +++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index 2b8614dd..0b78e34f 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -900,6 +900,7 @@ static GLFWbool flushDisplay(void) static void handleEvents(double* timeout) { + GLFWbool event = GLFW_FALSE; struct pollfd fds[] = { { wl_display_get_fd(_glfw.wl.display), POLLIN }, @@ -907,31 +908,38 @@ static void handleEvents(double* timeout) { _glfw.wl.cursorTimerfd, POLLIN }, }; - while (wl_display_prepare_read(_glfw.wl.display) != 0) - wl_display_dispatch_pending(_glfw.wl.display); - - // If an error other than EAGAIN happens, we have likely been disconnected - // from the Wayland session; try to handle that the best we can. - if (!flushDisplay()) + while (!event) { - wl_display_cancel_read(_glfw.wl.display); + while (wl_display_prepare_read(_glfw.wl.display) != 0) + wl_display_dispatch_pending(_glfw.wl.display); - _GLFWwindow* window = _glfw.windowListHead; - while (window) + // If an error other than EAGAIN happens, we have likely been disconnected + // from the Wayland session; try to handle that the best we can. + if (!flushDisplay()) { - _glfwInputWindowCloseRequest(window); - window = window->next; + wl_display_cancel_read(_glfw.wl.display); + + _GLFWwindow* window = _glfw.windowListHead; + while (window) + { + _glfwInputWindowCloseRequest(window); + window = window->next; + } + + return; } - return; - } + if (!waitForData(fds, 3, timeout)) + { + wl_display_cancel_read(_glfw.wl.display); + return; + } - if (waitForData(fds, 3, timeout) > 0) - { if (fds[0].revents & POLLIN) { wl_display_read_events(_glfw.wl.display); - wl_display_dispatch_pending(_glfw.wl.display); + if (wl_display_dispatch_pending(_glfw.wl.display) > 0) + event = GLFW_TRUE; } else wl_display_cancel_read(_glfw.wl.display); @@ -952,6 +960,8 @@ static void handleEvents(double* timeout) _glfwInputTextWayland(_glfw.wl.keyboardFocus, _glfw.wl.keyboardLastScancode); } + + event = GLFW_TRUE; } } @@ -960,11 +970,12 @@ static void handleEvents(double* timeout) uint64_t repeats; if (read(_glfw.wl.cursorTimerfd, &repeats, sizeof(repeats)) == 8) + { incrementCursorImage(_glfw.wl.pointerFocus); + event = GLFW_TRUE; + } } } - else - wl_display_cancel_read(_glfw.wl.display); } // Translates a GLFW standard cursor to a theme cursor name From 1813cc0af5061279863712db862f0b1b4e89d106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 3 Mar 2022 23:15:47 +0100 Subject: [PATCH 19/30] Update version of VS used on windows-latest (cherry picked from commit 1e0c3bca7f6da896828e00f3da606d5e306c3034) --- .github/workflows/build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 014498ca..0b09e0f3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -96,8 +96,8 @@ jobs: - name: Build shared library run: cmake --build build-shared --parallel - build-windows-win32-vs2019: - name: Win32 (Windows, VS2019) + build-windows-win32-vs2022: + name: Win32 (Windows, VS2022) runs-on: windows-latest env: CFLAGS: /WX @@ -105,12 +105,12 @@ jobs: - uses: actions/checkout@v2 - name: Configure static library - run: cmake -S . -B build-static -G "Visual Studio 16 2019" + run: cmake -S . -B build-static -G "Visual Studio 17 2022" - name: Build static library run: cmake --build build-static --parallel - name: Configure shared library - run: cmake -S . -B build-shared -G "Visual Studio 16 2019" -D BUILD_SHARED_LIBS=ON + run: cmake -S . -B build-shared -G "Visual Studio 17 2022" -D BUILD_SHARED_LIBS=ON - name: Build shared library run: cmake --build build-shared --parallel From 6659a80040f1defad6a34a6cae59b70234eda139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 23 Feb 2022 18:47:30 +0100 Subject: [PATCH 20/30] X11: Fix sonames for loaded libraries on NetBSD The NetBSD sonames for X11 and related libraries is more stable than on OpenBSD but the version numbers are still bumped more often than their Linux counterparts, even excluding the one-time version bump across all X11 related libraries. This commit moves to using version-less sonames for X11 and related libraries on NetBSD, which will hopefully be more forward-compatible than hard-coding NetBSD-specific sonames. This may not be the correct long-term solution but it runs now. Binaries also appear to need an LD_LIBRARY_PATH or rpath entry of /usr/X11R7/lib in order for the libraries to be found by dlopen. Tested on NetBSD 9.2. (cherry picked from commit d78b0a4ead17e30182761b38dbbdfb88b037287b) --- README.md | 1 + src/egl_context.c | 8 ++++---- src/glx_context.c | 2 +- src/osmesa_context.c | 2 +- src/vulkan.c | 2 +- src/x11_init.c | 14 +++++++------- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 22d97bde..0753a770 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,7 @@ information on what to include when reporting a bug. - [X11] Bugfix: `glfwWaitEvents*` did not continue for joystick events - [X11] Bugfix: `glfwPostEmptyEvent` could be ignored due to race condition (#379,#1281,#1285,#2033) + - [X11] Bugfix: Dynamic loading on NetBSD failed due to soname differences - [Wayland] Added support for key names via xkbcommon - [Wayland] Bugfix: Key repeat could lead to a race condition (#1710) - [Wayland] Bugfix: Activating a window would emit two input focus events diff --git a/src/egl_context.c b/src/egl_context.c index de91abbb..58d9557b 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -320,7 +320,7 @@ GLFWbool _glfwInitEGL(void) "libEGL.dylib", #elif defined(__CYGWIN__) "libEGL-1.so", -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) "libEGL.so", #else "libEGL.so.1", @@ -643,7 +643,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, "libGLES_CM.dll", #elif defined(_GLFW_COCOA) "libGLESv1_CM.dylib", -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) "libGLESv1_CM.so", #else "libGLESv1_CM.so.1", @@ -662,7 +662,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, "libGLESv2.dylib", #elif defined(__CYGWIN__) "libGLESv2-2.so", -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) "libGLESv2.so", #else "libGLESv2.so.2", @@ -675,7 +675,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, _GLFW_OPENGL_LIBRARY, #elif defined(_GLFW_WIN32) #elif defined(_GLFW_COCOA) -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) "libGL.so", #else "libGL.so.1", diff --git a/src/glx_context.c b/src/glx_context.c index 06bc080e..1b1b3f90 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -260,7 +260,7 @@ GLFWbool _glfwInitGLX(void) _GLFW_GLX_LIBRARY, #elif defined(__CYGWIN__) "libGL-1.so", -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) "libGL.so", #else "libGL.so.1", diff --git a/src/osmesa_context.c b/src/osmesa_context.c index c73ff709..4072728b 100644 --- a/src/osmesa_context.c +++ b/src/osmesa_context.c @@ -124,7 +124,7 @@ GLFWbool _glfwInitOSMesa(void) "libOSMesa.8.dylib", #elif defined(__CYGWIN__) "libOSMesa-8.so", -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) "libOSMesa.so", #else "libOSMesa.so.8", diff --git a/src/vulkan.c b/src/vulkan.c index dea7e1d6..1b96579c 100644 --- a/src/vulkan.c +++ b/src/vulkan.c @@ -59,7 +59,7 @@ GLFWbool _glfwInitVulkan(int mode) _glfw.vk.handle = _glfw_dlopen("libvulkan.1.dylib"); if (!_glfw.vk.handle) _glfw.vk.handle = _glfwLoadLocalVulkanLoaderNS(); -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) _glfw.vk.handle = _glfw_dlopen("libvulkan.so"); #else _glfw.vk.handle = _glfw_dlopen("libvulkan.so.1"); diff --git a/src/x11_init.c b/src/x11_init.c index 5e6071f5..4fd9587e 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -571,7 +571,7 @@ static void detectEWMH(void) // static GLFWbool initExtensions(void) { -#if defined(__OpenBSD__) +#if defined(__OpenBSD__) || defined(__NetBSD__) _glfw.x11.vidmode.handle = _glfw_dlopen("libXxf86vm.so"); #else _glfw.x11.vidmode.handle = _glfw_dlopen("libXxf86vm.so.1"); @@ -595,7 +595,7 @@ static GLFWbool initExtensions(void) #if defined(__CYGWIN__) _glfw.x11.xi.handle = _glfw_dlopen("libXi-6.so"); -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) _glfw.x11.xi.handle = _glfw_dlopen("libXi.so"); #else _glfw.x11.xi.handle = _glfw_dlopen("libXi.so.6"); @@ -627,7 +627,7 @@ static GLFWbool initExtensions(void) #if defined(__CYGWIN__) _glfw.x11.randr.handle = _glfw_dlopen("libXrandr-2.so"); -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) _glfw.x11.randr.handle = _glfw_dlopen("libXrandr.so"); #else _glfw.x11.randr.handle = _glfw_dlopen("libXrandr.so.2"); @@ -721,7 +721,7 @@ static GLFWbool initExtensions(void) #if defined(__CYGWIN__) _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor-1.so"); -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor.so"); #else _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor.so.1"); @@ -738,7 +738,7 @@ static GLFWbool initExtensions(void) #if defined(__CYGWIN__) _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama-1.so"); -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama.so"); #else _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama.so.1"); @@ -791,7 +791,7 @@ static GLFWbool initExtensions(void) #if defined(__CYGWIN__) _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb-1.so"); -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb.so"); #else _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb.so.1"); @@ -804,7 +804,7 @@ static GLFWbool initExtensions(void) #if defined(__CYGWIN__) _glfw.x11.xrender.handle = _glfw_dlopen("libXrender-1.so"); -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) _glfw.x11.xrender.handle = _glfw_dlopen("libXrender.so"); #else _glfw.x11.xrender.handle = _glfw_dlopen("libXrender.so.1"); From 35a65361ffb937188aebfda5e00c39c108ce9797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 4 Mar 2022 13:37:38 +0100 Subject: [PATCH 21/30] POSIX: Fix undeclared function warning on Cygwin (cherry picked from commit adc202d2c3182ca6ad8344624941e56d8e0bc493) --- src/x11_window.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/x11_window.c b/src/x11_window.c index a86a8ff1..bf923fe6 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -27,9 +27,7 @@ // It is fine to use C99 in this file because it will not be built with VS //======================================================================== -#if defined(__linux__) - #define _GNU_SOURCE -#endif +#define _GNU_SOURCE #include "internal.h" From d9512b694b2bd4c62213f2e2ce1b81ece817d5ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 7 Mar 2022 18:14:16 +0100 Subject: [PATCH 22/30] Win32: Fix rect of undecorated maximized windows A window created maximized and undecorated would cover the whole monitor Windows placed it on instead of just that monitor's workarea. This commit adjusts the maximized rect to cover just the workarea, similar to how undecorated windows that become maximized are handled during WM_GETMINMAXINFO. Fixes #1806 (cherry picked from commit a730acf8e50e7efa70e79e42c511a97f27c97e4d) --- README.md | 2 ++ src/win32_window.c | 29 ++++++++++++++++++++++++----- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0753a770..0a1d5f69 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,8 @@ information on what to include when reporting a bug. ## Changelog + - [Win32] Bugfix: A window created maximized and undecorated would cover the whole + monitor (#1806) - [Cocoa] Bugfix: `kUTTypeURL` was deprecated in macOS 12.0 (#2003) - [X11] Bugfix: Dynamic loading on OpenBSD failed due to soname differences - [X11] Bugfix: Waiting for events would fail if file descriptor was too large diff --git a/src/win32_window.c b/src/win32_window.c index d6fc9d07..da6ac717 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1285,18 +1285,22 @@ static int createNativeWindow(_GLFWwindow* window, window->win32.scaleToMonitor = wndconfig->scaleToMonitor; - // Adjust window rect to account for DPI scaling of the window frame and - // (if enabled) DPI scaling of the content area - // This cannot be done until we know what monitor the window was placed on if (!window->monitor) { RECT rect = { 0, 0, wndconfig->width, wndconfig->height }; WINDOWPLACEMENT wp = { sizeof(wp) }; + const HMONITOR mh = MonitorFromWindow(window->win32.handle, + MONITOR_DEFAULTTONEAREST); + + // Adjust window rect to account for DPI scaling of the window frame and + // (if enabled) DPI scaling of the content area + // This cannot be done until we know what monitor the window was placed on + // Only update the restored window rect as the window may be maximized if (wndconfig->scaleToMonitor) { float xscale, yscale; - _glfwPlatformGetWindowContentScale(window, &xscale, &yscale); + _glfwGetMonitorContentScaleWin32(mh, &xscale, &yscale); if (xscale > 0.f && yscale > 0.f) { @@ -1316,11 +1320,26 @@ static int createNativeWindow(_GLFWwindow* window, else AdjustWindowRectEx(&rect, style, FALSE, exStyle); - // Only update the restored window rect as the window may be maximized GetWindowPlacement(window->win32.handle, &wp); wp.rcNormalPosition = rect; wp.showCmd = SW_HIDE; SetWindowPlacement(window->win32.handle, &wp); + + // Adjust rect of maximized undecorated window, because by default Windows will + // make such a window cover the whole monitor instead of its workarea + + if (wndconfig->maximized && !wndconfig->decorated) + { + MONITORINFO mi = { sizeof(mi) }; + GetMonitorInfo(mh, &mi); + + SetWindowPos(window->win32.handle, HWND_TOP, + mi.rcWork.left, + mi.rcWork.top, + mi.rcWork.right - mi.rcWork.left, + mi.rcWork.bottom - mi.rcWork.top, + SWP_NOACTIVATE | SWP_NOZORDER); + } } DragAcceptFiles(window->win32.handle, TRUE); From 85a3bf40fb72b98a6886c9454b09014b6efe12bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 7 Mar 2022 19:19:31 +0100 Subject: [PATCH 23/30] Win32: Fix scale fixup losing initial position The window content scale correction at creation overwrote the inital, more pleasant placement of the window by CW_USEDEFAULT, if the window was created with GLFW_MAXIMIZED set. This is because the translation to screen coordinates was done using the current position, not the position from the restored window rect. (cherry picked from commit 367d06deafb00057850796abc02489756a7c6c18) --- README.md | 2 ++ src/win32_window.c | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0a1d5f69..d0f46849 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,8 @@ information on what to include when reporting a bug. - [Win32] Bugfix: A window created maximized and undecorated would cover the whole monitor (#1806) + - [Win32] Bugfix: The default restored window position was lost when creating a maximized + window - [Cocoa] Bugfix: `kUTTypeURL` was deprecated in macOS 12.0 (#2003) - [X11] Bugfix: Dynamic loading on OpenBSD failed due to soname differences - [X11] Bugfix: Waiting for events would fail if file descriptor was too large diff --git a/src/win32_window.c b/src/win32_window.c index da6ac717..a68b3c8b 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1309,9 +1309,6 @@ static int createNativeWindow(_GLFWwindow* window, } } - ClientToScreen(window->win32.handle, (POINT*) &rect.left); - ClientToScreen(window->win32.handle, (POINT*) &rect.right); - if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) { AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, @@ -1321,6 +1318,10 @@ static int createNativeWindow(_GLFWwindow* window, AdjustWindowRectEx(&rect, style, FALSE, exStyle); GetWindowPlacement(window->win32.handle, &wp); + OffsetRect(&rect, + wp.rcNormalPosition.left - rect.left, + wp.rcNormalPosition.top - rect.top); + wp.rcNormalPosition = rect; wp.showCmd = SW_HIDE; SetWindowPlacement(window->win32.handle, &wp); From 8d084267255efa939fc1e75ae3b266997d8537a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 10 Mar 2022 19:14:49 +0100 Subject: [PATCH 24/30] Fix dependency list for X11 on Cygwin (cherry picked from commit 1eef3a363e2f64718c82122c5d48bff44c4b2e5d) --- docs/compile.dox | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/compile.dox b/docs/compile.dox index d618d024..ec458f4f 100644 --- a/docs/compile.dox +++ b/docs/compile.dox @@ -68,8 +68,10 @@ install the `xorgproto` package. pkg install xorgproto @endcode -On Cygwin the `xorgproto` package in the Devel section of the GUI installer will -install the headers and other development related files for all of X11. +On Cygwin the `libXcursor-devel`, `libXi-devel`, `libXinerama-devel`, +`libXrandr-devel` and `libXrender-devel` packages in the Libs section of the GUI +installer will install all the headers and other development related files GLFW +requires for X11. Once you have the required depdendencies, move on to @ref compile_generate. From 541b151cff6b5c243e0c6fa3ed64b3daaf89615f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 8 Mar 2022 23:00:47 +0100 Subject: [PATCH 25/30] Win32: Fix maximization showing a hidden window The normal way of maximizing a window also makes it visible. This implements window maximization manually for when the window passed to glfwMaximizeWindow is hidden. This will very likely not be forward-compatible and should be replaced. (cherry picked from commit 723f3eb40db27a26c846f0d38ee24af3365ffa96) --- README.md | 1 + src/win32_init.c | 2 ++ src/win32_platform.h | 3 +++ src/win32_window.c | 58 +++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 63 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d0f46849..2bd4b63a 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,7 @@ information on what to include when reporting a bug. monitor (#1806) - [Win32] Bugfix: The default restored window position was lost when creating a maximized window + - [Win32] Bugfix: `glfwMaximizeWindow` would make a hidden window visible - [Cocoa] Bugfix: `kUTTypeURL` was deprecated in macOS 12.0 (#2003) - [X11] Bugfix: Dynamic loading on OpenBSD failed due to soname differences - [X11] Bugfix: Waiting for events would fail if file descriptor was too large diff --git a/src/win32_init.c b/src/win32_init.c index 40eb795f..cb6e8222 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -92,6 +92,8 @@ static GLFWbool loadLibraries(void) GetProcAddress(_glfw.win32.user32.instance, "GetDpiForWindow"); _glfw.win32.user32.AdjustWindowRectExForDpi_ = (PFN_AdjustWindowRectExForDpi) GetProcAddress(_glfw.win32.user32.instance, "AdjustWindowRectExForDpi"); + _glfw.win32.user32.GetSystemMetricsForDpi_ = (PFN_GetSystemMetricsForDpi) + GetProcAddress(_glfw.win32.user32.instance, "GetSystemMetricsForDpi"); _glfw.win32.dinput8.instance = LoadLibraryA("dinput8.dll"); if (_glfw.win32.dinput8.instance) diff --git a/src/win32_platform.h b/src/win32_platform.h index b964e135..2e947ecf 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -235,12 +235,14 @@ typedef BOOL (WINAPI * PFN_EnableNonClientDpiScaling)(HWND); typedef BOOL (WINAPI * PFN_SetProcessDpiAwarenessContext)(HANDLE); typedef UINT (WINAPI * PFN_GetDpiForWindow)(HWND); typedef BOOL (WINAPI * PFN_AdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT); +typedef int (WINAPI * PFN_GetSystemMetricsForDpi)(int,UINT); #define SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware_ #define ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx_ #define EnableNonClientDpiScaling _glfw.win32.user32.EnableNonClientDpiScaling_ #define SetProcessDpiAwarenessContext _glfw.win32.user32.SetProcessDpiAwarenessContext_ #define GetDpiForWindow _glfw.win32.user32.GetDpiForWindow_ #define AdjustWindowRectExForDpi _glfw.win32.user32.AdjustWindowRectExForDpi_ +#define GetSystemMetricsForDpi _glfw.win32.user32.GetSystemMetricsForDpi_ // dwmapi.dll function pointer typedefs typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*); @@ -366,6 +368,7 @@ typedef struct _GLFWlibraryWin32 PFN_SetProcessDpiAwarenessContext SetProcessDpiAwarenessContext_; PFN_GetDpiForWindow GetDpiForWindow_; PFN_AdjustWindowRectExForDpi AdjustWindowRectExForDpi_; + PFN_GetSystemMetricsForDpi GetSystemMetricsForDpi_; } user32; struct { diff --git a/src/win32_window.c b/src/win32_window.c index a68b3c8b..c124ab23 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -489,6 +489,59 @@ static void releaseMonitor(_GLFWwindow* window) _glfwRestoreVideoModeWin32(window->monitor); } +// Manually maximize the window, for when SW_MAXIMIZE cannot be used +// +static void maximizeWindowManually(_GLFWwindow* window) +{ + RECT rect; + DWORD style; + MONITORINFO mi = { sizeof(mi) }; + + GetMonitorInfo(MonitorFromWindow(window->win32.handle, + MONITOR_DEFAULTTONEAREST), &mi); + + rect = mi.rcWork; + + if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE) + { + if (rect.right - rect.left > window->maxwidth) + rect.right = rect.left + window->maxwidth; + if (rect.bottom - rect.top > window->maxheight) + rect.bottom = rect.top + window->maxheight; + } + + style = GetWindowLongW(window->win32.handle, GWL_STYLE); + style |= WS_MAXIMIZE; + SetWindowLongW(window->win32.handle, GWL_STYLE, style); + + if (window->decorated) + { + const DWORD exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); + + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + { + const UINT dpi = GetDpiForWindow(window->win32.handle); + AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, dpi); + OffsetRect(&rect, 0, GetSystemMetricsForDpi(SM_CYCAPTION, dpi)); + } + else + { + AdjustWindowRectEx(&rect, style, FALSE, exStyle); + OffsetRect(&rect, 0, GetSystemMetrics(SM_CYCAPTION)); + } + + if (rect.bottom > mi.rcWork.bottom) + rect.bottom = mi.rcWork.bottom; + } + + SetWindowPos(window->win32.handle, HWND_TOP, + rect.left, + rect.top, + rect.right - rect.left, + rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED); +} + // Window callback function (handles window messages) // static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, @@ -1692,7 +1745,10 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window) void _glfwPlatformMaximizeWindow(_GLFWwindow* window) { - ShowWindow(window->win32.handle, SW_MAXIMIZE); + if (IsWindowVisible(window->win32.handle)) + ShowWindow(window->win32.handle, SW_MAXIMIZE); + else + maximizeWindowManually(window); } void _glfwPlatformShowWindow(_GLFWwindow* window) From d1269c1b7d81f1b04366e4684632dd61de612253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 8 Mar 2022 23:45:53 +0100 Subject: [PATCH 26/30] Win32: Fix calls to encoding compatibility macros Calls to Unicode specific functions should be made explicit. (cherry picked from commit 8ff9ed92b446831e76b434c601b3d1b0d4220c82) --- src/win32_init.c | 2 +- src/win32_joystick.c | 2 +- src/win32_monitor.c | 2 +- src/win32_window.c | 26 +++++++++++++------------- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/win32_init.c b/src/win32_init.c index cb6e8222..c1bdd5a9 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -486,7 +486,7 @@ void _glfwUpdateKeyNamesWin32(void) vk = vks[key - GLFW_KEY_KP_0]; } else - vk = MapVirtualKey(scancode, MAPVK_VSC_TO_VK); + vk = MapVirtualKeyW(scancode, MAPVK_VSC_TO_VK); length = ToUnicode(vk, scancode, state, chars, sizeof(chars) / sizeof(WCHAR), diff --git a/src/win32_joystick.c b/src/win32_joystick.c index 62ad7a53..f54d5704 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -497,7 +497,7 @@ void _glfwInitJoysticksWin32(void) { if (_glfw.win32.dinput8.instance) { - if (FAILED(DirectInput8Create(GetModuleHandle(NULL), + if (FAILED(DirectInput8Create(GetModuleHandleW(NULL), DIRECTINPUT_VERSION, &IID_IDirectInput8W, (void**) &_glfw.win32.dinput8.api, diff --git a/src/win32_monitor.c b/src/win32_monitor.c index 3cb33933..67337fd8 100644 --- a/src/win32_monitor.c +++ b/src/win32_monitor.c @@ -382,7 +382,7 @@ void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* width, int* height) { MONITORINFO mi = { sizeof(mi) }; - GetMonitorInfo(monitor->win32.handle, &mi); + GetMonitorInfoW(monitor->win32.handle, &mi); if (xpos) *xpos = mi.rcWork.left; diff --git a/src/win32_window.c b/src/win32_window.c index c124ab23..12f5900b 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -435,7 +435,7 @@ static int getKeyMods(void) static void fitToMonitor(_GLFWwindow* window) { MONITORINFO mi = { sizeof(mi) }; - GetMonitorInfo(window->monitor->win32.handle, &mi); + GetMonitorInfoW(window->monitor->win32.handle, &mi); SetWindowPos(window->win32.handle, HWND_TOPMOST, mi.rcMonitor.left, mi.rcMonitor.top, @@ -456,8 +456,8 @@ static void acquireMonitor(_GLFWwindow* window) // the OpenGL ICD switches to page flipping if (IsWindowsXPOrGreater()) { - SystemParametersInfo(SPI_GETMOUSETRAILS, 0, &_glfw.win32.mouseTrailSize, 0); - SystemParametersInfo(SPI_SETMOUSETRAILS, 0, 0, 0); + SystemParametersInfoW(SPI_GETMOUSETRAILS, 0, &_glfw.win32.mouseTrailSize, 0); + SystemParametersInfoW(SPI_SETMOUSETRAILS, 0, 0, 0); } } @@ -482,7 +482,7 @@ static void releaseMonitor(_GLFWwindow* window) // HACK: Restore mouse trail length saved in acquireMonitor if (IsWindowsXPOrGreater()) - SystemParametersInfo(SPI_SETMOUSETRAILS, _glfw.win32.mouseTrailSize, 0, 0); + SystemParametersInfoW(SPI_SETMOUSETRAILS, _glfw.win32.mouseTrailSize, 0, 0); } _glfwInputMonitorWindow(window->monitor, NULL); @@ -497,8 +497,8 @@ static void maximizeWindowManually(_GLFWwindow* window) DWORD style; MONITORINFO mi = { sizeof(mi) }; - GetMonitorInfo(MonitorFromWindow(window->win32.handle, - MONITOR_DEFAULTTONEAREST), &mi); + GetMonitorInfoW(MonitorFromWindow(window->win32.handle, + MONITOR_DEFAULTTONEAREST), &mi); rect = mi.rcWork; @@ -1120,7 +1120,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, ZeroMemory(&mi, sizeof(mi)); mi.cbSize = sizeof(mi); - GetMonitorInfo(mh, &mi); + GetMonitorInfoW(mh, &mi); mmi->ptMaxPosition.x = mi.rcWork.left - mi.rcMonitor.left; mmi->ptMaxPosition.y = mi.rcWork.top - mi.rcMonitor.top; @@ -1385,7 +1385,7 @@ static int createNativeWindow(_GLFWwindow* window, if (wndconfig->maximized && !wndconfig->decorated) { MONITORINFO mi = { sizeof(mi) }; - GetMonitorInfo(mh, &mi); + GetMonitorInfoW(mh, &mi); SetWindowPos(window->win32.handle, HWND_TOP, mi.rcWork.left, @@ -1564,8 +1564,8 @@ void _glfwPlatformSetWindowIcon(_GLFWwindow* window, smallIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICONSM); } - SendMessage(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon); - SendMessage(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon); + SendMessageW(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon); + SendMessageW(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon); if (window->win32.bigIcon) DestroyIcon(window->win32.bigIcon); @@ -1835,7 +1835,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, acquireMonitor(window); - GetMonitorInfo(window->monitor->win32.handle, &mi); + GetMonitorInfoW(window->monitor->win32.handle, &mi); SetWindowPos(window->win32.handle, HWND_TOPMOST, mi.rcMonitor.left, mi.rcMonitor.top, @@ -2099,7 +2099,7 @@ void _glfwPlatformWaitEventsTimeout(double timeout) void _glfwPlatformPostEmptyEvent(void) { - PostMessage(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0); + PostMessageW(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0); } void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) @@ -2343,7 +2343,7 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, memset(&sci, 0, sizeof(sci)); sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; - sci.hinstance = GetModuleHandle(NULL); + sci.hinstance = GetModuleHandleW(NULL); sci.hwnd = window->win32.handle; err = vkCreateWin32SurfaceKHR(instance, &sci, allocator, surface); From 5688fb19e61079f508daa6f4f5d39485213f2211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 9 Mar 2022 18:18:04 +0100 Subject: [PATCH 27/30] Win32: Update rationale for reimplementation It is true that plain MinGW lacks this header, but that is not the main reason for reimplementing IsWindowsVersionOrGreater. (cherry picked from commit aa803f7de5cc086b1c335161a50016f23c49882a) --- src/win32_init.c | 3 ++- src/win32_platform.h | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/win32_init.c b/src/win32_init.c index c1bdd5a9..4923b266 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -509,7 +509,8 @@ void _glfwUpdateKeyNamesWin32(void) } } -// Replacement for IsWindowsVersionOrGreater as MinGW lacks versionhelpers.h +// Replacement for IsWindowsVersionOrGreater, as we cannot rely on the +// application having a correct embedded manifest // BOOL _glfwIsWindowsVersionOrGreaterWin32(WORD major, WORD minor, WORD sp) { diff --git a/src/win32_platform.h b/src/win32_platform.h index 2e947ecf..92d43d07 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -162,7 +162,9 @@ typedef enum #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE) -4) #endif /*DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2*/ -// HACK: Define versionhelpers.h functions manually as MinGW lacks the header +// Replacement for versionhelpers.h macros, as we cannot rely on the +// application having a correct embedded manifest +// #define IsWindowsXPOrGreater() \ _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WINXP), \ LOBYTE(_WIN32_WINNT_WINXP), 0) From d9fd087bbff26197d0e6e8c6ce6feec19e9ea474 Mon Sep 17 00:00:00 2001 From: Slemmie Date: Fri, 20 Aug 2021 06:41:59 +0200 Subject: [PATCH 28/30] X11: Fix undefined behavior in bit shift of int Closes #1951 (cherry picked from commit b54fb0af10bb0167df67fece984350e66bf569ce) --- src/x11_window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x11_window.c b/src/x11_window.c index bf923fe6..ce089d0d 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1332,7 +1332,7 @@ static void processEvent(XEvent *event) // (the server never sends a timestamp of zero) // NOTE: Timestamp difference is compared to handle wrap-around Time diff = event->xkey.time - window->x11.keyPressTimes[keycode]; - if (diff == event->xkey.time || (diff > 0 && diff < (1 << 31))) + if (diff == event->xkey.time || (diff > 0 && diff < ((Time)1 << 31))) { if (keycode) _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); From 395f0a8b637ef50cb94f4b73d9b87954b70067b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 10 Mar 2022 20:04:56 +0100 Subject: [PATCH 29/30] Update changelog and add credit Related to #1951 (cherry picked from commit 1461c59aa2426b25503102e62bc8f4b65e079c5f) --- CONTRIBUTORS.md | 1 + README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index c17b7374..e80a0fed 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -183,6 +183,7 @@ video tutorials. - Joao da Silva - Daniel Sieger - Daniel Skorupski + - Slemmie - Bradley Smith - Cliff Smolinsky - Patrick Snape diff --git a/README.md b/README.md index 2bd4b63a..cc2667e2 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,7 @@ information on what to include when reporting a bug. - [X11] Bugfix: `glfwPostEmptyEvent` could be ignored due to race condition (#379,#1281,#1285,#2033) - [X11] Bugfix: Dynamic loading on NetBSD failed due to soname differences + - [X11] Bugfix: Left shift of int constant relied on undefined behavior (#1951) - [Wayland] Added support for key names via xkbcommon - [Wayland] Bugfix: Key repeat could lead to a race condition (#1710) - [Wayland] Bugfix: Activating a window would emit two input focus events From 45ce5ddd197d5c58f50fdd3296a5131c894e5527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 13 Mar 2022 15:18:39 +0100 Subject: [PATCH 30/30] Fix button field names in input guide Fixes #2056 (cherry picked from commit 46950a5e61ae6febb6dd554aea212f9130927b98) --- CONTRIBUTORS.md | 1 + docs/input.dox | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index e80a0fed..0bc0cd29 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -29,6 +29,7 @@ video tutorials. - David Carlier - Arturo Castro - Chi-kwan Chan + - TheChocolateOre - Joseph Chua - Ian Clarkson - Michał Cichoń diff --git a/docs/input.dox b/docs/input.dox index d9c27a67..7514e957 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -818,7 +818,7 @@ The second value is always the human-readable name of the gamepad. All subsequent values are in the form `:` and describe the layout of the mapping. These fields may not all be present and may occur in any order. -The button fields are `a`, `b`, `c`, `d`, `back`, `start`, `guide`, `dpup`, +The button fields are `a`, `b`, `x`, `y`, `back`, `start`, `guide`, `dpup`, `dpright`, `dpdown`, `dpleft`, `leftshoulder`, `rightshoulder`, `leftstick` and `rightstick`.