From a28adba06acc4e5a09e836bd5d4569636c5d3f65 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/43] Wayland: Fix multiple copies of single constant --- 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 e7756385..d4a44464 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -1367,14 +1367,15 @@ int _glfwInitWayland(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 = _glfw_calloc(4096, 1); + + _glfw.wl.clipboardSize = 4096; + _glfw.wl.clipboardString = _glfw_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 4a68926bfd999c835009429e6452b2c271252959 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/43] Wayland: Remove unnecessary NULL checks It is fine to pass NULL to _glfw_free. --- 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 d4a44464..769cc084 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -1461,9 +1461,7 @@ void _glfwTerminateWayland(void) if (_glfw.wl.cursorTimerfd >= 0) close(_glfw.wl.cursorTimerfd); - if (_glfw.wl.clipboardString) - _glfw_free(_glfw.wl.clipboardString); - if (_glfw.wl.clipboardSendString) - _glfw_free(_glfw.wl.clipboardSendString); + _glfw_free(_glfw.wl.clipboardString); + _glfw_free(_glfw.wl.clipboardSendString); } From 152f50cd0149ace9242971bf1bae3a5abde24951 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/43] Wayland: Fix error type for allocation failure --- 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 769cc084..e4ae6666 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -1372,7 +1372,7 @@ int _glfwInitWayland(void) _glfw.wl.clipboardString = _glfw_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 b2aa1800..0def0746 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -1675,7 +1675,7 @@ static GLFWbool growClipboardString(void) clipboard = _glfw_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 20adc18aa587b75867775942d25356014e11fde9 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/43] Wayland: Clean up monitor scale update --- src/wl_window.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index 0def0746..367acacc 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -345,26 +345,25 @@ static void resizeWindow(_GLFWwindow* window) static void checkScaleChange(_GLFWwindow* window) { - int scale = 1; - 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 (int 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 2e656afc4972827930e845c3124a08c42ac5d564 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/43] GLX: Fix context creation failing unnecessarily Regression introduced with 3bb5c459d63d7cf9c990213e39303d9ba5eaebcc. --- README.md | 1 + src/glx_context.c | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 7ffd4850..9543919e 100644 --- a/README.md +++ b/README.md @@ -304,6 +304,7 @@ information on what to include when reporting a bug. - [EGL] Added ANGLE backend selection via `EGL_ANGLE_platform_angle` extension (#1380) - [EGL] Bugfix: The `GLFW_DOUBLEBUFFER` context attribute was ignored (#1843) + - [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 31cd34dc..00f38ac3 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -308,10 +308,6 @@ GLFWbool _glfwInitGLX(void) _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXCreateWindow"); _glfw.glx.DestroyWindow = (PFNGLXDESTROYWINDOWPROC) _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXDestroyWindow"); - _glfw.glx.GetProcAddress = (PFNGLXGETPROCADDRESSPROC) - _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetProcAddress"); - _glfw.glx.GetProcAddressARB = (PFNGLXGETPROCADDRESSPROC) - _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetProcAddressARB"); _glfw.glx.GetVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC) _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetVisualFromFBConfig"); @@ -327,8 +323,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, @@ -336,6 +330,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) + _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetProcAddress"); + _glfw.glx.GetProcAddressARB = (PFNGLXGETPROCADDRESSPROC) + _glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetProcAddressARB"); + if (!glXQueryExtension(_glfw.x11.display, &_glfw.glx.errorBase, &_glfw.glx.eventBase)) From 789d2924c0f865bbba6df3c7097199d1e2f2ecf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 7 Jan 2022 11:51:12 +0100 Subject: [PATCH 06/43] Formatting Make it clear that context attribute helper macros are macros. --- src/egl_context.c | 42 +++++++------- src/glx_context.c | 32 +++++------ src/nsgl_context.m | 44 +++++++-------- src/osmesa_context.c | 22 ++++---- src/wgl_context.c | 130 +++++++++++++++++++++---------------------- 5 files changed, 135 insertions(+), 135 deletions(-) diff --git a/src/egl_context.c b/src/egl_context.c index 89ea78fa..963a59d6 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -506,7 +506,7 @@ void _glfwTerminateEGL(void) } } -#define setAttrib(a, v) \ +#define SET_ATTRIB(a, v) \ { \ assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ attribs[index++] = a; \ @@ -584,13 +584,13 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, { if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) { - setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, - EGL_NO_RESET_NOTIFICATION_KHR); + SET_ATTRIB(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, + EGL_NO_RESET_NOTIFICATION_KHR); } else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) { - setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, - EGL_LOSE_CONTEXT_ON_RESET_KHR); + SET_ATTRIB(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, + EGL_LOSE_CONTEXT_ON_RESET_KHR); } flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; @@ -599,42 +599,42 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, if (ctxconfig->noerror) { if (_glfw.egl.KHR_create_context_no_error) - setAttrib(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE); + SET_ATTRIB(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE); } if (ctxconfig->major != 1 || ctxconfig->minor != 0) { - setAttrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major); - setAttrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor); + SET_ATTRIB(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major); + SET_ATTRIB(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor); } if (mask) - setAttrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask); + SET_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask); if (flags) - setAttrib(EGL_CONTEXT_FLAGS_KHR, flags); + SET_ATTRIB(EGL_CONTEXT_FLAGS_KHR, flags); } else { if (ctxconfig->client == GLFW_OPENGL_ES_API) - setAttrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major); + SET_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major); } if (_glfw.egl.KHR_context_flush_control) { if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) { - setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, - EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR); + SET_ATTRIB(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, + EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR); } else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) { - setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, - EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR); + SET_ATTRIB(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, + EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR); } } - setAttrib(EGL_NONE, EGL_NONE); + SET_ATTRIB(EGL_NONE, EGL_NONE); window->context.egl.handle = eglCreateContext(_glfw.egl.display, config, share, attribs); @@ -653,16 +653,16 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, if (fbconfig->sRGB) { if (_glfw.egl.KHR_gl_colorspace) - setAttrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR); + SET_ATTRIB(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR); } if (!fbconfig->doublebuffer) - setAttrib(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER); + SET_ATTRIB(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER); if (_glfw.egl.EXT_present_opaque) - setAttrib(EGL_PRESENT_OPAQUE_EXT, !fbconfig->transparent); + SET_ATTRIB(EGL_PRESENT_OPAQUE_EXT, !fbconfig->transparent); - setAttrib(EGL_NONE, EGL_NONE); + SET_ATTRIB(EGL_NONE, EGL_NONE); native = _glfw.platform.getEGLNativeWindow(window); // HACK: ANGLE does not implement eglCreatePlatformWindowSurfaceEXT @@ -782,7 +782,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, return GLFW_TRUE; } -#undef setAttrib +#undef SET_ATTRIB // Returns the Visual and depth of the chosen EGLConfig // diff --git a/src/glx_context.c b/src/glx_context.c index 00f38ac3..ced9c88f 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -435,7 +435,7 @@ void _glfwTerminateGLX(void) } } -#define setAttrib(a, v) \ +#define SET_ATTRIB(a, v) \ { \ assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ attribs[index++] = a; \ @@ -523,13 +523,13 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, { if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) { - setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, - GLX_NO_RESET_NOTIFICATION_ARB); + SET_ATTRIB(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + GLX_NO_RESET_NOTIFICATION_ARB); } else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) { - setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, - GLX_LOSE_CONTEXT_ON_RESET_ARB); + SET_ATTRIB(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + GLX_LOSE_CONTEXT_ON_RESET_ARB); } flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; @@ -542,13 +542,13 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, { if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) { - setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, - GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); + SET_ATTRIB(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, + GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); } else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) { - setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, - GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); + SET_ATTRIB(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, + GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); } } } @@ -556,7 +556,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, if (ctxconfig->noerror) { if (_glfw.glx.ARB_create_context_no_error) - setAttrib(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); + SET_ATTRIB(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); } // NOTE: Only request an explicitly versioned context when necessary, as @@ -564,17 +564,17 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, // highest version supported by the driver if (ctxconfig->major != 1 || ctxconfig->minor != 0) { - setAttrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); - setAttrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); + SET_ATTRIB(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); + SET_ATTRIB(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); } if (mask) - setAttrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask); + SET_ATTRIB(GLX_CONTEXT_PROFILE_MASK_ARB, mask); if (flags) - setAttrib(GLX_CONTEXT_FLAGS_ARB, flags); + SET_ATTRIB(GLX_CONTEXT_FLAGS_ARB, flags); - setAttrib(None, None); + SET_ATTRIB(None, None); window->context.glx.handle = _glfw.glx.CreateContextAttribsARB(_glfw.x11.display, @@ -631,7 +631,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, return GLFW_TRUE; } -#undef setAttrib +#undef SET_ATTRIB // Returns the Visual and depth of the chosen GLXFBConfig // diff --git a/src/nsgl_context.m b/src/nsgl_context.m index f85ef67b..fc1f7521 100644 --- a/src/nsgl_context.m +++ b/src/nsgl_context.m @@ -188,45 +188,45 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, // No-error contexts (GL_KHR_no_error) are not yet supported by macOS but // are not a hard constraint, so ignore and continue -#define addAttrib(a) \ +#define ADD_ATTRIB(a) \ { \ assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ attribs[index++] = a; \ } -#define setAttrib(a, v) { addAttrib(a); addAttrib(v); } +#define SET_ATTRIB(a, v) { ADD_ATTRIB(a); ADD_ATTRIB(v); } NSOpenGLPixelFormatAttribute attribs[40]; int index = 0; - addAttrib(NSOpenGLPFAAccelerated); - addAttrib(NSOpenGLPFAClosestPolicy); + ADD_ATTRIB(NSOpenGLPFAAccelerated); + ADD_ATTRIB(NSOpenGLPFAClosestPolicy); if (ctxconfig->nsgl.offline) { - addAttrib(NSOpenGLPFAAllowOfflineRenderers); + ADD_ATTRIB(NSOpenGLPFAAllowOfflineRenderers); // NOTE: This replaces the NSSupportsAutomaticGraphicsSwitching key in // Info.plist for unbundled applications // HACK: This assumes that NSOpenGLPixelFormat will remain // a straightforward wrapper of its CGL counterpart - addAttrib(kCGLPFASupportsAutomaticGraphicsSwitching); + ADD_ATTRIB(kCGLPFASupportsAutomaticGraphicsSwitching); } #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 if (ctxconfig->major >= 4) { - setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core); + SET_ATTRIB(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core); } else #endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ if (ctxconfig->major >= 3) { - setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core); + SET_ATTRIB(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core); } if (ctxconfig->major <= 2) { if (fbconfig->auxBuffers != GLFW_DONT_CARE) - setAttrib(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers); + SET_ATTRIB(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers); if (fbconfig->accumRedBits != GLFW_DONT_CARE && fbconfig->accumGreenBits != GLFW_DONT_CARE && @@ -238,7 +238,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, fbconfig->accumBlueBits + fbconfig->accumAlphaBits; - setAttrib(NSOpenGLPFAAccumSize, accumBits); + SET_ATTRIB(NSOpenGLPFAAccumSize, accumBits); } } @@ -256,17 +256,17 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, else if (colorBits < 15) colorBits = 15; - setAttrib(NSOpenGLPFAColorSize, colorBits); + SET_ATTRIB(NSOpenGLPFAColorSize, colorBits); } if (fbconfig->alphaBits != GLFW_DONT_CARE) - setAttrib(NSOpenGLPFAAlphaSize, fbconfig->alphaBits); + SET_ATTRIB(NSOpenGLPFAAlphaSize, fbconfig->alphaBits); if (fbconfig->depthBits != GLFW_DONT_CARE) - setAttrib(NSOpenGLPFADepthSize, fbconfig->depthBits); + SET_ATTRIB(NSOpenGLPFADepthSize, fbconfig->depthBits); if (fbconfig->stencilBits != GLFW_DONT_CARE) - setAttrib(NSOpenGLPFAStencilSize, fbconfig->stencilBits); + SET_ATTRIB(NSOpenGLPFAStencilSize, fbconfig->stencilBits); if (fbconfig->stereo) { @@ -275,33 +275,33 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, "NSGL: Stereo rendering is deprecated"); return GLFW_FALSE; #else - addAttrib(NSOpenGLPFAStereo); + ADD_ATTRIB(NSOpenGLPFAStereo); #endif } if (fbconfig->doublebuffer) - addAttrib(NSOpenGLPFADoubleBuffer); + ADD_ATTRIB(NSOpenGLPFADoubleBuffer); if (fbconfig->samples != GLFW_DONT_CARE) { if (fbconfig->samples == 0) { - setAttrib(NSOpenGLPFASampleBuffers, 0); + SET_ATTRIB(NSOpenGLPFASampleBuffers, 0); } else { - setAttrib(NSOpenGLPFASampleBuffers, 1); - setAttrib(NSOpenGLPFASamples, fbconfig->samples); + SET_ATTRIB(NSOpenGLPFASampleBuffers, 1); + SET_ATTRIB(NSOpenGLPFASamples, fbconfig->samples); } } // NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB // framebuffer, so there's no need (and no way) to request it - addAttrib(0); + ADD_ATTRIB(0); -#undef addAttrib -#undef setAttrib +#undef ADD_ATTRIB +#undef SET_ATTRIB window->context.nsgl.pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; diff --git a/src/osmesa_context.c b/src/osmesa_context.c index 161d9fd8..43ade8dc 100644 --- a/src/osmesa_context.c +++ b/src/osmesa_context.c @@ -190,7 +190,7 @@ void _glfwTerminateOSMesa(void) } } -#define setAttrib(a, v) \ +#define SET_ATTRIB(a, v) \ { \ assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ attribs[index++] = a; \ @@ -221,24 +221,24 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, { int index = 0, attribs[40]; - setAttrib(OSMESA_FORMAT, OSMESA_RGBA); - setAttrib(OSMESA_DEPTH_BITS, fbconfig->depthBits); - setAttrib(OSMESA_STENCIL_BITS, fbconfig->stencilBits); - setAttrib(OSMESA_ACCUM_BITS, accumBits); + SET_ATTRIB(OSMESA_FORMAT, OSMESA_RGBA); + SET_ATTRIB(OSMESA_DEPTH_BITS, fbconfig->depthBits); + SET_ATTRIB(OSMESA_STENCIL_BITS, fbconfig->stencilBits); + SET_ATTRIB(OSMESA_ACCUM_BITS, accumBits); if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) { - setAttrib(OSMESA_PROFILE, OSMESA_CORE_PROFILE); + SET_ATTRIB(OSMESA_PROFILE, OSMESA_CORE_PROFILE); } else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) { - setAttrib(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE); + SET_ATTRIB(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE); } if (ctxconfig->major != 1 || ctxconfig->minor != 0) { - setAttrib(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major); - setAttrib(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor); + SET_ATTRIB(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major); + SET_ATTRIB(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor); } if (ctxconfig->forward) @@ -248,7 +248,7 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, return GLFW_FALSE; } - setAttrib(0, 0); + SET_ATTRIB(0, 0); window->context.osmesa.handle = OSMesaCreateContextAttribs(attribs, share); @@ -287,7 +287,7 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, return GLFW_TRUE; } -#undef setAttrib +#undef SET_ATTRIB ////////////////////////////////////////////////////////////////////////// diff --git a/src/wgl_context.c b/src/wgl_context.c index 6586db10..a82c736b 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -52,12 +52,12 @@ static int findPixelFormatAttribValueWGL(const int* attribs, return 0; } -#define addAttrib(a) \ +#define ADD_ATTRIB(a) \ { \ assert((size_t) attribCount < sizeof(attribs) / sizeof(attribs[0])); \ attribs[attribCount++] = a; \ } -#define findAttribValue(a) \ +#define FIND_ATTRIB_VALUE(a) \ findPixelFormatAttribValueWGL(attribs, attribCount, values, a) // Return a list of available and usable framebuffer configs @@ -84,41 +84,41 @@ static int choosePixelFormatWGL(_GLFWwindow* window, return 0; } - addAttrib(WGL_SUPPORT_OPENGL_ARB); - addAttrib(WGL_DRAW_TO_WINDOW_ARB); - addAttrib(WGL_PIXEL_TYPE_ARB); - addAttrib(WGL_ACCELERATION_ARB); - addAttrib(WGL_RED_BITS_ARB); - addAttrib(WGL_RED_SHIFT_ARB); - addAttrib(WGL_GREEN_BITS_ARB); - addAttrib(WGL_GREEN_SHIFT_ARB); - addAttrib(WGL_BLUE_BITS_ARB); - addAttrib(WGL_BLUE_SHIFT_ARB); - addAttrib(WGL_ALPHA_BITS_ARB); - addAttrib(WGL_ALPHA_SHIFT_ARB); - addAttrib(WGL_DEPTH_BITS_ARB); - addAttrib(WGL_STENCIL_BITS_ARB); - addAttrib(WGL_ACCUM_BITS_ARB); - addAttrib(WGL_ACCUM_RED_BITS_ARB); - addAttrib(WGL_ACCUM_GREEN_BITS_ARB); - addAttrib(WGL_ACCUM_BLUE_BITS_ARB); - addAttrib(WGL_ACCUM_ALPHA_BITS_ARB); - addAttrib(WGL_AUX_BUFFERS_ARB); - addAttrib(WGL_STEREO_ARB); - addAttrib(WGL_DOUBLE_BUFFER_ARB); + ADD_ATTRIB(WGL_SUPPORT_OPENGL_ARB); + ADD_ATTRIB(WGL_DRAW_TO_WINDOW_ARB); + ADD_ATTRIB(WGL_PIXEL_TYPE_ARB); + ADD_ATTRIB(WGL_ACCELERATION_ARB); + ADD_ATTRIB(WGL_RED_BITS_ARB); + ADD_ATTRIB(WGL_RED_SHIFT_ARB); + ADD_ATTRIB(WGL_GREEN_BITS_ARB); + ADD_ATTRIB(WGL_GREEN_SHIFT_ARB); + ADD_ATTRIB(WGL_BLUE_BITS_ARB); + ADD_ATTRIB(WGL_BLUE_SHIFT_ARB); + ADD_ATTRIB(WGL_ALPHA_BITS_ARB); + ADD_ATTRIB(WGL_ALPHA_SHIFT_ARB); + ADD_ATTRIB(WGL_DEPTH_BITS_ARB); + ADD_ATTRIB(WGL_STENCIL_BITS_ARB); + ADD_ATTRIB(WGL_ACCUM_BITS_ARB); + ADD_ATTRIB(WGL_ACCUM_RED_BITS_ARB); + ADD_ATTRIB(WGL_ACCUM_GREEN_BITS_ARB); + ADD_ATTRIB(WGL_ACCUM_BLUE_BITS_ARB); + ADD_ATTRIB(WGL_ACCUM_ALPHA_BITS_ARB); + ADD_ATTRIB(WGL_AUX_BUFFERS_ARB); + ADD_ATTRIB(WGL_STEREO_ARB); + ADD_ATTRIB(WGL_DOUBLE_BUFFER_ARB); if (_glfw.wgl.ARB_multisample) - addAttrib(WGL_SAMPLES_ARB); + ADD_ATTRIB(WGL_SAMPLES_ARB); if (ctxconfig->client == GLFW_OPENGL_API) { if (_glfw.wgl.ARB_framebuffer_sRGB || _glfw.wgl.EXT_framebuffer_sRGB) - addAttrib(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB); + ADD_ATTRIB(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB); } else { if (_glfw.wgl.EXT_colorspace) - addAttrib(WGL_COLORSPACE_EXT); + ADD_ATTRIB(WGL_COLORSPACE_EXT); } } else @@ -152,48 +152,48 @@ static int choosePixelFormatWGL(_GLFWwindow* window, return 0; } - if (!findAttribValue(WGL_SUPPORT_OPENGL_ARB) || - !findAttribValue(WGL_DRAW_TO_WINDOW_ARB)) + if (!FIND_ATTRIB_VALUE(WGL_SUPPORT_OPENGL_ARB) || + !FIND_ATTRIB_VALUE(WGL_DRAW_TO_WINDOW_ARB)) { continue; } - if (findAttribValue(WGL_PIXEL_TYPE_ARB) != WGL_TYPE_RGBA_ARB) + if (FIND_ATTRIB_VALUE(WGL_PIXEL_TYPE_ARB) != WGL_TYPE_RGBA_ARB) continue; - if (findAttribValue(WGL_ACCELERATION_ARB) == WGL_NO_ACCELERATION_ARB) + if (FIND_ATTRIB_VALUE(WGL_ACCELERATION_ARB) == WGL_NO_ACCELERATION_ARB) continue; - if (findAttribValue(WGL_DOUBLE_BUFFER_ARB) != fbconfig->doublebuffer) + if (FIND_ATTRIB_VALUE(WGL_DOUBLE_BUFFER_ARB) != fbconfig->doublebuffer) continue; - u->redBits = findAttribValue(WGL_RED_BITS_ARB); - u->greenBits = findAttribValue(WGL_GREEN_BITS_ARB); - u->blueBits = findAttribValue(WGL_BLUE_BITS_ARB); - u->alphaBits = findAttribValue(WGL_ALPHA_BITS_ARB); + u->redBits = FIND_ATTRIB_VALUE(WGL_RED_BITS_ARB); + u->greenBits = FIND_ATTRIB_VALUE(WGL_GREEN_BITS_ARB); + u->blueBits = FIND_ATTRIB_VALUE(WGL_BLUE_BITS_ARB); + u->alphaBits = FIND_ATTRIB_VALUE(WGL_ALPHA_BITS_ARB); - u->depthBits = findAttribValue(WGL_DEPTH_BITS_ARB); - u->stencilBits = findAttribValue(WGL_STENCIL_BITS_ARB); + u->depthBits = FIND_ATTRIB_VALUE(WGL_DEPTH_BITS_ARB); + u->stencilBits = FIND_ATTRIB_VALUE(WGL_STENCIL_BITS_ARB); - u->accumRedBits = findAttribValue(WGL_ACCUM_RED_BITS_ARB); - u->accumGreenBits = findAttribValue(WGL_ACCUM_GREEN_BITS_ARB); - u->accumBlueBits = findAttribValue(WGL_ACCUM_BLUE_BITS_ARB); - u->accumAlphaBits = findAttribValue(WGL_ACCUM_ALPHA_BITS_ARB); + u->accumRedBits = FIND_ATTRIB_VALUE(WGL_ACCUM_RED_BITS_ARB); + u->accumGreenBits = FIND_ATTRIB_VALUE(WGL_ACCUM_GREEN_BITS_ARB); + u->accumBlueBits = FIND_ATTRIB_VALUE(WGL_ACCUM_BLUE_BITS_ARB); + u->accumAlphaBits = FIND_ATTRIB_VALUE(WGL_ACCUM_ALPHA_BITS_ARB); - u->auxBuffers = findAttribValue(WGL_AUX_BUFFERS_ARB); + u->auxBuffers = FIND_ATTRIB_VALUE(WGL_AUX_BUFFERS_ARB); - if (findAttribValue(WGL_STEREO_ARB)) + if (FIND_ATTRIB_VALUE(WGL_STEREO_ARB)) u->stereo = GLFW_TRUE; if (_glfw.wgl.ARB_multisample) - u->samples = findAttribValue(WGL_SAMPLES_ARB); + u->samples = FIND_ATTRIB_VALUE(WGL_SAMPLES_ARB); if (ctxconfig->client == GLFW_OPENGL_API) { if (_glfw.wgl.ARB_framebuffer_sRGB || _glfw.wgl.EXT_framebuffer_sRGB) { - if (findAttribValue(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB)) + if (FIND_ATTRIB_VALUE(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB)) u->sRGB = GLFW_TRUE; } } @@ -201,7 +201,7 @@ static int choosePixelFormatWGL(_GLFWwindow* window, { if (_glfw.wgl.EXT_colorspace) { - if (findAttribValue(WGL_COLORSPACE_EXT) == WGL_COLORSPACE_SRGB_EXT) + if (FIND_ATTRIB_VALUE(WGL_COLORSPACE_EXT) == WGL_COLORSPACE_SRGB_EXT) u->sRGB = GLFW_TRUE; } } @@ -290,8 +290,8 @@ static int choosePixelFormatWGL(_GLFWwindow* window, return pixelFormat; } -#undef addAttrib -#undef findAttribValue +#undef ADD_ATTRIB +#undef FIND_ATTRIB_VALUE static void makeContextCurrentWGL(_GLFWwindow* window) { @@ -523,7 +523,7 @@ void _glfwTerminateWGL(void) _glfwPlatformFreeModule(_glfw.wgl.instance); } -#define setAttrib(a, v) \ +#define SET_ATTRIB(a, v) \ { \ assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ attribs[index++] = a; \ @@ -631,13 +631,13 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, { if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) { - setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, - WGL_NO_RESET_NOTIFICATION_ARB); + SET_ATTRIB(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + WGL_NO_RESET_NOTIFICATION_ARB); } else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) { - setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, - WGL_LOSE_CONTEXT_ON_RESET_ARB); + SET_ATTRIB(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + WGL_LOSE_CONTEXT_ON_RESET_ARB); } flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; @@ -650,13 +650,13 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, { if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) { - setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, - WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); + SET_ATTRIB(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, + WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); } else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) { - setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, - WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); + SET_ATTRIB(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, + WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); } } } @@ -664,7 +664,7 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, if (ctxconfig->noerror) { if (_glfw.wgl.ARB_create_context_no_error) - setAttrib(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); + SET_ATTRIB(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); } // NOTE: Only request an explicitly versioned context when necessary, as @@ -672,17 +672,17 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, // highest version supported by the driver if (ctxconfig->major != 1 || ctxconfig->minor != 0) { - setAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); - setAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); + SET_ATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); + SET_ATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); } if (flags) - setAttrib(WGL_CONTEXT_FLAGS_ARB, flags); + SET_ATTRIB(WGL_CONTEXT_FLAGS_ARB, flags); if (mask) - setAttrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask); + SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, mask); - setAttrib(0, 0); + SET_ATTRIB(0, 0); window->context.wgl.handle = wglCreateContextAttribsARB(window->context.wgl.dc, share, attribs); @@ -765,7 +765,7 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, return GLFW_TRUE; } -#undef setAttrib +#undef SET_ATTRIB GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle) { From ad01c1b614868c3cbc79306aa6a19c9fc06f34a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 20 Jan 2022 19:21:48 +0100 Subject: [PATCH 07/43] Win32: Fix key name code changing global key state This prevents glfwInit from potentially clobbering the dead key state for other applications. Closes #2018 --- CONTRIBUTORS.md | 1 + README.md | 2 ++ src/win32_init.c | 9 +++++++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index cb9b0d58..82e91773 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -10,6 +10,7 @@ video tutorials. - Matt Arsenault - ashishgamedev - David Avedissian + - Luca Bacci - Keith Bauer - John Bartholomew - Coşku Baş diff --git a/README.md b/README.md index 9543919e..0aa309d7 100644 --- a/README.md +++ b/README.md @@ -205,6 +205,8 @@ information on what to include when reporting a bug. - [Win32] Bugfix: Content scale queries could fail silently (#1615) - [Win32] Bugfix: Content scales could have garbage values if monitor was recently disconnected (#1615) + - [Win32] Bugfix: Key name update modified global key state on Windows 10 1607 + and later (#2018) - [Cocoa] Added support for `VK_EXT_metal_surface` (#1619) - [Cocoa] Added locating the Vulkan loader at runtime in an application bundle - [Cocoa] Moved main menu creation to GLFW initialization time (#1649) diff --git a/src/win32_init.c b/src/win32_init.c index e687d770..0479afe5 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -458,6 +458,11 @@ void _glfwUpdateKeyNamesWin32(void) { int key; BYTE state[256] = {0}; + UINT flags = 0; + + // Avoid modifying the global key state if supported + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + flags = (1 << 2); memset(_glfw.win32.keynames, 0, sizeof(_glfw.win32.keynames)); @@ -487,13 +492,13 @@ void _glfwUpdateKeyNamesWin32(void) length = ToUnicode(vk, scancode, state, chars, sizeof(chars) / sizeof(WCHAR), - 0); + flags); if (length == -1) { length = ToUnicode(vk, scancode, state, chars, sizeof(chars) / sizeof(WCHAR), - 0); + flags); } if (length < 1) From d3e4fcf8b7608e7b6f6cf1c102b1e28c478f5a6c 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 08/43] 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 --- CONTRIBUTORS.md | 1 + README.md | 2 ++ src/x11_window.c | 32 +++++++++++++------------------- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 82e91773..34ca624f 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -82,6 +82,7 @@ video tutorials. - Paul Holden - Warren Hu - Charles Huber + - illustris - InKryption - IntellectualKitty - Aaron Jacobs diff --git a/README.md b/README.md index 0aa309d7..7fc32b98 100644 --- a/README.md +++ b/README.md @@ -268,6 +268,8 @@ information on what to include when reporting a bug. - [X11] Bugfix: Icon pixel format conversion worked only by accident, relying on undefined behavior (#1986) - [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 dynamic loading of all Wayland libraries - [Wayland] Added support for key names via xkbcommon - [Wayland] Removed support for `wl_shell` (#1443) diff --git a/src/x11_window.c b/src/x11_window.c index 61e4fd6d..08422e5f 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); + if (_glfw.joysticksInitialized) + 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 92b5c67b50d2bab9401f464d4a40fecfccb09dfb 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 09/43] X11: Retry poll when failed with EINTR or EAGAIN Both of these errors should just lead to local retry. --- 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 08422e5f..f4adbd3e 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 1e987cb92ea646282a2e3f7c085f96ae7eeea425 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 10/43] 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 --- README.md | 1 + src/x11_window.c | 59 +++++++++++++++++++++++++++++------------------- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 7fc32b98..23cc069a 100644 --- a/README.md +++ b/README.md @@ -270,6 +270,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 dynamic loading of all Wayland libraries - [Wayland] Added support for key names via xkbcommon - [Wayland] Removed support for `wl_shell` (#1443) diff --git a/src/x11_window.c b/src/x11_window.c index f4adbd3e..122db2ba 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.joysticksInitialized) - 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.joysticksInitialized) + 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; } @@ -960,7 +973,7 @@ static const char* getSelectionString(Atom selection) SelectionNotify, ¬ification)) { - waitForEvent(NULL); + waitForX11Event(NULL); } if (notification.xselection.property == None) @@ -996,7 +1009,7 @@ static const char* getSelectionString(Atom selection) isSelPropNewValueNotify, (XPointer) ¬ification)) { - waitForEvent(NULL); + waitForX11Event(NULL); } XFree(data); @@ -1898,7 +1911,7 @@ void _glfwPushSelectionToManagerX11(void) } } - waitForEvent(NULL); + waitForX11Event(NULL); } } @@ -2240,7 +2253,7 @@ void _glfwGetWindowFrameSizeX11(_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"); @@ -2782,7 +2795,7 @@ void _glfwPollEventsX11(void) void _glfwWaitEventsX11(void) { while (!XPending(_glfw.x11.display)) - waitForEvent(NULL); + waitForAnyEvent(NULL); _glfwPollEventsX11(); } @@ -2791,7 +2804,7 @@ void _glfwWaitEventsTimeoutX11(double timeout) { while (!XPending(_glfw.x11.display)) { - if (!waitForEvent(&timeout)) + if (!waitForAnyEvent(&timeout)) break; } From 87970b7f265bbd39595de6428bbd14047affa753 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 11/43] 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 --- README.md | 1 + src/x11_window.c | 34 +++++++++++++++++++++++----------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 23cc069a..fefaf500 100644 --- a/README.md +++ b/README.md @@ -271,6 +271,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 dynamic loading of all Wayland libraries - [Wayland] Added support for key names via xkbcommon - [Wayland] Removed support for `wl_shell` (#1443) diff --git a/src/x11_window.c b/src/x11_window.c index 122db2ba..c42be084 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 @@ -2794,20 +2813,13 @@ void _glfwPollEventsX11(void) void _glfwWaitEventsX11(void) { - while (!XPending(_glfw.x11.display)) - waitForAnyEvent(NULL); - + waitForAnyEvent(NULL); _glfwPollEventsX11(); } void _glfwWaitEventsTimeoutX11(double timeout) { - while (!XPending(_glfw.x11.display)) - { - if (!waitForAnyEvent(&timeout)) - break; - } - + waitForAnyEvent(&timeout); _glfwPollEventsX11(); } From 363d4714414e53312cd5cb0be230f040580487ad 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 12/43] Cleanup --- 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 c42be084..50fba5e8 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2778,8 +2778,6 @@ GLFWbool _glfwRawMouseMotionSupportedX11(void) void _glfwPollEventsX11(void) { - _GLFWwindow* window; - #if defined(__linux__) if (_glfw.joysticksInitialized) _glfwDetectJoystickConnectionLinux(); @@ -2793,7 +2791,7 @@ void _glfwPollEventsX11(void) processEvent(&event); } - window = _glfw.x11.disabledCursorWindow; + _GLFWwindow* window = _glfw.x11.disabledCursorWindow; if (window) { int width, height; From cd22e2849512a88d0ab77bc7a3458646625f2c50 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 13/43] 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 --- CONTRIBUTORS.md | 2 ++ README.md | 2 ++ docs/news.dox | 6 ++++++ src/x11_init.c | 42 ++++++++++++++++++++++++++++++++++++++++++ src/x11_platform.h | 1 + src/x11_window.c | 44 +++++++++++++++++++++++++++++++++++--------- 6 files changed, 88 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 34ca624f..f20422ec 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -185,6 +185,7 @@ video tutorials. - Ali Sherief - Yoshiki Shibukawa - Dmitri Shuralyov + - Joao da Silva - Daniel Sieger - Daniel Skorupski - Anthony Smith @@ -192,6 +193,7 @@ video tutorials. - Cliff Smolinsky - Patrick Snape - Erlend Sogge Heggen + - Olivier Sohn - Julian Squires - Johannes Stein - Pontus Stenetorp diff --git a/README.md b/README.md index fefaf500..d1dcb600 100644 --- a/README.md +++ b/README.md @@ -272,6 +272,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 dynamic loading of all Wayland libraries - [Wayland] Added support for key names via xkbcommon - [Wayland] Removed support for `wl_shell` (#1443) diff --git a/docs/news.dox b/docs/news.dox index 6c55e65f..fbf60319 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -138,6 +138,12 @@ GLFW_TRANSPARENT_FRAMEBUFFER on Windows 7 if DWM transparency is off (the Transparency setting under Personalization > Window Color). +@subsubsection emptyevents_34 Empty events on X11 no longer roundtrip to server + +Events posted with @ref glfwPostEmptyEvent now use a separate unnamed pipe +instead of sending an X11 client event to the helper window. + + @subsection deprecations_34 Deprecations in version 3.4 @subsection removals_34 Removals in 3.4 diff --git a/src/x11_init.c b/src/x11_init.c index acfa7933..203828fc 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include // Translate the X11 KeySyms for a key to a GLFW key code @@ -1042,6 +1044,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) @@ -1491,6 +1524,9 @@ int _glfwInitX11(void) getSystemContentScale(&_glfw.x11.contentScaleX, &_glfw.x11.contentScaleY); + if (!createEmptyEventPipe()) + return GLFW_FALSE; + if (!initExtensions()) return GLFW_FALSE; @@ -1604,5 +1640,11 @@ void _glfwTerminateX11(void) _glfwPlatformFreeModule(_glfw.x11.xlib.handle); _glfw.x11.xlib.handle = NULL; } + + if (_glfw.x11.emptyEventPipe[0] || _glfw.x11.emptyEventPipe[1]) + { + close(_glfw.x11.emptyEventPipe[0]); + close(_glfw.x11.emptyEventPipe[1]); + } } diff --git a/src/x11_platform.h b/src/x11_platform.h index 61a0b17d..8da3a2e4 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -582,6 +582,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 50fba5e8..76becd6c 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.joysticksInitialized) @@ -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) // @@ -2778,6 +2808,8 @@ GLFWbool _glfwRawMouseMotionSupportedX11(void) void _glfwPollEventsX11(void) { + drainEmptyEvents(); + #if defined(__linux__) if (_glfw.joysticksInitialized) _glfwDetectJoystickConnectionLinux(); @@ -2823,13 +2855,7 @@ void _glfwWaitEventsTimeoutX11(double timeout) void _glfwPostEmptyEventX11(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 _glfwGetCursorPosX11(_GLFWwindow* window, double* xpos, double* ypos) From 84b0923fe61a12bd0bf9241da102053b906265bd 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 14/43] 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 --- 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 76becd6c..52cbbcf0 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 3c2913dcb96eed94742826f4276282f4e4a7b01e 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 15/43] 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. --- 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 367acacc..1a9f980d 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -716,6 +716,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[] = @@ -730,7 +749,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 203a7c59d25058f7dfd0c7a3b5062de0b87a8517 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 16/43] 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. --- 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 1a9f980d..c150b188 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -751,6 +751,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) { @@ -758,7 +760,6 @@ static void handleEvents(int timeout) window = window->next; } - wl_display_cancel_read(_glfw.wl.display); return; } From bb9d699ae66b2bdc8718995ba13c57c9c8e59602 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 3 Mar 2022 21:26:11 +0100 Subject: [PATCH 17/43] Share X11 fd polling logic with Wayland This moves the X11 polling implementation to a separate file where it can be used by either the X11 or Wayland backend or both. This code should be POSIX compatible where necessary but will use the lower latency but non-standard polling functions ppoll or pollts where those are available. This commit is based on work by OlivierSohn and kovidgoyal. Fixes #1281 Closes #1285 --- src/CMakeLists.txt | 1 + src/posix_poll.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++ src/posix_poll.h | 32 ++++++++++++++++++ src/wl_platform.h | 1 + src/wl_window.c | 13 ++++---- src/x11_platform.h | 1 + src/x11_window.c | 57 ++----------------------------- 7 files changed, 127 insertions(+), 61 deletions(-) create mode 100644 src/posix_poll.c create mode 100644 src/posix_poll.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a07ca931..01f191c9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -60,6 +60,7 @@ if (GLFW_BUILD_X11 OR GLFW_BUILD_WAYLAND) if (CMAKE_SYSTEM_NAME STREQUAL "Linux") target_sources(glfw PRIVATE linux_joystick.h linux_joystick.c) endif() + target_sources(glfw PRIVATE posix_poll.h posix_poll.c) endif() if (GLFW_BUILD_WAYLAND) diff --git a/src/posix_poll.c b/src/posix_poll.c new file mode 100644 index 00000000..352d9900 --- /dev/null +++ b/src/posix_poll.c @@ -0,0 +1,83 @@ +//======================================================================== +// GLFW 3.4 POSIX - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2022 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// 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 + +GLFWbool _glfwPollPOSIX(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; + } + } +} + diff --git a/src/posix_poll.h b/src/posix_poll.h new file mode 100644 index 00000000..1effd1cd --- /dev/null +++ b/src/posix_poll.h @@ -0,0 +1,32 @@ +//======================================================================== +// GLFW 3.4 POSIX - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2022 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== + +#include + +GLFWbool _glfwPollPOSIX(struct pollfd* fds, nfds_t count, double* timeout); + diff --git a/src/wl_platform.h b/src/wl_platform.h index 7565411b..ba405714 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -43,6 +43,7 @@ typedef VkResult (APIENTRY *PFN_vkCreateWaylandSurfaceKHR)(VkInstance,const VkWa typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice,uint32_t,struct wl_display*); #include "xkb_unicode.h" +#include "posix_poll.h" typedef int (* PFN_wl_display_flush)(struct wl_display *display); typedef void (* PFN_wl_display_cancel_read)(struct wl_display *display); diff --git a/src/wl_window.c b/src/wl_window.c index c150b188..4dfde7af 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -735,7 +735,7 @@ static GLFWbool flushDisplay(void) return GLFW_TRUE; } -static void handleEvents(int timeout) +static void handleEvents(double* timeout) { struct pollfd fds[] = { @@ -763,7 +763,7 @@ static void handleEvents(int timeout) return; } - if (poll(fds, 3, timeout) > 0) + if (_glfwPollPOSIX(fds, 3, timeout)) { if (fds[0].revents & POLLIN) { @@ -1168,17 +1168,18 @@ GLFWbool _glfwRawMouseMotionSupportedWayland(void) void _glfwPollEventsWayland(void) { - handleEvents(0); + double timeout = 0.0; + handleEvents(&timeout); } void _glfwWaitEventsWayland(void) { - handleEvents(-1); + handleEvents(NULL); } void _glfwWaitEventsTimeoutWayland(double timeout) { - handleEvents((int) (timeout * 1e3)); + handleEvents(&timeout); } void _glfwPostEmptyEventWayland(void) @@ -1729,7 +1730,7 @@ const char* _glfwGetClipboardStringWayland(void) close(fds[1]); // XXX: this is a huge hack, this function shouldn’t be synchronous! - handleEvents(-1); + handleEvents(NULL); while (1) { diff --git a/src/x11_platform.h b/src/x11_platform.h index 8da3a2e4..956104fa 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -453,6 +453,7 @@ typedef VkResult (APIENTRY *PFN_vkCreateXcbSurfaceKHR)(VkInstance,const VkXcbSur typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice,uint32_t,xcb_connection_t*,xcb_visualid_t); #include "xkb_unicode.h" +#include "posix_poll.h" #define GLFW_X11_WINDOW_STATE _GLFWwindowX11 x11; #define GLFW_X11_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11; diff --git a/src/x11_window.c b/src/x11_window.c index 52cbbcf0..6c329e63 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -27,18 +27,12 @@ // 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 @@ -62,53 +56,6 @@ #define _GLFW_XDND_VERSION 5 -// 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; - } - } -} - // 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 @@ -119,7 +66,7 @@ static GLFWbool waitForX11Event(double* timeout) while (!XPending(_glfw.x11.display)) { - if (!waitForData(&fd, 1, timeout)) + if (!_glfwPollPOSIX(&fd, 1, timeout)) return GLFW_FALSE; } @@ -146,7 +93,7 @@ static GLFWbool waitForAnyEvent(double* timeout) while (!XPending(_glfw.x11.display)) { - if (!waitForData(fds, count, timeout)) + if (!_glfwPollPOSIX(fds, count, timeout)) return GLFW_FALSE; for (int i = 1; i < count; i++) From 7ce1f3e1cf5eb86a17f0c739cfdbcf4094e8e395 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 18/43] Formatting --- 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 4dfde7af..8ca6f7b6 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -1732,7 +1732,7 @@ const char* _glfwGetClipboardStringWayland(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 a32cbf6d4febde6343167f19529b8bde8966670d 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 19/43] 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 --- README.md | 1 + src/wl_window.c | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index d1dcb600..bb9cbf19 100644 --- a/README.md +++ b/README.md @@ -298,6 +298,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) - [POSIX] Removed use of deprecated function `gettimeofday` - [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled - [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072) diff --git a/src/wl_window.c b/src/wl_window.c index 8ca6f7b6..15cc5e5f 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -1185,6 +1185,7 @@ void _glfwWaitEventsTimeoutWayland(double timeout) void _glfwPostEmptyEventWayland(void) { wl_display_sync(_glfw.wl.display); + flushDisplay(); } void _glfwGetCursorPosWayland(_GLFWwindow* window, double* xpos, double* ypos) From 71742d9a27a88d898ea13fd415fae1650dc2772e 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 20/43] 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. --- 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 15cc5e5f..54257b25 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -737,6 +737,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 }, @@ -744,31 +745,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 (!_glfwPollPOSIX(fds, 3, timeout)) + { + wl_display_cancel_read(_glfw.wl.display); + return; + } - if (_glfwPollPOSIX(fds, 3, timeout)) - { 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); @@ -789,6 +797,8 @@ static void handleEvents(double* timeout) _glfwInputTextWayland(_glfw.wl.keyboardFocus, _glfw.wl.keyboardLastScancode); } + + event = GLFW_TRUE; } } @@ -797,11 +807,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); } ////////////////////////////////////////////////////////////////////////// From 1e0c3bca7f6da896828e00f3da606d5e306c3034 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 21/43] Update version of VS used on windows-latest --- .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 249e8d68..7f798851 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -73,8 +73,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 @@ -82,12 +82,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 d78b0a4ead17e30182761b38dbbdfb88b037287b 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 22/43] 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. --- 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 | 18 +++++++++--------- 6 files changed, 17 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index bb9cbf19..8c597048 100644 --- a/README.md +++ b/README.md @@ -274,6 +274,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 dynamic loading of all Wayland libraries - [Wayland] Added support for key names via xkbcommon - [Wayland] Removed support for `wl_shell` (#1443) diff --git a/src/egl_context.c b/src/egl_context.c index 963a59d6..f8850fa2 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -325,7 +325,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", @@ -702,7 +702,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", @@ -721,7 +721,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", @@ -734,7 +734,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 ced9c88f..872612d1 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -259,7 +259,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 43ade8dc..38adabbc 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 f02b1ede..64a4650f 100644 --- a/src/vulkan.c +++ b/src/vulkan.c @@ -63,7 +63,7 @@ GLFWbool _glfwInitVulkan(int mode) _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.1.dylib"); if (!_glfw.vk.handle) _glfw.vk.handle = _glfwLoadLocalVulkanLoaderCocoa(); -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so"); #else _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so.1"); diff --git a/src/x11_init.c b/src/x11_init.c index 203828fc..78735d69 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -603,7 +603,7 @@ static void detectEWMH(void) // static GLFWbool initExtensions(void) { -#if defined(__OpenBSD__) +#if defined(__OpenBSD__) || defined(__NetBSD__) _glfw.x11.vidmode.handle = _glfwPlatformLoadModule("libXxf86vm.so"); #else _glfw.x11.vidmode.handle = _glfwPlatformLoadModule("libXxf86vm.so.1"); @@ -627,7 +627,7 @@ static GLFWbool initExtensions(void) #if defined(__CYGWIN__) _glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi-6.so"); -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) _glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi.so"); #else _glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi.so.6"); @@ -659,7 +659,7 @@ static GLFWbool initExtensions(void) #if defined(__CYGWIN__) _glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr-2.so"); -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) _glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr.so"); #else _glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr.so.2"); @@ -753,7 +753,7 @@ static GLFWbool initExtensions(void) #if defined(__CYGWIN__) _glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor-1.so"); -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) _glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor.so"); #else _glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor.so.1"); @@ -776,7 +776,7 @@ static GLFWbool initExtensions(void) #if defined(__CYGWIN__) _glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama-1.so"); -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) _glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama.so"); #else _glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama.so.1"); @@ -831,7 +831,7 @@ static GLFWbool initExtensions(void) { #if defined(__CYGWIN__) _glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb-1.so"); -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) _glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb.so"); #else _glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb.so.1"); @@ -846,7 +846,7 @@ static GLFWbool initExtensions(void) #if defined(__CYGWIN__) _glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender-1.so"); -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) _glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender.so"); #else _glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender.so.1"); @@ -875,7 +875,7 @@ static GLFWbool initExtensions(void) #if defined(__CYGWIN__) _glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext-6.so"); -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) _glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext.so"); #else _glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext.so.6"); @@ -1254,7 +1254,7 @@ GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform) #if defined(__CYGWIN__) void* module = _glfwPlatformLoadModule("libX11-6.so"); -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) void* module = _glfwPlatformLoadModule("libX11.so"); #else void* module = _glfwPlatformLoadModule("libX11.so.6"); From adc202d2c3182ca6ad8344624941e56d8e0bc493 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 23/43] POSIX: Fix undeclared function warning on Cygwin --- src/posix_poll.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/posix_poll.c b/src/posix_poll.c index 352d9900..676a8a51 100644 --- a/src/posix_poll.c +++ b/src/posix_poll.c @@ -26,9 +26,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 a730acf8e50e7efa70e79e42c511a97f27c97e4d 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 24/43] 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 --- README.md | 2 ++ src/win32_window.c | 29 ++++++++++++++++++++++++----- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8c597048..f4ef3791 100644 --- a/README.md +++ b/README.md @@ -207,6 +207,8 @@ information on what to include when reporting a bug. disconnected (#1615) - [Win32] Bugfix: Key name update modified global key state on Windows 10 1607 and later (#2018) + - [Win32] Bugfix: A window created maximized and undecorated would cover the whole + monitor (#1806) - [Cocoa] Added support for `VK_EXT_metal_surface` (#1619) - [Cocoa] Added locating the Vulkan loader at runtime in an application bundle - [Cocoa] Moved main menu creation to GLFW initialization time (#1649) diff --git a/src/win32_window.c b/src/win32_window.c index b3da6b2a..c8f7782e 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1292,18 +1292,22 @@ static int createNativeWindow(_GLFWwindow* window, window->win32.scaleToMonitor = wndconfig->scaleToMonitor; window->win32.keymenu = wndconfig->win32.keymenu; - // 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; - _glfwGetWindowContentScaleWin32(window, &xscale, &yscale); + _glfwGetHMONITORContentScaleWin32(mh, &xscale, &yscale); if (xscale > 0.f && yscale > 0.f) { @@ -1323,11 +1327,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 367d06deafb00057850796abc02489756a7c6c18 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 25/43] 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. --- README.md | 2 ++ src/win32_window.c | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f4ef3791..cc3e3ccc 100644 --- a/README.md +++ b/README.md @@ -209,6 +209,8 @@ information on what to include when reporting a bug. and later (#2018) - [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] Added support for `VK_EXT_metal_surface` (#1619) - [Cocoa] Added locating the Vulkan loader at runtime in an application bundle - [Cocoa] Moved main menu creation to GLFW initialization time (#1649) diff --git a/src/win32_window.c b/src/win32_window.c index c8f7782e..0f76cf56 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1316,9 +1316,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, @@ -1328,6 +1325,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 1eef3a363e2f64718c82122c5d48bff44c4b2e5d 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 26/43] Fix dependency list for X11 on Cygwin --- docs/compile.dox | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/compile.dox b/docs/compile.dox index 05da99cf..925ab1ab 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 dependencies, move on to @ref compile_generate. From 723f3eb40db27a26c846f0d38ee24af3365ffa96 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 27/43] 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. --- 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 cc3e3ccc..f3bff91d 100644 --- a/README.md +++ b/README.md @@ -211,6 +211,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] Added support for `VK_EXT_metal_surface` (#1619) - [Cocoa] Added locating the Vulkan loader at runtime in an application bundle - [Cocoa] Moved main menu creation to GLFW initialization time (#1649) diff --git a/src/win32_init.c b/src/win32_init.c index 0479afe5..dfaf3d64 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -91,6 +91,8 @@ static GLFWbool loadLibraries(void) _glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "GetDpiForWindow"); _glfw.win32.user32.AdjustWindowRectExForDpi_ = (PFN_AdjustWindowRectExForDpi) _glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "AdjustWindowRectExForDpi"); + _glfw.win32.user32.GetSystemMetricsForDpi_ = (PFN_GetSystemMetricsForDpi) + _glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "GetSystemMetricsForDpi"); _glfw.win32.dinput8.instance = _glfwPlatformLoadModule("dinput8.dll"); if (_glfw.win32.dinput8.instance) diff --git a/src/win32_platform.h b/src/win32_platform.h index a7130377..2e84937a 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -283,12 +283,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*); @@ -471,6 +473,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 0f76cf56..400c50c0 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -484,6 +484,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, @@ -1688,7 +1741,10 @@ void _glfwRestoreWindowWin32(_GLFWwindow* window) void _glfwMaximizeWindowWin32(_GLFWwindow* window) { - ShowWindow(window->win32.handle, SW_MAXIMIZE); + if (IsWindowVisible(window->win32.handle)) + ShowWindow(window->win32.handle, SW_MAXIMIZE); + else + maximizeWindowManually(window); } void _glfwShowWindowWin32(_GLFWwindow* window) From 8ff9ed92b446831e76b434c601b3d1b0d4220c82 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 28/43] Win32: Fix calls to encoding compatibility macros Calls to Unicode specific functions should be made explicit. --- 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 dfaf3d64..dce4e682 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -490,7 +490,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 e45e0798..929a19cf 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -574,7 +574,7 @@ GLFWbool _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 cdee49a9..57b44af3 100644 --- a/src/win32_monitor.c +++ b/src/win32_monitor.c @@ -381,7 +381,7 @@ void _glfwGetMonitorWorkareaWin32(_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 400c50c0..42518934 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -434,7 +434,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, @@ -453,8 +453,8 @@ static void acquireMonitor(_GLFWwindow* window) // HACK: When mouse trails are enabled the cursor becomes invisible when // the OpenGL ICD switches to page flipping - 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); } if (!window->monitor->window) @@ -477,7 +477,7 @@ static void releaseMonitor(_GLFWwindow* window) SetThreadExecutionState(ES_CONTINUOUS); // HACK: Restore mouse trail length saved in acquireMonitor - SystemParametersInfo(SPI_SETMOUSETRAILS, _glfw.win32.mouseTrailSize, 0, 0); + SystemParametersInfoW(SPI_SETMOUSETRAILS, _glfw.win32.mouseTrailSize, 0, 0); } _glfwInputMonitorWindow(window->monitor, NULL); @@ -492,8 +492,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; @@ -1126,7 +1126,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; @@ -1392,7 +1392,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, @@ -1561,8 +1561,8 @@ void _glfwSetWindowIconWin32(_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); @@ -1831,7 +1831,7 @@ void _glfwSetWindowMonitorWin32(_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, @@ -2128,7 +2128,7 @@ void _glfwWaitEventsTimeoutWin32(double timeout) void _glfwPostEmptyEventWin32(void) { - PostMessage(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0); + PostMessageW(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0); } void _glfwGetCursorPosWin32(_GLFWwindow* window, double* xpos, double* ypos) @@ -2445,7 +2445,7 @@ VkResult _glfwCreateWindowSurfaceWin32(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 34573798f4dbbce4bc169ccbfaf9cd189c76ed10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 9 Mar 2022 17:30:06 +0100 Subject: [PATCH 29/43] Win32: Rename Windows 10 macros for clarity This switches the Windows 10 version helper macros to include the version numbers listed in MSDN requirements sections. --- src/win32_init.c | 4 ++-- src/win32_platform.h | 6 ++++-- src/win32_window.c | 28 ++++++++++++++-------------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/win32_init.c b/src/win32_init.c index dce4e682..27527dd1 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -463,7 +463,7 @@ void _glfwUpdateKeyNamesWin32(void) UINT flags = 0; // Avoid modifying the global key state if supported - if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + if (_glfwIsWindows10Version1607OrGreaterWin32()) flags = (1 << 2); memset(_glfw.win32.keynames, 0, sizeof(_glfw.win32.keynames)); @@ -633,7 +633,7 @@ int _glfwInitWin32(void) createKeyTables(); _glfwUpdateKeyNamesWin32(); - if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32()) + if (_glfwIsWindows10Version1703OrGreaterWin32()) SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); else if (IsWindows8Point1OrGreater()) SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); diff --git a/src/win32_platform.h b/src/win32_platform.h index 2e84937a..841cf6a0 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -176,9 +176,11 @@ typedef enum _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WINBLUE), \ LOBYTE(_WIN32_WINNT_WINBLUE), 0) -#define _glfwIsWindows10AnniversaryUpdateOrGreaterWin32() \ +// Windows 10 Anniversary Update +#define _glfwIsWindows10Version1607OrGreaterWin32() \ _glfwIsWindows10BuildOrGreaterWin32(14393) -#define _glfwIsWindows10CreatorsUpdateOrGreaterWin32() \ +// Windows 10 Creators Update +#define _glfwIsWindows10Version1703OrGreaterWin32() \ _glfwIsWindows10BuildOrGreaterWin32(15063) // HACK: Define macros that some xinput.h variants don't diff --git a/src/win32_window.c b/src/win32_window.c index 42518934..4a3bc2e0 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -194,7 +194,7 @@ static void getFullWindowSize(DWORD style, DWORD exStyle, { RECT rect = { 0, 0, contentWidth, contentHeight }; - if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + if (_glfwIsWindows10Version1607OrGreaterWin32()) AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, dpi); else AdjustWindowRectEx(&rect, style, FALSE, exStyle); @@ -211,7 +211,7 @@ static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area) UINT dpi = USER_DEFAULT_SCREEN_DPI; const float ratio = (float) window->numer / (float) window->denom; - if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + if (_glfwIsWindows10Version1607OrGreaterWin32()) dpi = GetDpiForWindow(window->win32.handle); getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), @@ -354,7 +354,7 @@ static void updateWindowStyles(const _GLFWwindow* window) GetClientRect(window->win32.handle, &rect); - if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + if (_glfwIsWindows10Version1607OrGreaterWin32()) { AdjustWindowRectExForDpi(&rect, style, FALSE, getWindowExStyle(window), @@ -513,7 +513,7 @@ static void maximizeWindowManually(_GLFWwindow* window) { const DWORD exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); - if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + if (_glfwIsWindows10Version1607OrGreaterWin32()) { const UINT dpi = GetDpiForWindow(window->win32.handle); AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, dpi); @@ -552,7 +552,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, { case WM_NCCREATE: { - if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + if (_glfwIsWindows10Version1607OrGreaterWin32()) { const CREATESTRUCTW* cs = (const CREATESTRUCTW*) lParam; const _GLFWwndconfig* wndconfig = cs->lpCreateParams; @@ -1098,7 +1098,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, if (window->monitor) break; - if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + if (_glfwIsWindows10Version1607OrGreaterWin32()) dpi = GetDpiForWindow(window->win32.handle); getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), @@ -1173,7 +1173,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, break; // Adjust the window size to keep the content area size constant - if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32()) + if (_glfwIsWindows10Version1703OrGreaterWin32()) { RECT source = {0}, target = {0}; SIZE* size = (SIZE*) lParam; @@ -1204,7 +1204,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, // need it to compensate for non-client area scaling if (!window->monitor && (window->win32.scaleToMonitor || - _glfwIsWindows10CreatorsUpdateOrGreaterWin32())) + _glfwIsWindows10Version1703OrGreaterWin32())) { RECT* suggested = (RECT*) lParam; SetWindowPos(window->win32.handle, HWND_TOP, @@ -1369,7 +1369,7 @@ static int createNativeWindow(_GLFWwindow* window, } } - if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + if (_glfwIsWindows10Version1607OrGreaterWin32()) { AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, GetDpiForWindow(window->win32.handle)); @@ -1592,7 +1592,7 @@ void _glfwSetWindowPosWin32(_GLFWwindow* window, int xpos, int ypos) { RECT rect = { xpos, ypos, xpos, ypos }; - if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + if (_glfwIsWindows10Version1607OrGreaterWin32()) { AdjustWindowRectExForDpi(&rect, getWindowStyle(window), FALSE, getWindowExStyle(window), @@ -1633,7 +1633,7 @@ void _glfwSetWindowSizeWin32(_GLFWwindow* window, int width, int height) { RECT rect = { 0, 0, width, height }; - if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + if (_glfwIsWindows10Version1607OrGreaterWin32()) { AdjustWindowRectExForDpi(&rect, getWindowStyle(window), FALSE, getWindowExStyle(window), @@ -1700,7 +1700,7 @@ void _glfwGetWindowFrameSizeWin32(_GLFWwindow* window, _glfwGetWindowSizeWin32(window, &width, &height); SetRect(&rect, 0, 0, width, height); - if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + if (_glfwIsWindows10Version1607OrGreaterWin32()) { AdjustWindowRectExForDpi(&rect, getWindowStyle(window), FALSE, getWindowExStyle(window), @@ -1789,7 +1789,7 @@ void _glfwSetWindowMonitorWin32(_GLFWwindow* window, { RECT rect = { xpos, ypos, xpos + width, ypos + height }; - if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + if (_glfwIsWindows10Version1607OrGreaterWin32()) { AdjustWindowRectExForDpi(&rect, getWindowStyle(window), FALSE, getWindowExStyle(window), @@ -1860,7 +1860,7 @@ void _glfwSetWindowMonitorWin32(_GLFWwindow* window, else after = HWND_NOTOPMOST; - if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + if (_glfwIsWindows10Version1607OrGreaterWin32()) { AdjustWindowRectExForDpi(&rect, getWindowStyle(window), FALSE, getWindowExStyle(window), From aa803f7de5cc086b1c335161a50016f23c49882a 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 30/43] Win32: Update rationale for reimplementation It is true that plain MinGW lacks this header, but that is not the main reason for reimplementing IsWindowsVersionOrGreater. --- 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 27527dd1..7b468841 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -513,7 +513,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 841cf6a0..0958b076 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 IsWindowsVistaOrGreater() \ _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_VISTA), \ LOBYTE(_WIN32_WINNT_VISTA), 0) From 8f9ff8503e0a3dc143c1bdb19327dd29c3ee2d57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 9 Mar 2022 23:06:13 +0100 Subject: [PATCH 31/43] Formatting --- src/win32_window.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/win32_window.c b/src/win32_window.c index 4a3bc2e0..c6351a91 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -97,8 +97,7 @@ static const GLFWimage* chooseImage(int count, const GLFWimage* images, // Creates an RGBA icon or cursor // -static HICON createIcon(const GLFWimage* image, - int xhot, int yhot, GLFWbool icon) +static HICON createIcon(const GLFWimage* image, int xhot, int yhot, GLFWbool icon) { int i; HDC dc; @@ -539,8 +538,7 @@ static void maximizeWindowManually(_GLFWwindow* window) // Window callback function (handles window messages) // -static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, - WPARAM wParam, LPARAM lParam) +static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { _GLFWwindow* window = GetPropW(hWnd, L"GLFW"); if (!window) @@ -1538,8 +1536,7 @@ void _glfwSetWindowTitleWin32(_GLFWwindow* window, const char* title) _glfw_free(wideTitle); } -void _glfwSetWindowIconWin32(_GLFWwindow* window, - int count, const GLFWimage* images) +void _glfwSetWindowIconWin32(_GLFWwindow* window, int count, const GLFWimage* images) { HICON bigIcon = NULL, smallIcon = NULL; @@ -1652,8 +1649,8 @@ void _glfwSetWindowSizeWin32(_GLFWwindow* window, int width, int height) } void _glfwSetWindowSizeLimitsWin32(_GLFWwindow* window, - int minwidth, int minheight, - int maxwidth, int maxheight) + int minwidth, int minheight, + int maxwidth, int maxheight) { RECT area; @@ -1691,8 +1688,8 @@ void _glfwGetFramebufferSizeWin32(_GLFWwindow* window, int* width, int* height) } void _glfwGetWindowFrameSizeWin32(_GLFWwindow* window, - int* left, int* top, - int* right, int* bottom) + int* left, int* top, + int* right, int* bottom) { RECT rect; int width, height; @@ -2189,8 +2186,8 @@ int _glfwGetKeyScancodeWin32(int key) } int _glfwCreateCursorWin32(_GLFWcursor* cursor, - const GLFWimage* image, - int xhot, int yhot) + const GLFWimage* image, + int xhot, int yhot) { cursor->win32.handle = (HCURSOR) createIcon(image, xhot, yhot, GLFW_FALSE); if (!cursor->win32.handle) From b54fb0af10bb0167df67fece984350e66bf569ce Mon Sep 17 00:00:00 2001 From: Slemmie Date: Fri, 20 Aug 2021 06:41:59 +0200 Subject: [PATCH 32/43] X11: Fix undefined behavior in bit shift of int Closes #1951 --- 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 6c329e63..dcde3443 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1267,7 +1267,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 1461c59aa2426b25503102e62bc8f4b65e079c5f 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 33/43] Update changelog and add credit Related to #1951 --- CONTRIBUTORS.md | 1 + README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index f20422ec..406ebd02 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -188,6 +188,7 @@ video tutorials. - Joao da Silva - Daniel Sieger - Daniel Skorupski + - Slemmie - Anthony Smith - Bradley Smith - Cliff Smolinsky diff --git a/README.md b/README.md index f3bff91d..7560284d 100644 --- a/README.md +++ b/README.md @@ -280,6 +280,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 dynamic loading of all Wayland libraries - [Wayland] Added support for key names via xkbcommon - [Wayland] Removed support for `wl_shell` (#1443) From 46950a5e61ae6febb6dd554aea212f9130927b98 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 34/43] Fix button field names in input guide Fixes #2056 --- CONTRIBUTORS.md | 1 + docs/input.dox | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 406ebd02..88645126 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -30,6 +30,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 dcd8f670..faa94cd4 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -821,7 +821,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`. From 9cc252a406b79c31ab82648a21b715e2d3fc7ece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 13 Mar 2022 15:57:56 +0100 Subject: [PATCH 35/43] Revert ad01c1b614868c3cbc79306aa6a19c9fc06f34a6 This change broke key names for dead keys, because that depends on the effect on the global state of simulating two key presses. Issue found by CTest tests. Reverts #2018 --- README.md | 2 -- src/win32_init.c | 9 ++------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 7560284d..715a5248 100644 --- a/README.md +++ b/README.md @@ -205,8 +205,6 @@ information on what to include when reporting a bug. - [Win32] Bugfix: Content scale queries could fail silently (#1615) - [Win32] Bugfix: Content scales could have garbage values if monitor was recently disconnected (#1615) - - [Win32] Bugfix: Key name update modified global key state on Windows 10 1607 - and later (#2018) - [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 diff --git a/src/win32_init.c b/src/win32_init.c index 7b468841..ee3dad54 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -460,11 +460,6 @@ void _glfwUpdateKeyNamesWin32(void) { int key; BYTE state[256] = {0}; - UINT flags = 0; - - // Avoid modifying the global key state if supported - if (_glfwIsWindows10Version1607OrGreaterWin32()) - flags = (1 << 2); memset(_glfw.win32.keynames, 0, sizeof(_glfw.win32.keynames)); @@ -494,13 +489,13 @@ void _glfwUpdateKeyNamesWin32(void) length = ToUnicode(vk, scancode, state, chars, sizeof(chars) / sizeof(WCHAR), - flags); + 0); if (length == -1) { length = ToUnicode(vk, scancode, state, chars, sizeof(chars) / sizeof(WCHAR), - flags); + 0); } if (length < 1) From 3ee5031fd7dcac5ecb7387d3dd73195f03e87398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 14 Mar 2022 16:01:34 +0100 Subject: [PATCH 36/43] Add shared min and max functions for int --- src/init.c | 10 ++++++++++ src/internal.h | 2 ++ src/null_window.c | 16 ++++++++-------- src/win32_window.c | 9 +++------ src/wl_init.c | 9 ++------- src/wl_window.c | 6 +----- 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/init.c b/src/init.c index 80f424a8..9f0316ac 100644 --- a/src/init.c +++ b/src/init.c @@ -179,6 +179,16 @@ char* _glfw_strdup(const char* source) return result; } +int _glfw_min(int a, int b) +{ + return a < b ? a : b; +} + +int _glfw_max(int a, int b) +{ + return a > b ? a : b; +} + float _glfw_fminf(float a, float b) { if (a != a) diff --git a/src/internal.h b/src/internal.h index f8548fa3..b7dc13a0 100644 --- a/src/internal.h +++ b/src/internal.h @@ -998,6 +998,8 @@ const char* _glfwGetVulkanResultString(VkResult result); size_t _glfwEncodeUTF8(char* s, uint32_t codepoint); char* _glfw_strdup(const char* source); +int _glfw_min(int a, int b); +int _glfw_max(int a, int b); float _glfw_fminf(float a, float b); float _glfw_fmaxf(float a, float b); diff --git a/src/null_window.c b/src/null_window.c index 710d4c9c..7e87b9da 100644 --- a/src/null_window.c +++ b/src/null_window.c @@ -39,15 +39,15 @@ static void applySizeLimits(_GLFWwindow* window, int* width, int* height) *height = (int) (*width / ratio); } - if (window->minwidth != GLFW_DONT_CARE && *width < window->minwidth) - *width = window->minwidth; - else if (window->maxwidth != GLFW_DONT_CARE && *width > window->maxwidth) - *width = window->maxwidth; + if (window->minwidth != GLFW_DONT_CARE) + *width = _glfw_max(*width, window->minwidth); + else if (window->maxwidth != GLFW_DONT_CARE) + *width = _glfw_min(*width, window->maxwidth); - if (window->minheight != GLFW_DONT_CARE && *height < window->minheight) - *height = window->minheight; - else if (window->maxheight != GLFW_DONT_CARE && *height > window->maxheight) - *height = window->maxheight; + if (window->minheight != GLFW_DONT_CARE) + *height = _glfw_min(*height, window->minheight); + else if (window->maxheight != GLFW_DONT_CARE) + *height = _glfw_max(*height, window->maxheight); } static void fitToMonitor(_GLFWwindow* window) diff --git a/src/win32_window.c b/src/win32_window.c index c6351a91..5448eddc 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -498,10 +498,8 @@ static void maximizeWindowManually(_GLFWwindow* window) 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; + rect.right = _glfw_min(rect.right, rect.left + window->maxwidth); + rect.bottom = _glfw_min(rect.bottom, rect.top + window->maxheight); } style = GetWindowLongW(window->win32.handle, GWL_STYLE); @@ -524,8 +522,7 @@ static void maximizeWindowManually(_GLFWwindow* window) OffsetRect(&rect, 0, GetSystemMetrics(SM_CYCAPTION)); } - if (rect.bottom > mi.rcWork.bottom) - rect.bottom = mi.rcWork.bottom; + rect.bottom = _glfw_min(rect.bottom, mi.rcWork.bottom); } SetWindowPos(window->win32.handle, HWND_TOP, diff --git a/src/wl_init.c b/src/wl_init.c index e4ae6666..f02c6320 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -57,11 +57,6 @@ #include "wayland-idle-inhibit-unstable-v1-client-protocol-code.h" -static inline int min(int n1, int n2) -{ - return n1 < n2 ? n1 : n2; -} - static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface, int* which) { @@ -788,7 +783,7 @@ static void registryHandleGlobal(void* data, { if (strcmp(interface, "wl_compositor") == 0) { - _glfw.wl.compositorVersion = min(3, version); + _glfw.wl.compositorVersion = _glfw_min(3, version); _glfw.wl.compositor = wl_registry_bind(registry, name, &wl_compositor_interface, _glfw.wl.compositorVersion); @@ -811,7 +806,7 @@ static void registryHandleGlobal(void* data, { if (!_glfw.wl.seat) { - _glfw.wl.seatVersion = min(4, version); + _glfw.wl.seatVersion = _glfw_min(4, version); _glfw.wl.seat = wl_registry_bind(registry, name, &wl_seat_interface, _glfw.wl.seatVersion); diff --git a/src/wl_window.c b/src/wl_window.c index 54257b25..8c47d710 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -353,11 +353,7 @@ static void checkScaleChange(_GLFWwindow* window) int maxScale = 1; for (int i = 0; i < window->wl.monitorsCount; i++) - { - const int scale = window->wl.monitors[i]->wl.scale; - if (maxScale < scale) - maxScale = scale; - } + maxScale = _glfw_max(window->wl.monitors[i]->wl.scale, maxScale); // Only change the framebuffer size if the scale changed. if (window->wl.scale != maxScale) From 535c3ce63240ee91f998219b35dc82abef545c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 15 Mar 2022 17:51:57 +0100 Subject: [PATCH 37/43] Fix GLAPIENTRY redefinition warning On a Unix system, if you define GLFW_INCLUDE_NONE and GLFW_EXPOSE_NATIVE_GLX, then include glfw3.h and glfw3native.h, you will get a redefinition warning for GLAPIENTRY. The glfw3.h header defines GLAPIENTRY as a service for OpenGL related headers that assume it's already defined. However, glx.h includes gl.h, which defines GLAPIENTRY unconditionally. If not for Hyrum's law, the better solution would have been not to define GLAPIENTRY if GLFW_INCLUDE_NONE is defined. Fixes #2010 --- include/GLFW/glfw3native.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/GLFW/glfw3native.h b/include/GLFW/glfw3native.h index 41b2f86b..da4b7572 100644 --- a/include/GLFW/glfw3native.h +++ b/include/GLFW/glfw3native.h @@ -111,12 +111,22 @@ extern "C" { /* NSGL is declared by Cocoa.h */ #endif #if defined(GLFW_EXPOSE_NATIVE_GLX) + /* This is a workaround for the fact that glfw3.h defines GLAPIENTRY because by + * default it also acts as an OpenGL header + * However, glx.h will include gl.h, which will define it unconditionally + */ + #undef GLAPIENTRY #include #endif #if defined(GLFW_EXPOSE_NATIVE_EGL) #include #endif #if defined(GLFW_EXPOSE_NATIVE_OSMESA) + /* This is a workaround for the fact that glfw3.h defines GLAPIENTRY because by + * default it also acts as an OpenGL header + * However, osmesa.h will include gl.h, which will define it unconditionally + */ + #undef GLAPIENTRY #include #endif From add0521efb1fc0e95082716748b7aad837753fba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 15 Mar 2022 17:59:57 +0100 Subject: [PATCH 38/43] Fix accidental C99 in C89 header --- include/GLFW/glfw3native.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/GLFW/glfw3native.h b/include/GLFW/glfw3native.h index da4b7572..11fee09d 100644 --- a/include/GLFW/glfw3native.h +++ b/include/GLFW/glfw3native.h @@ -82,9 +82,10 @@ extern "C" { *************************************************************************/ #if defined(GLFW_EXPOSE_NATIVE_WIN32) || defined(GLFW_EXPOSE_NATIVE_WGL) - // This is a workaround for the fact that glfw3.h needs to export APIENTRY (for - // example to allow applications to correctly declare a GL_KHR_debug callback) - // but windows.h assumes no one will define APIENTRY before it does + /* This is a workaround for the fact that glfw3.h needs to export APIENTRY (for + * example to allow applications to correctly declare a GL_KHR_debug callback) + * but windows.h assumes no one will define APIENTRY before it does + */ #if defined(GLFW_APIENTRY_DEFINED) #undef APIENTRY #undef GLFW_APIENTRY_DEFINED From 03cfe957e739e41cdfd66b554c076b5b31f48c1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 15 Mar 2022 19:12:29 +0100 Subject: [PATCH 39/43] Win32: Fix scancode and key for Alt+PrtSc events Alt+PrtSc emits a different scancode than just PrtSc. Since the GLFW API assumes each key corresponds to only one scancode, this cannot be added to the keycodes array. Instead we replace the scancode at the point of entry. Fixes #1993 --- CONTRIBUTORS.md | 1 + README.md | 2 ++ src/win32_window.c | 4 ++++ 3 files changed, 7 insertions(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 88645126..bb70c1f5 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -70,6 +70,7 @@ video tutorials. - Ryan C. Gordon - Stephen Gowen - Kovid Goyal + - Kevin Grandemange - Eloi Marín Gratacós - Stefan Gustavson - Andrew Gutekanst diff --git a/README.md b/README.md index 715a5248..e81997ba 100644 --- a/README.md +++ b/README.md @@ -210,6 +210,8 @@ information on what to include when reporting a bug. - [Win32] Bugfix: The default restored window position was lost when creating a maximized window - [Win32] Bugfix: `glfwMaximizeWindow` would make a hidden window visible + - [Win32] Bugfix: `Alt+PrtSc` would emit `GLFW_KEY_UNKNOWN` and a different + scancode than `PrtSc` (#1993) - [Cocoa] Added support for `VK_EXT_metal_surface` (#1619) - [Cocoa] Added locating the Vulkan loader at runtime in an application bundle - [Cocoa] Moved main menu creation to GLFW initialization time (#1649) diff --git a/src/win32_window.c b/src/win32_window.c index 5448eddc..1d207d8b 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -752,6 +752,10 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l scancode = MapVirtualKeyW((UINT) wParam, MAPVK_VK_TO_VSC); } + // HACK: Alt+PrtSc has a different scancode than just PrtSc + if (scancode == 0x54) + scancode = 0x137; + key = _glfw.win32.keycodes[scancode]; // The Ctrl keys require special handling From 8d9231fe5ec82c3a0a7bddfcd3a409759a7a45d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 15 Mar 2022 19:22:21 +0100 Subject: [PATCH 40/43] Win32: Fix glfwGetKeyScancode for GLFW_KEY_PAUSE The bug described in 03cfe957e739e41cdfd66b554c076b5b31f48c1e was already present for another key where modifiers changes its scancode. Related to #1993 --- README.md | 2 ++ src/win32_init.c | 1 - src/win32_window.c | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e81997ba..d931de54 100644 --- a/README.md +++ b/README.md @@ -212,6 +212,8 @@ information on what to include when reporting a bug. - [Win32] Bugfix: `glfwMaximizeWindow` would make a hidden window visible - [Win32] Bugfix: `Alt+PrtSc` would emit `GLFW_KEY_UNKNOWN` and a different scancode than `PrtSc` (#1993) + - [Win32] Bugfix: `GLFW_KEY_PAUSE` scancode from `glfwGetKeyScancode` did not + match event scancode (#1993) - [Cocoa] Added support for `VK_EXT_metal_surface` (#1619) - [Cocoa] Added locating the Vulkan loader at runtime in an application bundle - [Cocoa] Moved main menu creation to GLFW initialization time (#1649) diff --git a/src/win32_init.c b/src/win32_init.c index ee3dad54..31406401 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -253,7 +253,6 @@ static void createKeyTables(void) _glfw.win32.keycodes[0x151] = GLFW_KEY_PAGE_DOWN; _glfw.win32.keycodes[0x149] = GLFW_KEY_PAGE_UP; _glfw.win32.keycodes[0x045] = GLFW_KEY_PAUSE; - _glfw.win32.keycodes[0x146] = GLFW_KEY_PAUSE; _glfw.win32.keycodes[0x039] = GLFW_KEY_SPACE; _glfw.win32.keycodes[0x00F] = GLFW_KEY_TAB; _glfw.win32.keycodes[0x03A] = GLFW_KEY_CAPS_LOCK; diff --git a/src/win32_window.c b/src/win32_window.c index 1d207d8b..37e42c3d 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -756,6 +756,10 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l if (scancode == 0x54) scancode = 0x137; + // HACK: Ctrl+Pause has a different scancode than just Pause + if (scancode == 0x146) + scancode = 0x45; + key = _glfw.win32.keycodes[scancode]; // The Ctrl keys require special handling From 66a4882eb14344115e9cda9f8c0f0c5d0362ca6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 15 Mar 2022 21:22:49 +0100 Subject: [PATCH 41/43] Add checks for some invalid values to public API There were no checks for invalid values or asserts for all invalid NULL pointers to glfwSetWindowIcon or glfwCreateCursor. Fixes #1862 --- CONTRIBUTORS.md | 1 + include/GLFW/glfw3.h | 7 ++++--- src/input.c | 7 +++++++ src/window.c | 21 +++++++++++++++++++++ 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index bb70c1f5..577da149 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -84,6 +84,7 @@ video tutorials. - Paul Holden - Warren Hu - Charles Huber + - Brent Huisman - illustris - InKryption - IntellectualKitty diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 72d5fa71..3f320065 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -3258,7 +3258,8 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title); * count is zero. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks). + * GLFW_INVALID_VALUE, @ref GLFW_PLATFORM_ERROR and @ref + * GLFW_FEATURE_UNAVAILABLE (see remarks). * * @pointer_lifetime The specified image data is copied before this function * returns. @@ -4892,8 +4893,8 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); * @return The handle of the created cursor, or `NULL` if an * [error](@ref error_handling) occurred. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. * * @pointer_lifetime The specified image data is copied before this function * returns. diff --git a/src/input.c b/src/input.c index 6a2c3e1d..90ee5273 100644 --- a/src/input.c +++ b/src/input.c @@ -764,9 +764,16 @@ GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot) _GLFWcursor* cursor; assert(image != NULL); + assert(image->pixels != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + if (image->width <= 0 || image->height <= 0) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid image dimensions for cursor"); + return NULL; + } + cursor = _glfw_calloc(1, sizeof(_GLFWcursor)); cursor->next = _glfw.cursorListHead; _glfw.cursorListHead = cursor; diff --git a/src/window.c b/src/window.c index a65ed760..a24feb60 100644 --- a/src/window.c +++ b/src/window.c @@ -514,12 +514,33 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* handle, const char* title) GLFWAPI void glfwSetWindowIcon(GLFWwindow* handle, int count, const GLFWimage* images) { + int i; _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); assert(count >= 0); assert(count == 0 || images != NULL); _GLFW_REQUIRE_INIT(); + + if (count < 0) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid image count for window icon"); + return; + } + + for (i = 0; i < count; i++) + { + assert(images[i].pixels != NULL); + + if (images[i].width <= 0 || images[i].height <= 0) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid image dimensions for window icon"); + return; + } + } + _glfw.platform.setWindowIcon(window, count, images); } From 07a5518c3e42f4412a5d9fa8620950d8f5041e28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 17 Mar 2022 23:54:39 +0100 Subject: [PATCH 42/43] Win32: Fix using executable instance and not ours Operations that take an instance handle should be passed the handle of whatever module we are inside instead of blindly passing the handle of the executable. This commit makes GLFW retrieve its own instance on initialization. This makes the most difference for window classes, which are per-instance. Using the executable instance led to name conflicts if there were several copies of GLFW in a single process. Note that having this is still a bad idea unless you know what things to avoid, and those things are mostly platform-specific. This is partly because the library wasn't designed for it and partly because it needs to save, update and restore various per-process and per-session settings like current context and video mode. However, multiple simultaneous copies of GLFW in a single Win32 process should now at least initialize, like is already the case on other platforms. Fixes #469 Fixes #1296 Fixes #1395 Related to #927 Related to #1885 --- CONTRIBUTORS.md | 2 ++ README.md | 1 + src/win32_init.c | 12 +++++++++++- src/win32_joystick.c | 2 +- src/win32_platform.h | 1 + src/win32_window.c | 8 ++++---- 6 files changed, 20 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 577da149..4011336f 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -90,6 +90,7 @@ video tutorials. - IntellectualKitty - Aaron Jacobs - Erik S. V. Jansson + - jjYBdx4IL - Toni Jovanoski - Arseny Kapoulkine - Cem Karan @@ -210,6 +211,7 @@ video tutorials. - Jared Tiala - Sergey Tikhomirov - Arthur Tombs + - TronicLabs - Ioannis Tsakpinis - Samuli Tuomola - Matthew Turner diff --git a/README.md b/README.md index d931de54..d2499596 100644 --- a/README.md +++ b/README.md @@ -214,6 +214,7 @@ information on what to include when reporting a bug. scancode than `PrtSc` (#1993) - [Win32] Bugfix: `GLFW_KEY_PAUSE` scancode from `glfwGetKeyScancode` did not match event scancode (#1993) + - [Win32] Bugfix: Instance-local operations used executable instance (#469,#1296,#1395) - [Cocoa] Added support for `VK_EXT_metal_surface` (#1619) - [Cocoa] Added locating the Vulkan loader at runtime in an application bundle - [Cocoa] Moved main menu creation to GLFW initialization time (#1649) diff --git a/src/win32_init.c b/src/win32_init.c index 31406401..7aefc78a 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -71,6 +71,16 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) // static GLFWbool loadLibraries(void) { + if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (const WCHAR*) &_glfw, + (HMODULE*) &_glfw.win32.instance)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to retrieve own module handle"); + return GLFW_FALSE; + } + _glfw.win32.user32.instance = _glfwPlatformLoadModule("user32.dll"); if (!_glfw.win32.user32.instance) { @@ -334,7 +344,7 @@ static GLFWbool createHelperWindow(void) WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 1, 1, NULL, NULL, - GetModuleHandleW(NULL), + _glfw.win32.instance, NULL); if (!_glfw.win32.helperWindowHandle) diff --git a/src/win32_joystick.c b/src/win32_joystick.c index 929a19cf..a6fe8e8d 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -574,7 +574,7 @@ GLFWbool _glfwInitJoysticksWin32(void) { if (_glfw.win32.dinput8.instance) { - if (FAILED(DirectInput8Create(GetModuleHandleW(NULL), + if (FAILED(DirectInput8Create(_glfw.win32.instance, DIRECTINPUT_VERSION, &IID_IDirectInput8W, (void**) &_glfw.win32.dinput8.api, diff --git a/src/win32_platform.h b/src/win32_platform.h index 0958b076..c3dc262f 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -442,6 +442,7 @@ typedef struct _GLFWwindowWin32 // typedef struct _GLFWlibraryWin32 { + HINSTANCE instance; HWND helperWindowHandle; HDEVNOTIFY deviceNotificationHandle; int acquiredMonitorCount; diff --git a/src/win32_window.c b/src/win32_window.c index 37e42c3d..5f4dd7d2 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1321,7 +1321,7 @@ static int createNativeWindow(_GLFWwindow* window, fullWidth, fullHeight, NULL, // No parent window NULL, // No window menu - GetModuleHandleW(NULL), + _glfw.win32.instance, (LPVOID) wndconfig); _glfw_free(wideTitle); @@ -1429,7 +1429,7 @@ GLFWbool _glfwRegisterWindowClassWin32(void) wc.cbSize = sizeof(wc); wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wc.lpfnWndProc = (WNDPROC) windowProc; - wc.hInstance = GetModuleHandleW(NULL); + wc.hInstance = _glfw.win32.instance; wc.hCursor = LoadCursorW(NULL, IDC_ARROW); wc.lpszClassName = _GLFW_WNDCLASSNAME; @@ -1459,7 +1459,7 @@ GLFWbool _glfwRegisterWindowClassWin32(void) // void _glfwUnregisterWindowClassWin32(void) { - UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL)); + UnregisterClassW(_GLFW_WNDCLASSNAME, _glfw.win32.instance); } int _glfwCreateWindowWin32(_GLFWwindow* window, @@ -2447,7 +2447,7 @@ VkResult _glfwCreateWindowSurfaceWin32(VkInstance instance, memset(&sci, 0, sizeof(sci)); sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; - sci.hinstance = GetModuleHandleW(NULL); + sci.hinstance = _glfw.win32.instance; sci.hwnd = window->win32.handle; err = vkCreateWin32SurfaceKHR(instance, &sci, allocator, surface); From 955fbd9d265fa95adf9cb94896eb9a516aa50420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 18 Mar 2022 00:31:34 +0100 Subject: [PATCH 43/43] Cocoa: Fix AirPlay causing harmless init error Emitting an error for one specific type of failure in retrieving the correct name for a display is not very useful, especially when initialization is otherwise unaffected. There should be a path for information like that but this isn't it. Fixes #1791 --- CONTRIBUTORS.md | 1 + README.md | 1 + src/cocoa_monitor.m | 4 ---- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 4011336f..cc77ff13 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -89,6 +89,7 @@ video tutorials. - InKryption - IntellectualKitty - Aaron Jacobs + - JannikGM - Erik S. V. Jansson - jjYBdx4IL - Toni Jovanoski diff --git a/README.md b/README.md index d2499596..13e3e087 100644 --- a/README.md +++ b/README.md @@ -245,6 +245,7 @@ information on what to include when reporting a bug. a fraction of a second (#1962) - [Cocoa] Bugfix: `kIOMasterPortDefault` was deprecated in macOS 12.0 (#1980) - [Cocoa] Bugfix: `kUTTypeURL` was deprecated in macOS 12.0 (#2003) + - [Cocoa] Bugfix: A connected Apple AirPlay would emit a useless error (#1791) - [X11] Bugfix: The CMake files did not check for the XInput headers (#1480) - [X11] Bugfix: Key names were not updated when the keyboard layout changed (#1462,#1528) diff --git a/src/cocoa_monitor.m b/src/cocoa_monitor.m index 70c75aa3..64d9eb2c 100644 --- a/src/cocoa_monitor.m +++ b/src/cocoa_monitor.m @@ -98,11 +98,7 @@ static char* getMonitorName(CGDirectDisplayID displayID, NSScreen* screen) IOObjectRelease(it); if (!service) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Cocoa: Failed to find service port for display"); return _glfw_strdup("Display"); - } CFDictionaryRef names = CFDictionaryGetValue(info, CFSTR(kDisplayProductName));