Compare commits

...

6 Commits

Author SHA1 Message Date
Peru S
881f1ce63f
Merge 959f13c1bd into 936307558e 2025-11-08 12:44:33 +01:00
Doug Binks
936307558e X11: Clamp w,h in glfwSetWindowSize to >= 1
-  prevents BadValue error and program exit
2025-11-08 10:37:52 +00:00
Drew Weymouth
4df5129529 X11: check crtcInfo for NULL when polling monitors 2025-11-07 17:39:26 +00:00
Ivor Wanders
6de70d8252 X11: Prevent BadWindow when creating small windows
The glfwCreateWindow function ensures that the width and height are
at least greater or equal than zero, but on X11 it is invalid to
create a window with dimensions that equal zero, see [1].

This change ensures that the dimensions passed to XCreateWindow are
at least 1 by 1.

This issue was detected in [2], where a call to glfwCreateWindow
was done to request a 1x1 window, with a _glfw.x11.contentScaleX of
less than 1.0 (0.958333) this results in a request for a 0x0 window
which then causes an BadWindow error from X11.

[1]: e003f52661/specs/libX11/CH03.xml (L1333-1337)
[2]: https://github.com/WerWolv/ImHex/pull/2390
2025-11-07 17:24:35 +00: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
6 changed files with 47 additions and 4 deletions

View File

@ -236,6 +236,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
@ -282,10 +283,12 @@ video tutorials.
- Corentin Wallez - Corentin Wallez
- Torsten Walluhn - Torsten Walluhn
- Patrick Walton - Patrick Walton
- Ivor Wanders
- Jim Wang - Jim Wang
- Xo Wang - Xo Wang
- Andre Weissflog - Andre Weissflog
- Jay Weisskopf - Jay Weisskopf
- Drew Weymouth
- Frank Wille - Frank Wille
- Andy Williams - Andy Williams
- Joel Winarske - Joel Winarske

View File

@ -145,10 +145,15 @@ information on what to include when reporting a bug.
- [Wayland] Bugfix: The cursor position was not updated when clicking through - [Wayland] Bugfix: The cursor position was not updated when clicking through
from a modal to the content area from a modal to the content area
- [X11] Bugfix: Running without a WM could trigger an assert (#2593,#2601,#2631) - [X11] Bugfix: Running without a WM could trigger an assert (#2593,#2601,#2631)
- [X11] Bugfix: Occasional crash when an idle display awakes (#2766)
- [X11] Bugfix: Prevent BadWindow when creating small windows with a content scale
less than 1 (#2754)
- [X11] Bugfix: Clamp width and height to >= 1 to prevent BadValue error and app exit
- [Null] Added Vulkan 'window' surface creation via `VK_EXT_headless_surface` - [Null] Added Vulkan 'window' surface creation via `VK_EXT_headless_surface`
- [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

@ -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,8 +548,23 @@ 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;
}
}
return DefWindowProcW(hWnd, uMsg, wParam, lParam); if (!window)
{
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);

View File

@ -151,6 +151,11 @@ void _glfwPollMonitorsX11(void)
} }
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc); XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc);
if (!ci) {
XRRFreeOutputInfo(oi);
continue;
}
if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
{ {
widthMM = oi->mm_height; widthMM = oi->mm_height;

View File

@ -576,6 +576,10 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
height *= _glfw.x11.contentScaleY; height *= _glfw.x11.contentScaleY;
} }
// The dimensions must be nonzero, or a BadValue error results.
width = _glfw_max(1, width);
height = _glfw_max(1, height);
int xpos = 0, ypos = 0; int xpos = 0, ypos = 0;
if (wndconfig->xpos != GLFW_ANY_POSITION && wndconfig->ypos != GLFW_ANY_POSITION) if (wndconfig->xpos != GLFW_ANY_POSITION && wndconfig->ypos != GLFW_ANY_POSITION)
@ -2203,6 +2207,10 @@ void _glfwGetWindowSizeX11(_GLFWwindow* window, int* width, int* height)
void _glfwSetWindowSizeX11(_GLFWwindow* window, int width, int height) void _glfwSetWindowSizeX11(_GLFWwindow* window, int width, int height)
{ {
// The dimensions must be nonzero, or a BadValue error results.
width = _glfw_max(1, width);
height = _glfw_max(1, height);
if (window->monitor) if (window->monitor)
{ {
if (window->monitor->window == window) if (window->monitor->window == window)