Compare commits

...

6 Commits

Author SHA1 Message Date
Peru S
00e5312bd6
Merge 959f13c1bd into 7ef6efeb66 2025-08-18 22:20:13 +01:00
Camilla Löwy
7ef6efeb66 Wayland: Fix cursor position after a modal
If a modal surface like the window menu was active, clicking on the GLFW
window content area to close it would correctly emit the cursor enter
event but would not propagate the cursor position from the event.
2025-08-18 20:58:12 +02:00
Camilla Löwy
3cf9f6726d Wayland: Fix fallback decoration cursor updating
When a click through to the fallback decorations caused the end of
a modal like the window menu, the cursor shape would not be updated
until the next time the cursor moved.

This commit adds an update of the cursor for the pointer enter event for
fallback decoration surfaces, in addition to the updates at pointer
motion events.
2025-08-18 18:06:46 +02:00
Camilla Löwy
bfa1c424e5 Wayland: Fix fallback decoration menu placement
The fallback decorations would place the menu at the wrong position, by
not translating the last decoration surface position into toplevel
surface coordinates.

This also limits the menu to the caption area of the top decoration
surface, similar to how other toolkits work.
2025-08-18 18:06:46 +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
5 changed files with 56 additions and 11 deletions

View File

@ -233,6 +233,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

@ -139,11 +139,17 @@ information on what to include when reporting a bug.
fallback decorations fallback decorations
- [Wayland] Bugfix: Fallback decorations would report scroll events - [Wayland] Bugfix: Fallback decorations would report scroll events
- [Wayland] Bugfix: Keyboard repeat events halted when any key is released (#2568) - [Wayland] Bugfix: Keyboard repeat events halted when any key is released (#2568)
- [Wayland] Bugfix: Fallback decorations would show menu at wrong position
- [Wayland] Bugfix: The cursor was not updated when clicking through from
a modal to a fallback decoration
- [Wayland] Bugfix: The cursor position was not updated when clicking through
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)
- [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,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);

View File

@ -405,13 +405,19 @@ static void handleFallbackDecorationButton(_GLFWwindow* window,
} }
else if (button == BTN_RIGHT) else if (button == BTN_RIGHT)
{ {
if (window->wl.xdg.toplevel) if (!window->wl.xdg.toplevel)
{ return;
if (window->wl.fallback.focus != window->wl.fallback.top.surface)
return;
if (ypos < GLFW_BORDER_SIZE)
return;
xdg_toplevel_show_window_menu(window->wl.xdg.toplevel, xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,
_glfw.wl.seat, serial, _glfw.wl.seat, serial,
window->wl.cursorPosX, xpos,
window->wl.cursorPosY); ypos - GLFW_CAPTION_HEIGHT - GLFW_BORDER_SIZE);
}
} }
} }
@ -1532,11 +1538,21 @@ static void pointerHandleEnter(void* userData,
window->wl.hovered = GLFW_TRUE; window->wl.hovered = GLFW_TRUE;
_glfwSetCursorWayland(window, window->wl.currentCursor); _glfwSetCursorWayland(window, window->wl.currentCursor);
_glfwInputCursorEnter(window, GLFW_TRUE); _glfwInputCursorEnter(window, GLFW_TRUE);
if (window->cursorMode != GLFW_CURSOR_DISABLED)
{
window->wl.cursorPosX = wl_fixed_to_double(sx);
window->wl.cursorPosY = wl_fixed_to_double(sy);
_glfwInputCursorPos(window, window->wl.cursorPosX, window->wl.cursorPosY);
}
} }
else else
{ {
if (window->wl.fallback.decorations) if (window->wl.fallback.decorations)
{
window->wl.fallback.focus = surface; window->wl.fallback.focus = surface;
updateFallbackDecorationCursor(window, sx, sy);
}
} }
} }