Compare commits

...

14 Commits

Author SHA1 Message Date
Minterl
94ec2521ec
Merge c371f4cb7d into 162896e5b9 2025-11-17 00:00:51 +00:00
Doug Binks
162896e5b9
Wayland: free modules at end of terminate function
- Fixes #2744
2025-11-14 16:35:47 +00: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
Mike Interlandi
c371f4cb7d null platform fallback for other platform implementations 2025-02-03 13:35:35 -05:00
Mike Interlandi
845f0bd901 declare function in other platform headers 2025-02-03 13:23:00 -05:00
Mike Interlandi
955e8b0fa4 validate nItems & prop in _glfwGetWindowIsFullscreenX11 2025-02-03 13:06:41 -05:00
Mike Interlandi
8c3f416c3b remove .cache from .gitignore 2025-02-03 12:56:53 -05:00
Mike Interlandi
77fae536a9 move fullscreen check in tests/window with other glfwGetWindowAttrib 2025-02-03 12:11:02 -05:00
Mike Interlandi
1b5c120205 cleanup 2025-02-03 12:04:35 -05:00
Mike Interlandi
bb4ba846da integrate _glfwGetWindowIsFullscreenX11 with platform idiom 2025-02-03 11:57:46 -05:00
Mike Interlandi
618532218e GLFW_FULLSCREEN window attrib (x11) 2025-02-02 17:07:38 -05:00
Mike Interlandi
98019fbe98 add clangd .cache to gitignore 2025-02-01 18:11:04 -05:00
19 changed files with 118 additions and 23 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

