Compare commits

...

4 Commits

Author SHA1 Message Date
Peru S
a4ece81b20
Merge 959f13c1bd into 63a7e8b7f8 2025-08-20 21:24:38 +02:00
Camilla Löwy
63a7e8b7f8 Add and update Wayland-specific notes in docs
Fixes #2746
2025-08-20 20:13:07 +02:00
Peru S
959f13c1bd Add to CONTRIBUTORS.md and README.md 2025-07-29 12:59:07 -07:00
Peru S
2fded1aab2 Fix windowProc when SetPropW() fails silently
**Issue**

In some cases, on Windows, `SetPropW` returns `FALSE`.
glfw currently silently ignores the result.
This means that the message pump `windowProc` fails to work (does not receive keyboard events for example). Drawing is fine though as it's a different GLFW mechanism.

I had this failure frequently infrequently and it was frustrating to deal with (just have to rerun the program a few times and hope `SetPropW` doesn't return `FALSE`). So sending this fix in case others are facing the issue on Windows.

**Fix**

On Windows+GLFW, `windowProc` will fallback to looking up the GLFW window list (just like `PollEvents` does).
Also added the error code to `_glfwInputError` message to aid debugging in the future.

My suggestion is to get rid of `SetPropW`/`GetPropW` as it is a string-based Windows API (slow/fragile) - we already have the lightweight linked list, might as well just use it always - also it's usually just the one or two windows we deal with.

- [x] Verified on Windows - message pump is stable with this fix (once I was able to repro this issue).
2025-07-29 12:53:19 -07:00
7 changed files with 70 additions and 24 deletions

View File

@ -55,6 +55,7 @@ video tutorials.
- Jason Daly - Jason Daly
- danhambleton - danhambleton
- Jarrod Davis - Jarrod Davis
- decce
- Olivier Delannoy - Olivier Delannoy
- Paul R. Deppe - Paul R. Deppe
- Michael Dickens - Michael Dickens
@ -233,6 +234,7 @@ video tutorials.
- Jan Schürkamp - Jan Schürkamp
- Christian Sdunek - Christian Sdunek
- Matt Sealey - Matt Sealey
- Perumaal Shanmugam
- Steve Sexton - Steve Sexton
- Arkady Shapkin - Arkady Shapkin
- Mingjie Shen - Mingjie Shen

View File

@ -148,6 +148,7 @@ information on what to include when reporting a bug.
- [Null] Added EGL context creation on Mesa via `EGL_MESA_platform_surfaceless` - [Null] Added EGL context creation on Mesa via `EGL_MESA_platform_surfaceless`
- [EGL] Allowed native access on Wayland with `GLFW_CONTEXT_CREATION_API` set to - [EGL] Allowed native access on Wayland with `GLFW_CONTEXT_CREATION_API` set to
`GLFW_NATIVE_CONTEXT_API` (#2518) `GLFW_NATIVE_CONTEXT_API` (#2518)
- [Win32] Bugfix: Fix `windowProc` to work when `SetPropW` fails silently
## Contact ## Contact

View File

@ -255,3 +255,7 @@ hardware gamma correction, which today is typically an approximation of sRGB
gamma. This means that setting a perfectly linear ramp, or gamma 1.0, will gamma. This means that setting a perfectly linear ramp, or gamma 1.0, will
produce the default (usually sRGB-like) behavior. produce the default (usually sRGB-like) behavior.
@note @wayland An application cannot read or modify the monitor gamma ramp. The
@ref glfwGetGammaRamp, @ref glfwSetGammaRamp and @ref glfwSetGamma functions
emit @ref GLFW_FEATURE_UNAVAILABLE.

View File

@ -893,6 +893,12 @@ int xpos, ypos;
glfwGetWindowPos(window, &xpos, &ypos); glfwGetWindowPos(window, &xpos, &ypos);
``` ```
@note @wayland An applications cannot know the positions of its windows or
whether one has been moved. The @ref GLFW_POSITION_X and @ref GLFW_POSITION_Y
window hints are ignored. The @ref glfwGetWindowPos and @ref glfwSetWindowPos
functions emit @ref GLFW_FEATURE_UNAVAILABLE. The window position callback will
not be called.
### Window title {#window_title} ### Window title {#window_title}
@ -1038,6 +1044,12 @@ You can also get the current iconification state with @ref glfwGetWindowAttrib.
int iconified = glfwGetWindowAttrib(window, GLFW_ICONIFIED); int iconified = glfwGetWindowAttrib(window, GLFW_ICONIFIED);
``` ```
@note @wayland An application cannot know if any of its windows have been
iconified or restore one from iconification. The @ref glfwRestoreWindow
function can only restore windows from maximization and the iconify callback
will not be called. The [GLFW_ICONIFIED](@ref GLFW_ICONIFIED_attrib) attribute
will be false. The @ref glfwIconifyWindow function works normally.
### Window maximization {#window_maximize} ### Window maximization {#window_maximize}

View File

@ -2915,8 +2915,8 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref GLFW_INVALID_VALUE, * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref GLFW_INVALID_VALUE,
* @ref GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks). * @ref GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
* *
* @remark @wayland Gamma handling is a privileged protocol, this function * @remark @wayland Monitor gamma is a privileged protocol, so this function
* will thus never be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE. * cannot be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE.
* *
* @thread_safety This function must only be called from the main thread. * @thread_safety This function must only be called from the main thread.
* *
@ -2939,8 +2939,8 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref GLFW_PLATFORM_ERROR * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref GLFW_PLATFORM_ERROR
* and @ref GLFW_FEATURE_UNAVAILABLE (see remarks). * and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
* *
* @remark @wayland Gamma handling is a privileged protocol, this function * @remark @wayland Monitor gamma is a privileged protocol, so this function
* will thus never be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE while * cannot be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE while
* returning `NULL`. * returning `NULL`.
* *
* @pointer_lifetime The returned structure and its arrays are allocated and * @pointer_lifetime The returned structure and its arrays are allocated and
@ -2983,8 +2983,8 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor);
* *
* @remark @win32 The gamma ramp size must be 256. * @remark @win32 The gamma ramp size must be 256.
* *
* @remark @wayland Gamma handling is a privileged protocol, this function * @remark @wayland Monitor gamma is a privileged protocol, so this function
* will thus never be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE. * cannot be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE.
* *
* @pointer_lifetime The specified gamma ramp is copied before this function * @pointer_lifetime The specified gamma ramp is copied before this function
* returns. * returns.
@ -3430,8 +3430,8 @@ GLFWAPI void glfwSetWindowIcon(GLFWwindow* window, int count, const GLFWimage* i
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
* GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks). * GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
* *
* @remark @wayland There is no way for an application to retrieve the global * @remark @wayland Window positions are not currently part of any common
* position of its windows. This function will emit @ref * Wayland protocol, so this function cannot be implemented and will emit @ref
* GLFW_FEATURE_UNAVAILABLE. * GLFW_FEATURE_UNAVAILABLE.
* *
* @thread_safety This function must only be called from the main thread. * @thread_safety This function must only be called from the main thread.
@ -3464,8 +3464,8 @@ GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
* GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks). * GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
* *
* @remark @wayland There is no way for an application to set the global * @remark @wayland Window positions are not currently part of any common
* position of its windows. This function will emit @ref * Wayland protocol, so this function cannot be implemented and will emit @ref
* GLFW_FEATURE_UNAVAILABLE. * GLFW_FEATURE_UNAVAILABLE.
* *
* @thread_safety This function must only be called from the main thread. * @thread_safety This function must only be called from the main thread.
@ -3807,10 +3807,6 @@ GLFWAPI void glfwSetWindowOpacity(GLFWwindow* window, float opacity);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR. * GLFW_PLATFORM_ERROR.
* *
* @remark @wayland Once a window is iconified, @ref glfwRestoreWindow wont
* be able to restore it. This is a design decision of the xdg-shell
* protocol.
*
* @thread_safety This function must only be called from the main thread. * @thread_safety This function must only be called from the main thread.
* *
* @sa @ref window_iconify * @sa @ref window_iconify
@ -3838,6 +3834,10 @@ GLFWAPI void glfwIconifyWindow(GLFWwindow* window);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR. * GLFW_PLATFORM_ERROR.
* *
* @remark @wayland Restoring a window from maximization is not currently part
* of any common Wayland protocol, so this function can only restore windows
* from maximization.
*
* @thread_safety This function must only be called from the main thread. * @thread_safety This function must only be called from the main thread.
* *
* @sa @ref window_iconify * @sa @ref window_iconify
@ -4058,8 +4058,8 @@ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window);
* affected by any resizing or mode switching, although you may need to update * affected by any resizing or mode switching, although you may need to update
* your viewport if the framebuffer size has changed. * your viewport if the framebuffer size has changed.
* *
* @remark @wayland The desired window position is ignored, as there is no way * @remark @wayland Window positions are not currently part of any common
* for an application to set this property. * Wayland protocol. The window position arguments are ignored.
* *
* @thread_safety This function must only be called from the main thread. * @thread_safety This function must only be called from the main thread.
* *
@ -4096,8 +4096,9 @@ GLFWAPI void glfwSetWindowMonitor(GLFWwindow* window, GLFWmonitor* monitor, int
* errors. However, this function should not fail as long as it is passed * errors. However, this function should not fail as long as it is passed
* valid arguments and the library has been [initialized](@ref intro_init). * valid arguments and the library has been [initialized](@ref intro_init).
* *
* @remark @wayland The Wayland protocol provides no way to check whether a * @remark @wayland Checking whether a window is iconified is not currently
* window is iconfied, so @ref GLFW_ICONIFIED always returns `GLFW_FALSE`. * part of any common Wayland protocol, so the @ref GLFW_ICONIFIED attribute
* cannot be implemented and is always `GLFW_FALSE`.
* *
* @thread_safety This function must only be called from the main thread. * @thread_safety This function must only be called from the main thread.
* *
@ -4219,8 +4220,8 @@ GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window);
* *
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
* *
* @remark @wayland This callback will never be called, as there is no way for * @remark @wayland This callback will not be called. The Wayland protocol
* an application to know its global position. * provides no way to be notified of when a window is moved.
* *
* @thread_safety This function must only be called from the main thread. * @thread_safety This function must only be called from the main thread.
* *
@ -4395,6 +4396,10 @@ GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwi
* *
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
* *
* @remark @wayland This callback will not be called. The Wayland protocol
* provides no way to be notified of when a window is iconified, and no way to
* check whether a window is currently iconified.
*
* @thread_safety This function must only be called from the main thread. * @thread_safety This function must only be called from the main thread.
* *
* @sa @ref window_iconify * @sa @ref window_iconify

