Compare commits

...

5 Commits

Author SHA1 Message Date
Pannoniae
663505f406
Merge a284523f9e into 4df5129529 2025-11-08 03:39:35 +01: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
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
5 changed files with 235 additions and 74 deletions

View File

@ -282,10 +282,12 @@ video tutorials.
- Corentin Wallez
- Torsten Walluhn
- Patrick Walton
- Ivor Wanders
- Jim Wang
- Xo Wang
- Andre Weissflog
- Jay Weisskopf
- Drew Weymouth
- Frank Wille
- Andy Williams
- Joel Winarske

View File

@ -145,10 +145,13 @@ information on what to include when reporting a bug.
- [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: Occasional crash when an idle display awakes (#2766)
- [Null] Added Vulkan 'window' surface creation via `VK_EXT_headless_surface`
- [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
`GLFW_NATIVE_CONTEXT_API` (#2518)
- [X11] Bugfix: Prevent BadWindow when creating small windows with a content scale
less than 1 (#2754)
## Contact

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

@ -151,6 +151,11 @@ void _glfwPollMonitorsX11(void)
}
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)
{
widthMM = oi->mm_height;

View File

@ -576,6 +576,10 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
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;
if (wndconfig->xpos != GLFW_ANY_POSITION && wndconfig->ypos != GLFW_ANY_POSITION)