@ -144,7 +144,13 @@ information on what to include when reporting a bug.
a modal to a fallback decoration
- [Wayland] Bugfix: The cursor position was not updated when clicking through
from a modal to the content area
- [Wayland] Bugfix: free modules at end of terminate function to resolve
potential segmentation fault (#2744)
- [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 EGL context creation on Mesa via `EGL_MESA_platform_surfaceless`
- [EGL] Allowed native access on Wayland with `GLFW_CONTEXT_CREATION_API` set to

View File

@ -1102,6 +1102,7 @@ extern "C" {
* [window hint](@ref GLFW_SCALE_FRAMEBUFFER_hint).
*/
#define GLFW_SCALE_FRAMEBUFFER 0x0002200D
#define GLFW_FULLSCREEN 0x0002200E
/*! @brief Legacy name for compatibility.
*
* This is an alias for the

View File

@ -555,6 +555,7 @@ GLFWbool _glfwConnectCocoa(int platformID, _GLFWplatform* platform)
.setWindowFloating = _glfwSetWindowFloatingCocoa,
.setWindowOpacity = _glfwSetWindowOpacityCocoa,
.setWindowMousePassthrough = _glfwSetWindowMousePassthroughCocoa,
.getWindowIsFullscreen = _glfwGetWindowIsFullscreenNull,
.pollEvents = _glfwPollEventsCocoa,
.waitEvents = _glfwWaitEventsCocoa,
.waitEventsTimeout = _glfwWaitEventsTimeoutCocoa,

View File

@ -247,6 +247,7 @@ void _glfwSetWindowFloatingCocoa(_GLFWwindow* window, GLFWbool enabled);
float _glfwGetWindowOpacityCocoa(_GLFWwindow* window);
void _glfwSetWindowOpacityCocoa(_GLFWwindow* window, float opacity);
void _glfwSetWindowMousePassthroughCocoa(_GLFWwindow* window, GLFWbool enabled);
GLFWbool _glfwGetWindowIsFullscreenCocoa(_GLFWwindow* window);
void _glfwSetRawMouseMotionCocoa(_GLFWwindow *window, GLFWbool enabled);
GLFWbool _glfwRawMouseMotionSupportedCocoa(void);

View File

@ -555,7 +555,8 @@ void _glfwTerminateEGL(void)
_glfw.egl.display = EGL_NO_DISPLAY;
}
if (_glfw.egl.handle)
// Free modules only after all wayland termination functions are called
if (_glfw.egl.handle && _glfw.platform.platformID != GLFW_PLATFORM_WAYLAND)
{
_glfwPlatformFreeModule(_glfw.egl.handle);
_glfw.egl.handle = NULL;

View File

@ -746,6 +746,7 @@ struct _GLFWplatform
void (*setWindowFloating)(_GLFWwindow*,GLFWbool);
void (*setWindowOpacity)(_GLFWwindow*,float);
void (*setWindowMousePassthrough)(_GLFWwindow*,GLFWbool);
GLFWbool (*getWindowIsFullscreen) (_GLFWwindow*);
void (*pollEvents)(void);
void (*waitEvents)(void);
void (*waitEventsTimeout)(double);

View File

@ -243,6 +243,8 @@ void _glfwSetWindowResizableNull(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetWindowDecoratedNull(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetWindowFloatingNull(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetWindowMousePassthroughNull(_GLFWwindow* window, GLFWbool enabled);
GLFWbool _glfwGetWindowIsFullscreenNull(_GLFWwindow* window);
float _glfwGetWindowOpacityNull(_GLFWwindow* window);
void _glfwSetWindowOpacityNull(_GLFWwindow* window, float opacity);
void _glfwSetRawMouseMotionNull(_GLFWwindow *window, GLFWbool enabled);

View File

@ -408,6 +408,11 @@ void _glfwSetWindowMousePassthroughNull(_GLFWwindow* window, GLFWbool enabled)
{
}
GLFWbool _glfwGetWindowIsFullscreenNull(_GLFWwindow* window)
{
return 0;
}
float _glfwGetWindowOpacityNull(_GLFWwindow* window)
{
return window->null.opacity;

View File

@ -660,6 +660,7 @@ GLFWbool _glfwConnectWin32(int platformID, _GLFWplatform* platform)
.setWindowFloating = _glfwSetWindowFloatingWin32,
.setWindowOpacity = _glfwSetWindowOpacityWin32,
.setWindowMousePassthrough = _glfwSetWindowMousePassthroughWin32,
.getWindowIsFullscreen = _glfwGetWindowIsFullscreenNull,
.pollEvents = _glfwPollEventsWin32,
.waitEvents = _glfwWaitEventsWin32,
.waitEventsTimeout = _glfwWaitEventsTimeoutWin32,

View File

@ -513,6 +513,7 @@ void _glfwSetWindowResizableWin32(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetWindowDecoratedWin32(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetWindowFloatingWin32(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetWindowMousePassthroughWin32(_GLFWwindow* window, GLFWbool enabled);
GLFWbool _glfwGetWindowIsFullscreenWin32(_GLFWwindow* window);
float _glfwGetWindowOpacityWin32(_GLFWwindow* window);
void _glfwSetWindowOpacityWin32(_GLFWwindow* window, float opacity);

View File

@ -899,6 +899,8 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib)
return window->focusOnShow;
case GLFW_MOUSE_PASSTHROUGH:
return window->mousePassthrough;
case GLFW_FULLSCREEN:
return _glfw.platform.getWindowIsFullscreen(window);
case GLFW_TRANSPARENT_FRAMEBUFFER:
return _glfw.platform.framebufferTransparent(window);
case GLFW_RESIZABLE:

View File

@ -506,6 +506,7 @@ GLFWbool _glfwConnectWayland(int platformID, _GLFWplatform* platform)
.setWindowFloating = _glfwSetWindowFloatingWayland,
.setWindowOpacity = _glfwSetWindowOpacityWayland,
.setWindowMousePassthrough = _glfwSetWindowMousePassthroughWayland,
.getWindowIsFullscreen = _glfwGetWindowIsFullscreenNull,
.pollEvents = _glfwPollEventsWayland,
.waitEvents = _glfwWaitEventsWayland,
.waitEventsTimeout = _glfwWaitEventsTimeoutWayland,
@ -907,18 +908,6 @@ void _glfwTerminateWayland(void)
libdecor_unref(_glfw.wl.libdecor.context);
}
if (_glfw.wl.libdecor.handle)
{
_glfwPlatformFreeModule(_glfw.wl.libdecor.handle);
_glfw.wl.libdecor.handle = NULL;
}
if (_glfw.wl.egl.handle)
{
_glfwPlatformFreeModule(_glfw.wl.egl.handle);
_glfw.wl.egl.handle = NULL;
}
if (_glfw.wl.xkb.composeState)
xkb_compose_state_unref(_glfw.wl.xkb.composeState);
if (_glfw.wl.xkb.keymap)
@ -927,21 +916,11 @@ void _glfwTerminateWayland(void)
xkb_state_unref(_glfw.wl.xkb.state);
if (_glfw.wl.xkb.context)
xkb_context_unref(_glfw.wl.xkb.context);
if (_glfw.wl.xkb.handle)
{
_glfwPlatformFreeModule(_glfw.wl.xkb.handle);
_glfw.wl.xkb.handle = NULL;
}
if (_glfw.wl.cursorTheme)
wl_cursor_theme_destroy(_glfw.wl.cursorTheme);
if (_glfw.wl.cursorThemeHiDPI)
wl_cursor_theme_destroy(_glfw.wl.cursorThemeHiDPI);
if (_glfw.wl.cursor.handle)
{
_glfwPlatformFreeModule(_glfw.wl.cursor.handle);
_glfw.wl.cursor.handle = NULL;
}
for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)
wl_data_offer_destroy(_glfw.wl.offers[i].offer);
@ -1001,6 +980,36 @@ void _glfwTerminateWayland(void)
if (_glfw.wl.cursorTimerfd >= 0)
close(_glfw.wl.cursorTimerfd);
// Free modules only after all wayland termination functions are called
if (_glfw.egl.handle)
{
_glfwPlatformFreeModule(_glfw.egl.handle);
_glfw.egl.handle = NULL;
}
if (_glfw.wl.libdecor.handle)
{
_glfwPlatformFreeModule(_glfw.wl.libdecor.handle);
_glfw.wl.libdecor.handle = NULL;
}
if (_glfw.wl.egl.handle)
{
_glfwPlatformFreeModule(_glfw.wl.egl.handle);
_glfw.wl.egl.handle = NULL;
}
if (_glfw.wl.xkb.handle)
{
_glfwPlatformFreeModule(_glfw.wl.xkb.handle);
_glfw.wl.xkb.handle = NULL;
}
if (_glfw.wl.cursor.handle)
{
_glfwPlatformFreeModule(_glfw.wl.cursor.handle);
_glfw.wl.cursor.handle = NULL;
}
_glfw_free(_glfw.wl.clipboardString);
}

View File

@ -649,6 +649,7 @@ void _glfwSetWindowFloatingWayland(_GLFWwindow* window, GLFWbool enabled);
float _glfwGetWindowOpacityWayland(_GLFWwindow* window);
void _glfwSetWindowOpacityWayland(_GLFWwindow* window, float opacity);
void _glfwSetWindowMousePassthroughWayland(_GLFWwindow* window, GLFWbool enabled);
GLFWbool _glfwGetWindowIsFullscreenWayland(_GLFWwindow* window);
void _glfwSetRawMouseMotionWayland(_GLFWwindow* window, GLFWbool enabled);
GLFWbool _glfwRawMouseMotionSupportedWayland(void);

View File

@ -1237,6 +1237,7 @@ GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform)
.setWindowFloating = _glfwSetWindowFloatingX11,
.setWindowOpacity = _glfwSetWindowOpacityX11,
.setWindowMousePassthrough = _glfwSetWindowMousePassthroughX11,
.getWindowIsFullscreen = _glfwGetWindowIsFullscreenX11,
.pollEvents = _glfwPollEventsX11,
.waitEvents = _glfwWaitEventsX11,
.waitEventsTimeout = _glfwWaitEventsTimeoutX11,

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

@ -935,6 +935,7 @@ void _glfwSetWindowFloatingX11(_GLFWwindow* window, GLFWbool enabled);
float _glfwGetWindowOpacityX11(_GLFWwindow* window);
void _glfwSetWindowOpacityX11(_GLFWwindow* window, float opacity);
void _glfwSetWindowMousePassthroughX11(_GLFWwindow* window, GLFWbool enabled);
GLFWbool _glfwGetWindowIsFullscreenX11(_GLFWwindow* window);
void _glfwSetRawMouseMotionX11(_GLFWwindow *window, GLFWbool enabled);
GLFWbool _glfwRawMouseMotionSupportedX11(void);

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)
@ -2203,6 +2207,10 @@ void _glfwGetWindowSizeX11(_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->window == window)
@ -2729,6 +2737,51 @@ void _glfwSetWindowMousePassthroughX11(_GLFWwindow* window, GLFWbool enabled)
}
}
GLFWbool _glfwGetWindowIsFullscreenX11(_GLFWwindow* window)
{
Atom wm_state = XInternAtom(_glfw.x11.display, "_NET_WM_STATE", True);
Atom wm_state_fullscreen = XInternAtom(_glfw.x11.display, "_NET_WM_STATE_FULLSCREEN", True);
Atom type = XA_ATOM;
int format;
size_t nItems;
size_t bytesAfterReturn;
Atom* prop;
int result = XGetWindowProperty(
_glfw.x11.display,
window->x11.handle,
wm_state,
0,
~0L,
False,
AnyPropertyType,
&type,
&format,
&nItems,
&bytesAfterReturn,
(unsigned char**)&prop
);
assert(result == Success);
assert(nItems > 0);
if (!prop) {
return 0;
}
GLFWbool isFullscreen = 0;
for (int i = 0; i < nItems; i++) {
if (prop[i] == wm_state_fullscreen) {
isFullscreen = 1;
}
}
XFree(prop);
return isFullscreen;
}
float _glfwGetWindowOpacityX11(_GLFWwindow* window)
{
float opacity = 1.f;

View File

@ -441,6 +441,7 @@ int main(int argc, char** argv)
nk_value_bool(nk, "Visible", glfwGetWindowAttrib(window, GLFW_VISIBLE));
nk_value_bool(nk, "Iconified", glfwGetWindowAttrib(window, GLFW_ICONIFIED));
nk_value_bool(nk, "Maximized", glfwGetWindowAttrib(window, GLFW_MAXIMIZED));
nk_value_bool(nk, "Fullscreen", glfwGetWindowAttrib(window, GLFW_FULLSCREEN));
}
nk_end(nk);