Compare commits

...

5 Commits

Author SHA1 Message Date
Pannoniae
68f54c3d7f
Merge a284523f9e into 9352d8fe93 2026-01-14 22:25:13 -03:00
Camilla Löwy
9352d8fe93 X11: Cleanup 2026-01-14 18:26:50 +01:00
Camilla Löwy
a228a8b447 X11: Fix window made non-floating by being hidden
The previous implementation was based on the incorrect assumption that
the _NET_WM_STATE_ABOVE state is always retained on unmapped windows.
According to EWMH the WM should remove the _NET_WM_STATE property when
a window is unmapped.

This commit moves the adding of _NET_WM_STATE_ABOVE to before mapping
the window during glfwShowWindow.  The logic for removing
_NET_WM_STATE_ABOVE from hidden windows is retained, as EWMH still
allows WMs to leave the window property on unmapped window.

Fixes #2276
2026-01-12 21:26:42 +01:00
Pannoniae
a284523f9e fix MinGW build 2025-08-09 14:45:08 +01:00
Pannoniae
8ef7bfdd2e clean application of the patch for #2684 2025-07-30 19:07:18 +01:00
3 changed files with 269 additions and 103 deletions

View File

@ -153,6 +153,7 @@ information on what to include when reporting a bug.
- [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
- [X11] Bugfix: Floating windows silently became non-floating when hidden (#2276)
- [Linux] Bugfix: The header for `ioctl` was only implicitly included (#2778)
- [Null] Added Vulkan 'window' surface creation via `VK_EXT_headless_surface`
- [Null] Added EGL context creation on Mesa via `EGL_MESA_platform_surfaceless`

View File

@ -35,6 +35,19 @@
#include <assert.h>
#include <windowsx.h>
#include <shellapi.h>
#include <BaseTsd.h>
#include <stdio.h>
#ifdef _WIN64
typedef UINT64 QWORD; // Needed for NEXTRAWINPUTBLOCK()
#endif
#ifndef RI_MOUSE_HWHEEL
// MinGW may not have the define for RI_MOUSE_HWHEEL
#define RI_MOUSE_HWHEEL 0x0800
#endif
// Returns the window style for the specified window
//
@ -265,7 +278,7 @@ static void releaseCursor(void)
//
static void enableRawMouseMotion(_GLFWwindow* window)
{
const RAWINPUTDEVICE rid = { 0x01, 0x02, 0, window->win32.handle };
const RAWINPUTDEVICE rid = { 0x01, 0x02, RIDEV_NOLEGACY, window->win32.handle };
if (!RegisterRawInputDevices(&rid, 1, sizeof(rid)))
{
@ -894,77 +907,6 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
return 0;
}
case WM_INPUT:
{
UINT size = 0;
HRAWINPUT ri = (HRAWINPUT) lParam;
RAWINPUT* data = NULL;
int dx, dy;
if (_glfw.win32.disabledCursorWindow != window)
break;
if (!window->rawMouseMotion)
break;
GetRawInputData(ri, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
if (size > (UINT) _glfw.win32.rawInputSize)
{
_glfw_free(_glfw.win32.rawInput);
_glfw.win32.rawInput = _glfw_calloc(size, 1);
_glfw.win32.rawInputSize = size;
}
size = _glfw.win32.rawInputSize;
if (GetRawInputData(ri, RID_INPUT,
_glfw.win32.rawInput, &size,
sizeof(RAWINPUTHEADER)) == (UINT) -1)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Win32: Failed to retrieve raw input data");
break;
}
data = _glfw.win32.rawInput;
if (data->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE)
{
POINT pos = {0};
int width, height;
if (data->data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP)
{
pos.x += GetSystemMetrics(SM_XVIRTUALSCREEN);
pos.y += GetSystemMetrics(SM_YVIRTUALSCREEN);
width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
}
else
{
width = GetSystemMetrics(SM_CXSCREEN);
height = GetSystemMetrics(SM_CYSCREEN);
}
pos.x += (int) ((data->data.mouse.lLastX / 65535.f) * width);
pos.y += (int) ((data->data.mouse.lLastY / 65535.f) * height);
ScreenToClient(window->win32.handle, &pos);
dx = pos.x - window->win32.lastCursorPosX;
dy = pos.y - window->win32.lastCursorPosY;
}
else
{
dx = data->data.mouse.lLastX;
dy = data->data.mouse.lLastY;
}
_glfwInputCursorPos(window,
window->virtualCursorPosX + dx,
window->virtualCursorPosY + dy);
window->win32.lastCursorPosX += dx;
window->win32.lastCursorPosY += dy;
break;
}
case WM_MOUSELEAVE:
{
window->win32.cursorTracked = GLFW_FALSE;
@ -2086,11 +2028,215 @@ GLFWbool _glfwRawMouseMotionSupportedWin32(void)
return GLFW_TRUE;
}
void _processRawInput(void)
{
UINT size = 0;
UINT riSize = 0;
_GLFWwindow* window = _glfw.windowListHead;
if (_glfw.win32.disabledCursorWindow != window)
return;
if (!window->rawMouseMotion)
return;
// get the size of the raw input buffer
UINT result = GetRawInputBuffer(NULL, &riSize, sizeof(RAWINPUTHEADER));
if (result == (UINT)-1)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Win32: Failed to retrieve raw input buffer size");
return;
}
UINT byteCount = riSize * 16;
if (byteCount > (UINT)_glfw.win32.rawInputSize)
{
_glfw_free(_glfw.win32.rawInput);
_glfw.win32.rawInput = _glfw_calloc(byteCount, 1);
_glfw.win32.rawInputSize = byteCount;
}
// read it (actually) this time into the buffer
size = _glfw.win32.rawInputSize;
result = GetRawInputBuffer(_glfw.win32.rawInput, &size, sizeof(RAWINPUTHEADER));
if (result == (UINT)-1)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Win32: Failed to retrieve raw input buffer");
_glfw_free(_glfw.win32.rawInput);
return;
}
// print msg count
//printf("raw input count: %u\n", result);
UINT riCount = result;
RAWINPUT* data = _glfw.win32.rawInput;
for (unsigned int i = 0; i < riCount; ++i)
{
if (data->header.dwType == RIM_TYPEMOUSE) {
int dx = 0, dy = 0;
if (data->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE)
{
POINT pos = {0};
int width, height;
if (data->data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP)
{
pos.x += GetSystemMetrics(SM_XVIRTUALSCREEN);
pos.y += GetSystemMetrics(SM_YVIRTUALSCREEN);
width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
}
else
{
width = GetSystemMetrics(SM_CXSCREEN);
height = GetSystemMetrics(SM_CYSCREEN);
}
pos.x += (int)((data->data.mouse.lLastX / 65535.f) * width);
pos.y += (int)((data->data.mouse.lLastY / 65535.f) * height);
ScreenToClient(window->win32.handle, &pos);
dx = pos.x - window->win32.lastCursorPosX;
dy = pos.y - window->win32.lastCursorPosY;
}
else
{
if (data->data.mouse.lLastX || data->data.mouse.lLastY)
{
dx = data->data.mouse.lLastX;
dy = data->data.mouse.lLastY;
}
}
if (dx != 0 || dy != 0)
{
_glfwInputCursorPos(window,
window->virtualCursorPosX + dx,
window->virtualCursorPosY + dy);
window->win32.lastCursorPosX += dx;
window->win32.lastCursorPosY += dy;
}
// Instead of reposting the events, we duplicate the button events' handlers here.
USHORT buttonFlags = data->data.mouse.usButtonFlags;
HWND hwnd = window->win32.handle;
// if any down or up button (anything except RI_MOUSE_WHEEL or RI_MOUSE_HWHEEL), process
if (buttonFlags & 0xFFFF & ~(RI_MOUSE_WHEEL | RI_MOUSE_HWHEEL))
{
int i, button = -1, action = -1;
if (buttonFlags & RI_MOUSE_LEFT_BUTTON_DOWN)
{
button = GLFW_MOUSE_BUTTON_LEFT;
action = GLFW_PRESS;
}
if (buttonFlags & RI_MOUSE_LEFT_BUTTON_UP)
{
button = GLFW_MOUSE_BUTTON_LEFT;
action = GLFW_RELEASE;
}
if (buttonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN)
{
button = GLFW_MOUSE_BUTTON_RIGHT;
action = GLFW_PRESS;
}
if (buttonFlags & RI_MOUSE_RIGHT_BUTTON_UP)
{
button = GLFW_MOUSE_BUTTON_RIGHT;
action = GLFW_RELEASE;
}
if (buttonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN)
{
button = GLFW_MOUSE_BUTTON_MIDDLE;
action = GLFW_PRESS;
}
if (buttonFlags & RI_MOUSE_MIDDLE_BUTTON_UP)
{
button = GLFW_MOUSE_BUTTON_MIDDLE;
action = GLFW_RELEASE;
}
if (buttonFlags & RI_MOUSE_BUTTON_4_DOWN)
{
button = GLFW_MOUSE_BUTTON_4;
action = GLFW_PRESS;
}
if (buttonFlags & RI_MOUSE_BUTTON_4_UP)
{
button = GLFW_MOUSE_BUTTON_4;
action = GLFW_RELEASE;
}
if (buttonFlags & RI_MOUSE_BUTTON_5_DOWN)
{
button = GLFW_MOUSE_BUTTON_5;
action = GLFW_PRESS;
}
if (buttonFlags & RI_MOUSE_BUTTON_5_UP)
{
button = GLFW_MOUSE_BUTTON_5;
action = GLFW_RELEASE;
}
for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++)
{
if (window->mouseButtons[i] == GLFW_PRESS)
break;
}
if (i > GLFW_MOUSE_BUTTON_LAST)
SetCapture(hwnd);
_glfwInputMouseClick(window, button, action, getKeyMods());
for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++)
{
if (window->mouseButtons[i] == GLFW_PRESS)
break;
}
if (i > GLFW_MOUSE_BUTTON_LAST)
ReleaseCapture();
}
// Handle mouse wheel events
if (buttonFlags & RI_MOUSE_WHEEL)
{
SHORT wheelDelta = (SHORT)data->data.mouse.usButtonData;
_glfwInputScroll(window, 0.0, wheelDelta / (double) WHEEL_DELTA);
}
if (buttonFlags & RI_MOUSE_HWHEEL)
{
SHORT wheelDelta = (SHORT)data->data.mouse.usButtonData;
_glfwInputScroll(window, -wheelDelta / (double) WHEEL_DELTA, 0.0);
}
}
data = NEXTRAWINPUTBLOCK(data);
}
}
void _glfwPollEventsWin32(void)
{
MSG msg;
HWND handle;
_GLFWwindow* window;
_GLFWwindow* window = _glfw.windowListHead;
_processRawInput(); // this does the whole `GetRawInputBuffer` thing
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
{
@ -2153,7 +2299,8 @@ void _glfwPollEventsWin32(void)
}
window = _glfw.win32.disabledCursorWindow;
if (window)
// Disable with raw mouse motion because that reports dx/dy directly
if (window && !window->rawMouseMotion)
{
int width, height;
_glfwGetWindowSizeWin32(window, &width, &height);

View File

@ -2438,6 +2438,38 @@ void _glfwShowWindowX11(_GLFWwindow* window)
if (_glfwWindowVisibleX11(window))
return;
if (window->floating && _glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_ABOVE)
{
Atom* states = NULL;
const unsigned long count =
_glfwGetWindowPropertyX11(window->x11.handle,
_glfw.x11.NET_WM_STATE,
XA_ATOM, (unsigned char**) &states);
// NOTE: We don't check for failure as this property may not exist yet
// and that's fine (and we'll create it implicitly with append)
unsigned long i;
for (i = 0; i < count; i++)
{
if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE)
break;
}
if (i == count)
{
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
PropModeAppend,
(unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE,
1);
}
if (states)
XFree(states);
}
XMapWindow(_glfw.x11.display, window->x11.handle);
waitForVisibilityNotify(window);
}
@ -2667,6 +2699,10 @@ void _glfwSetWindowFloatingX11(_GLFWwindow* window, GLFWbool enabled)
}
else
{
// NOTE: _NET_WM_STATE_ABOVE is added when the window is shown
if (enabled)
return;
Atom* states = NULL;
const unsigned long count =
_glfwGetWindowPropertyX11(window->x11.handle,
@ -2677,8 +2713,6 @@ void _glfwSetWindowFloatingX11(_GLFWwindow* window, GLFWbool enabled)
// NOTE: We don't check for failure as this property may not exist yet
// and that's fine (and we'll create it implicitly with append)
if (enabled)
{
unsigned long i;
for (i = 0; i < count; i++)
@ -2687,28 +2721,12 @@ void _glfwSetWindowFloatingX11(_GLFWwindow* window, GLFWbool enabled)
break;
}
if (i == count)
{
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
PropModeAppend,
(unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE,
1);
}
}
else if (states)
{
for (unsigned long i = 0; i < count; i++)
{
if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE)
if (i < count)
{
states[i] = states[count - 1];
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
PropModeReplace, (unsigned char*) states, count - 1);
break;
}
}
}
if (states)