View File

@ -493,18 +493,19 @@ void _glfwInputErrorWin32(int error, const char* description)
WCHAR buffer[_GLFW_MESSAGE_SIZE] = L""; WCHAR buffer[_GLFW_MESSAGE_SIZE] = L"";
char message[_GLFW_MESSAGE_SIZE] = ""; char message[_GLFW_MESSAGE_SIZE] = "";
DWORD lastError = GetLastError();
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_MAX_WIDTH_MASK, FORMAT_MESSAGE_MAX_WIDTH_MASK,
NULL, NULL,
GetLastError() & 0xffff, lastError & 0xffff,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
buffer, buffer,
sizeof(buffer) / sizeof(WCHAR), sizeof(buffer) / sizeof(WCHAR),
NULL); NULL);
WideCharToMultiByte(CP_UTF8, 0, buffer, -1, message, sizeof(message), NULL, NULL); WideCharToMultiByte(CP_UTF8, 0, buffer, -1, message, sizeof(message), NULL, NULL);
_glfwInputError(error, "%s: %s", description, message); _glfwInputError(error, "%s (0x%lx / %lu): %s", description, lastError, lastError, message);
} }
// Updates key names according to the current keyboard layout // Updates key names according to the current keyboard layout

View File

@ -548,9 +548,24 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
EnableNonClientDpiScaling(hWnd); EnableNonClientDpiScaling(hWnd);
} }
} }
else
{
// HACK: SetPropW returns FALSE in some instances (GetLastError() = 0x8 Insufficient resources).
// We already have the global list of windows, check against it. It's not many, and we are already
// doing this in the (one of the callers) PollEvents below.
window = _glfw.windowListHead;
while (window)
{
if (window->win32.handle == hWnd) { break; }
window = window->next;
}
}
if (!window)
{
return DefWindowProcW(hWnd, uMsg, wParam, lParam); return DefWindowProcW(hWnd, uMsg, wParam, lParam);
} }
}
switch (uMsg) switch (uMsg)
{ {
@ -1401,7 +1416,13 @@ static int createNativeWindow(_GLFWwindow* window,
return GLFW_FALSE; return GLFW_FALSE;
} }
SetPropW(window->win32.handle, L"GLFW", window); if (!SetPropW(window->win32.handle, L"GLFW", window))
{
// In some cases, SetPropW returns FALSE: GetLastError() returns 0x8 (Insufficient resources).
// The message pump fails to work because windowProc cannot look up the GLFW property.
// Instead of failing the program completely by raising an error instead, windowProc looks up
// the global window list to find the hWnd under consideration.
}
ChangeWindowMessageFilterEx(window->win32.handle, WM_DROPFILES, MSGFLT_ALLOW, NULL); ChangeWindowMessageFilterEx(window->win32.handle, WM_DROPFILES, MSGFLT_ALLOW, NULL);
ChangeWindowMessageFilterEx(window->win32.handle, WM_COPYDATA, MSGFLT_ALLOW, NULL); ChangeWindowMessageFilterEx(window->win32.handle, WM_COPYDATA, MSGFLT_ALLOW, NULL);