From d3ede7b6847b66cf30b067214b2b4b126d4c729b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 10 Jun 2022 00:14:05 +0200 Subject: [PATCH 01/47] Add credit Related to #2108 --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 23d1418e..43c37ac9 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -173,6 +173,7 @@ video tutorials. - Pablo Prietz - przemekmirek - pthom + - Martin Pulec - Guillaume Racicot - Philip Rideout - Eddie Ringle From 523fdf50c14210e03434648ee45bade9067fd41c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 16 Jun 2022 13:32:31 +0200 Subject: [PATCH 02/47] Wayland: Cleanup --- src/wl_window.c | 58 ++++++++++++++++--------------------------------- 1 file changed, 19 insertions(+), 39 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index 34abddf5..5c390a05 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -1428,51 +1428,31 @@ static void keyboardHandleModifiers(void* userData, 0, group); - unsigned int mods = 0; + _glfw.wl.xkb.modifiers = 0; - if (xkb_state_mod_index_is_active(_glfw.wl.xkb.state, - _glfw.wl.xkb.controlIndex, - XKB_STATE_MODS_EFFECTIVE) == 1) + struct { - mods |= GLFW_MOD_CONTROL; - } - - if (xkb_state_mod_index_is_active(_glfw.wl.xkb.state, - _glfw.wl.xkb.altIndex, - XKB_STATE_MODS_EFFECTIVE) == 1) + xkb_mod_index_t index; + unsigned int bit; + } modifiers[] = { - mods |= GLFW_MOD_ALT; - } + { _glfw.wl.xkb.controlIndex, GLFW_MOD_CONTROL }, + { _glfw.wl.xkb.altIndex, GLFW_MOD_ALT }, + { _glfw.wl.xkb.shiftIndex, GLFW_MOD_SHIFT }, + { _glfw.wl.xkb.superIndex, GLFW_MOD_SUPER }, + { _glfw.wl.xkb.capsLockIndex, GLFW_MOD_CAPS_LOCK }, + { _glfw.wl.xkb.numLockIndex, GLFW_MOD_NUM_LOCK } + }; - if (xkb_state_mod_index_is_active(_glfw.wl.xkb.state, - _glfw.wl.xkb.shiftIndex, - XKB_STATE_MODS_EFFECTIVE) == 1) + for (size_t i = 0; i < sizeof(modifiers) / sizeof(modifiers[0]); i++) { - mods |= GLFW_MOD_SHIFT; + if (xkb_state_mod_index_is_active(_glfw.wl.xkb.state, + modifiers[i].index, + XKB_STATE_MODS_EFFECTIVE) == 1) + { + _glfw.wl.xkb.modifiers |= modifiers[i].bit; + } } - - if (xkb_state_mod_index_is_active(_glfw.wl.xkb.state, - _glfw.wl.xkb.superIndex, - XKB_STATE_MODS_EFFECTIVE) == 1) - { - mods |= GLFW_MOD_SUPER; - } - - if (xkb_state_mod_index_is_active(_glfw.wl.xkb.state, - _glfw.wl.xkb.capsLockIndex, - XKB_STATE_MODS_EFFECTIVE) == 1) - { - mods |= GLFW_MOD_CAPS_LOCK; - } - - if (xkb_state_mod_index_is_active(_glfw.wl.xkb.state, - _glfw.wl.xkb.numLockIndex, - XKB_STATE_MODS_EFFECTIVE) == 1) - { - mods |= GLFW_MOD_NUM_LOCK; - } - - _glfw.wl.xkb.modifiers = mods; } #ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION From ddd087d6627d19655d78196b5836c1d090b59506 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 9 Jun 2022 21:31:44 +0200 Subject: [PATCH 03/47] Wayland: Fix behavior of leaving full screen mode These changes make GLFW fullscreen more consistent, but unfortunately also make GLFW even more oblivious to user-initiated XDG shell fullscreen changes. Fixes #1995 --- CONTRIBUTORS.md | 1 + README.md | 4 +++ src/wl_platform.h | 3 +-- src/wl_window.c | 64 +++++++++++++++++++++++++++++------------------ 4 files changed, 45 insertions(+), 27 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 43c37ac9..50f77fa5 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -160,6 +160,7 @@ video tutorials. - Christopher Pelloux - Arturo J. Pérez - Vladimir Perminov + - Olivier Perret - Anthony Pesch - Orson Peters - Emmanuel Gil Peyrot diff --git a/README.md b/README.md index fe5a2c76..28e26261 100644 --- a/README.md +++ b/README.md @@ -331,6 +331,10 @@ information on what to include when reporting a bug. - [Wayland] Bugfix: The OSMesa library was not unloaded on termination - [Wayland] Bugfix: `glfwCreateWindow` could emit `GLFW_FEATURE_UNAVAILABLE` - [Wayland] Bugfix: Lock key modifier bits were only set when lock keys were pressed + - [Wayland] Bugfix: A window leaving full screen mode would be iconified (#1995) + - [Wayland] Bugfix: A window leaving full screen mode ignored its desired size + - [Wayland] Bugfix: `glfwSetWindowMonitor` did not update windowed mode size + - [Wayland] Bugfix: `glfwRestoreWindow` would make a full screen window windowed - [POSIX] Removed use of deprecated function `gettimeofday` - [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled - [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072) diff --git a/src/wl_platform.h b/src/wl_platform.h index 98858bc5..1036fb5e 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -233,6 +233,7 @@ typedef struct _GLFWwindowWayland int width, height; GLFWbool visible; GLFWbool maximized; + GLFWbool activated; GLFWbool hovered; GLFWbool transparent; struct wl_surface* surface; @@ -264,8 +265,6 @@ typedef struct _GLFWwindowWayland struct zwp_idle_inhibitor_v1* idleInhibitor; - GLFWbool wasFullscreen; - struct { GLFWbool serverSide; struct wl_buffer* buffer; diff --git a/src/wl_window.c b/src/wl_window.c index 5c390a05..7e086461 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -429,20 +429,35 @@ static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable) } } -static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, - int refreshRate) +// Make the specified window and its video mode active on its monitor +// +static void acquireMonitor(_GLFWwindow* window) { if (window->wl.xdg.toplevel) { - xdg_toplevel_set_fullscreen( - window->wl.xdg.toplevel, - monitor->wl.output); + xdg_toplevel_set_fullscreen(window->wl.xdg.toplevel, + window->monitor->wl.output); } + setIdleInhibitor(window, GLFW_TRUE); + if (!window->wl.decorations.serverSide) destroyDecorations(window); } +// Remove the window and restore the original video mode +// +static void releaseMonitor(_GLFWwindow* window) +{ + if (window->wl.xdg.toplevel) + xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel); + + setIdleInhibitor(window, GLFW_FALSE); + + if (!_glfw.wl.decorationManager) + createDecorations(window); +} + static void xdgToplevelHandleConfigure(void* userData, struct xdg_toplevel* toplevel, int32_t width, @@ -495,16 +510,13 @@ static void xdgToplevelHandleConfigure(void* userData, _glfwInputWindowDamage(window); } - if (window->wl.wasFullscreen && window->autoIconify) + if (window->wl.activated && !activated) { - if (!activated || !fullscreen) - { + if (window->monitor && window->autoIconify) _glfwIconifyWindowWayland(window); - window->wl.wasFullscreen = GLFW_FALSE; - } } - if (fullscreen && activated) - window->wl.wasFullscreen = GLFW_TRUE; + + window->wl.activated = activated; } static void xdgToplevelHandleClose(void* userData, @@ -1896,14 +1908,12 @@ void _glfwRestoreWindowWayland(_GLFWwindow* window) { if (window->wl.xdg.toplevel) { - if (window->monitor) - xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel); if (window->wl.maximized) xdg_toplevel_unset_maximized(window->wl.xdg.toplevel); // There is no way to unset minimized, or even to know if we are // minimized, so there is nothing to do in this case. } - _glfwInputWindowMonitor(window, NULL); + window->wl.maximized = GLFW_FALSE; } @@ -1959,19 +1969,23 @@ void _glfwSetWindowMonitorWayland(_GLFWwindow* window, int width, int height, int refreshRate) { - if (monitor) + if (window->monitor == monitor) { - setFullscreen(window, monitor, refreshRate); - } - else - { - if (window->wl.xdg.toplevel) - xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel); - setIdleInhibitor(window, GLFW_FALSE); - if (!_glfw.wl.decorationManager) - createDecorations(window); + if (!monitor) + _glfwSetWindowSizeWayland(window, width, height); + + return; } + + if (window->monitor) + releaseMonitor(window); + _glfwInputWindowMonitor(window, monitor); + + if (window->monitor) + acquireMonitor(window); + else + _glfwSetWindowSizeWayland(window, width, height); } GLFWbool _glfwWindowFocusedWayland(_GLFWwindow* window) From f39ffefb6a754677305efab556216f99f90c778a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 10 Jun 2022 13:29:24 +0200 Subject: [PATCH 04/47] Wayland: Fix maximization by user being ignored The internal maximization state was not updated when an event was received that the user had changed the maximization state of a window, and no maximization events were emitted. This affected both the GLFW_MAXIMIZED attribute and glfwRestoreWindow. --- README.md | 3 +++ src/wl_window.c | 11 ++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 28e26261..df7cfa47 100644 --- a/README.md +++ b/README.md @@ -335,6 +335,9 @@ information on what to include when reporting a bug. - [Wayland] Bugfix: A window leaving full screen mode ignored its desired size - [Wayland] Bugfix: `glfwSetWindowMonitor` did not update windowed mode size - [Wayland] Bugfix: `glfwRestoreWindow` would make a full screen window windowed + - [Wayland] Bugfix: A window maximized or restored by the user would enter an + inconsistent state + - [Wayland] Bugfix: Window maximization events were not emitted - [POSIX] Removed use of deprecated function `gettimeofday` - [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled - [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072) diff --git a/src/wl_window.c b/src/wl_window.c index 7e086461..06a922cf 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -516,7 +516,13 @@ static void xdgToplevelHandleConfigure(void* userData, _glfwIconifyWindowWayland(window); } + if (window->wl.maximized && !maximized) + _glfwInputWindowMaximize(window, GLFW_FALSE); + else if (maximized && !window->wl.maximized) + _glfwInputWindowMaximize(window, GLFW_TRUE); + window->wl.activated = activated; + window->wl.maximized = maximized; } static void xdgToplevelHandleClose(void* userData, @@ -1913,17 +1919,12 @@ void _glfwRestoreWindowWayland(_GLFWwindow* window) // There is no way to unset minimized, or even to know if we are // minimized, so there is nothing to do in this case. } - - window->wl.maximized = GLFW_FALSE; } void _glfwMaximizeWindowWayland(_GLFWwindow* window) { if (window->wl.xdg.toplevel) - { xdg_toplevel_set_maximized(window->wl.xdg.toplevel); - } - window->wl.maximized = GLFW_TRUE; } void _glfwShowWindowWayland(_GLFWwindow* window) From fdc72edf8177f74b9565094559ebd0a717af93a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 19 Jun 2022 18:30:03 +0200 Subject: [PATCH 05/47] Wayland: Fix missing fullscreen code path glfwRestoreWindow assumed it was only called in windowed mode. --- README.md | 1 + src/wl_window.c | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index df7cfa47..fd97d9bf 100644 --- a/README.md +++ b/README.md @@ -338,6 +338,7 @@ information on what to include when reporting a bug. - [Wayland] Bugfix: A window maximized or restored by the user would enter an inconsistent state - [Wayland] Bugfix: Window maximization events were not emitted + - [Wayland] Bugfix: `glfwRestoreWindow` assumed it was always in windowed mode - [POSIX] Removed use of deprecated function `gettimeofday` - [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled - [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072) diff --git a/src/wl_window.c b/src/wl_window.c index 06a922cf..6d71a9aa 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -1912,13 +1912,21 @@ void _glfwIconifyWindowWayland(_GLFWwindow* window) void _glfwRestoreWindowWayland(_GLFWwindow* window) { - if (window->wl.xdg.toplevel) + if (window->monitor) { - if (window->wl.maximized) - xdg_toplevel_unset_maximized(window->wl.xdg.toplevel); // There is no way to unset minimized, or even to know if we are // minimized, so there is nothing to do in this case. } + else + { + // We assume we are not minimized and acto only on maximization + + if (window->wl.xdg.toplevel) + { + if (window->wl.maximized) + xdg_toplevel_unset_maximized(window->wl.xdg.toplevel); + } + } } void _glfwMaximizeWindowWayland(_GLFWwindow* window) From 6857995498d6628b3052b547ecd7cdecfee342d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 10 Jun 2022 14:10:25 +0200 Subject: [PATCH 06/47] Wayland: Fix glfwSetWindowSize resizing fs windows glfwSetWindowSize would change the size of fullscreen mode windows as if they were windowed mode. --- README.md | 1 + src/wl_window.c | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fd97d9bf..6524bd30 100644 --- a/README.md +++ b/README.md @@ -339,6 +339,7 @@ information on what to include when reporting a bug. inconsistent state - [Wayland] Bugfix: Window maximization events were not emitted - [Wayland] Bugfix: `glfwRestoreWindow` assumed it was always in windowed mode + - [Wayland] Bugfix: `glfwSetWindowSize` would resize a full screen window - [POSIX] Removed use of deprecated function `gettimeofday` - [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled - [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072) diff --git a/src/wl_window.c b/src/wl_window.c index 6d71a9aa..56218513 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -506,7 +506,9 @@ static void xdgToplevelHandleConfigure(void* userData, } _glfwInputWindowSize(window, width, height); - _glfwSetWindowSizeWayland(window, width, height); + window->wl.width = width; + window->wl.height = height; + resizeWindow(window); _glfwInputWindowDamage(window); } @@ -1840,9 +1842,16 @@ void _glfwGetWindowSizeWayland(_GLFWwindow* window, int* width, int* height) void _glfwSetWindowSizeWayland(_GLFWwindow* window, int width, int height) { - window->wl.width = width; - window->wl.height = height; - resizeWindow(window); + if (window->monitor) + { + // Video mode setting is not available on Wayland + } + else + { + window->wl.width = width; + window->wl.height = height; + resizeWindow(window); + } } void _glfwSetWindowSizeLimitsWayland(_GLFWwindow* window, From 0b76e3a6f158549b96d1ae3424f094c63177b2ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 10 Jun 2022 14:19:13 +0200 Subject: [PATCH 07/47] Wayland: Fix duplicate window content scale events The window content scale event was emitted every time the window content area was resized, even if its scale had not changed. --- README.md | 2 ++ src/wl_window.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6524bd30..4a3b17d4 100644 --- a/README.md +++ b/README.md @@ -340,6 +340,8 @@ information on what to include when reporting a bug. - [Wayland] Bugfix: Window maximization events were not emitted - [Wayland] Bugfix: `glfwRestoreWindow` assumed it was always in windowed mode - [Wayland] Bugfix: `glfwSetWindowSize` would resize a full screen window + - [Wayland] Bugfix: A window content scale event would be emitted every time + the window resized - [POSIX] Removed use of deprecated function `gettimeofday` - [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled - [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072) diff --git a/src/wl_window.c b/src/wl_window.c index 56218513..8cead60d 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -315,7 +315,6 @@ static void resizeWindow(_GLFWwindow* window) if (!window->wl.transparent) setOpaqueRegion(window); _glfwInputFramebufferSize(window, scaledWidth, scaledHeight); - _glfwInputWindowContentScale(window, scale, scale); if (!window->wl.decorations.top.surface) return; @@ -362,6 +361,7 @@ static void checkScaleChange(_GLFWwindow* window) { window->wl.scale = maxScale; wl_surface_set_buffer_scale(window->wl.surface, maxScale); + _glfwInputWindowContentScale(window, maxScale, maxScale); resizeWindow(window); } } From 3bbb41eacc294d3030303eabfd16f66d452e9a72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 10 Jun 2022 15:45:07 +0200 Subject: [PATCH 08/47] Wayland: Fix glfwInit closing stdin on failure If platform initialization failed before either timer fd member had been set to -1 or a valid fd, termination would close stdin. --- README.md | 1 + src/wl_init.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a3b17d4..5e75122e 100644 --- a/README.md +++ b/README.md @@ -342,6 +342,7 @@ information on what to include when reporting a bug. - [Wayland] Bugfix: `glfwSetWindowSize` would resize a full screen window - [Wayland] Bugfix: A window content scale event would be emitted every time the window resized + - [Wayland] Bugfix: If `glfwInit` failed it would close stdin - [POSIX] Removed use of deprecated function `gettimeofday` - [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled - [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072) diff --git a/src/wl_init.c b/src/wl_init.c index 2e3a0573..f462d0e6 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -479,6 +479,10 @@ int _glfwInitWayland(void) long cursorSizeLong; int cursorSize; + // These must be set before any failure checks + _glfw.wl.timerfd = -1; + _glfw.wl.cursorTimerfd = -1; + _glfw.wl.client.display_flush = (PFN_wl_display_flush) _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_flush"); _glfw.wl.client.display_cancel_read = (PFN_wl_display_cancel_read) @@ -635,7 +639,6 @@ int _glfwInitWayland(void) // Sync so we got all initial output events wl_display_roundtrip(_glfw.wl.display); - _glfw.wl.timerfd = -1; if (_glfw.wl.seatVersion >= 4) _glfw.wl.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK); From 98c9961f3265c1a926e16ff454274e75eda377f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 17 Jun 2022 20:16:34 +0200 Subject: [PATCH 09/47] Wayland: Cleanup --- src/wl_monitor.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/wl_monitor.c b/src/wl_monitor.c index 568bdc5f..96572f46 100644 --- a/src/wl_monitor.c +++ b/src/wl_monitor.c @@ -123,9 +123,6 @@ static const struct wl_output_listener outputListener = void _glfwAddOutputWayland(uint32_t name, uint32_t version) { - _GLFWmonitor* monitor; - struct wl_output* output; - if (version < 2) { _glfwInputError(GLFW_PLATFORM_ERROR, @@ -133,19 +130,15 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version) return; } - // The actual name of this output will be set in the geometry handler. - monitor = _glfwAllocMonitor("", 0, 0); - - output = wl_registry_bind(_glfw.wl.registry, - name, - &wl_output_interface, - 2); + struct wl_output* output = wl_registry_bind(_glfw.wl.registry, + name, + &wl_output_interface, + 2); if (!output) - { - _glfwFreeMonitor(monitor); return; - } + // The actual name of this output will be set in the geometry handler + _GLFWmonitor* monitor = _glfwAllocMonitor("", 0, 0); monitor->wl.scale = 1; monitor->wl.output = output; monitor->wl.name = name; From ed39ff43f969b54ba4659293dfaf4d6948f07fed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 10 Jun 2022 15:46:24 +0200 Subject: [PATCH 10/47] Wayland: Use named constants for version checks The wayland-scanner output provides really nice, self-documenting version macros, so we should use them whenever possible. --- src/wl_init.c | 4 +++- src/wl_window.c | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/wl_init.c b/src/wl_init.c index f462d0e6..867bf670 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -639,8 +639,10 @@ int _glfwInitWayland(void) // Sync so we got all initial output events wl_display_roundtrip(_glfw.wl.display); - if (_glfw.wl.seatVersion >= 4) +#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION + if (_glfw.wl.seatVersion >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) _glfw.wl.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK); +#endif if (!_glfw.wl.wmBase) { diff --git a/src/wl_window.c b/src/wl_window.c index 8cead60d..f4c745ea 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -346,8 +346,7 @@ static void resizeWindow(_GLFWwindow* window) static void checkScaleChange(_GLFWwindow* window) { - // Check if we will be able to set the buffer scale or not. - if (_glfw.wl.compositorVersion < 3) + if (_glfw.wl.compositorVersion < WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION) return; // Get the scale factor from the highest scale monitor. From afb127769a5a39246ae80e2489f0d4cf43a32fbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 10 Jun 2022 18:36:16 +0200 Subject: [PATCH 11/47] Wayland: Add tracking of XDG fullscreen state --- src/wl_platform.h | 1 + src/wl_window.c | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/wl_platform.h b/src/wl_platform.h index 1036fb5e..c0721e2b 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -234,6 +234,7 @@ typedef struct _GLFWwindowWayland GLFWbool visible; GLFWbool maximized; GLFWbool activated; + GLFWbool fullscreen; GLFWbool hovered; GLFWbool transparent; struct wl_surface* surface; diff --git a/src/wl_window.c b/src/wl_window.c index f4c745ea..ef1ac584 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -522,8 +522,9 @@ static void xdgToplevelHandleConfigure(void* userData, else if (maximized && !window->wl.maximized) _glfwInputWindowMaximize(window, GLFW_TRUE); - window->wl.activated = activated; - window->wl.maximized = maximized; + window->wl.activated = activated; + window->wl.maximized = maximized; + window->wl.fullscreen = fullscreen; } static void xdgToplevelHandleClose(void* userData, From e33db6d7aa2b62072f312bd7b723efecf5b7c9ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 10 Jun 2022 18:38:06 +0200 Subject: [PATCH 12/47] Wayland: Fix resize events before ack_configure The surface was resized and the size event was emitted before we had sent xdg_surface::ack_configure. If user code then called some GLFW function that commited the surface, those changes would all get applied to the wrong configure event. This postpones size changes until after the ack. --- src/wl_platform.h | 4 +++ src/wl_window.c | 62 +++++++++++++++++++++++++++++------------------ 2 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/wl_platform.h b/src/wl_platform.h index c0721e2b..0c64bf2b 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -241,6 +241,10 @@ typedef struct _GLFWwindowWayland struct wl_egl_window* native; struct wl_callback* callback; + struct { + int width, height; + } pending; + struct { struct xdg_surface* surface; struct xdg_toplevel* toplevel; diff --git a/src/wl_window.c b/src/wl_window.c index ef1ac584..522a80e7 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -464,8 +464,6 @@ static void xdgToplevelHandleConfigure(void* userData, struct wl_array* states) { _GLFWwindow* window = userData; - float aspectRatio; - float targetRatio; uint32_t* state; GLFWbool maximized = GLFW_FALSE; GLFWbool fullscreen = GLFW_FALSE; @@ -489,28 +487,6 @@ static void xdgToplevelHandleConfigure(void* userData, } } - if (width != 0 && height != 0) - { - if (!maximized && !fullscreen) - { - if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE) - { - aspectRatio = (float)width / (float)height; - targetRatio = (float)window->numer / (float)window->denom; - if (aspectRatio < targetRatio) - height = width / targetRatio; - else if (aspectRatio > targetRatio) - width = height * targetRatio; - } - } - - _glfwInputWindowSize(window, width, height); - window->wl.width = width; - window->wl.height = height; - resizeWindow(window); - _glfwInputWindowDamage(window); - } - if (window->wl.activated && !activated) { if (window->monitor && window->autoIconify) @@ -525,6 +501,17 @@ static void xdgToplevelHandleConfigure(void* userData, window->wl.activated = activated; window->wl.maximized = maximized; window->wl.fullscreen = fullscreen; + + if (width && height) + { + window->wl.pending.width = width; + window->wl.pending.height = height; + } + else + { + window->wl.pending.width = window->wl.width; + window->wl.pending.height = window->wl.height; + } } static void xdgToplevelHandleClose(void* userData, @@ -544,7 +531,34 @@ static void xdgSurfaceHandleConfigure(void* userData, struct xdg_surface* surface, uint32_t serial) { + _GLFWwindow* window = userData; + int width = window->wl.pending.width; + int height = window->wl.pending.height; + xdg_surface_ack_configure(surface, serial); + + if (!window->wl.maximized && !window->wl.fullscreen) + { + if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE) + { + const float aspectRatio = (float) width / (float) height; + const float targetRatio = (float) window->numer / (float) window->denom; + if (aspectRatio < targetRatio) + height = width / targetRatio; + else if (aspectRatio > targetRatio) + width = height * targetRatio; + } + } + + if (width != window->wl.width || height != window->wl.height) + { + window->wl.width = width; + window->wl.height = height; + resizeWindow(window); + + _glfwInputWindowSize(window, width, height); + _glfwInputWindowDamage(window); + } } static const struct xdg_surface_listener xdgSurfaceListener = { From 2877fea550038d73a8d04feb38af6ca4e4c3a5b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 10 Jun 2022 18:51:57 +0200 Subject: [PATCH 13/47] Wayland: Remove superfluous comments These are just repeating parts of the identifier. --- src/wl_window.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index 522a80e7..af00c5ab 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -319,24 +319,20 @@ static void resizeWindow(_GLFWwindow* window) if (!window->wl.decorations.top.surface) return; - // Top decoration. wp_viewport_set_destination(window->wl.decorations.top.viewport, window->wl.width, _GLFW_DECORATION_TOP); wl_surface_commit(window->wl.decorations.top.surface); - // Left decoration. wp_viewport_set_destination(window->wl.decorations.left.viewport, _GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP); wl_surface_commit(window->wl.decorations.left.surface); - // Right decoration. wl_subsurface_set_position(window->wl.decorations.right.subsurface, window->wl.width, -_GLFW_DECORATION_TOP); wp_viewport_set_destination(window->wl.decorations.right.viewport, _GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP); wl_surface_commit(window->wl.decorations.right.surface); - // Bottom decoration. wl_subsurface_set_position(window->wl.decorations.bottom.subsurface, -_GLFW_DECORATION_WIDTH, window->wl.height); wp_viewport_set_destination(window->wl.decorations.bottom.viewport, From 040712ce99ea787a85ae68b75fa452ee817274b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 10 Jun 2022 18:53:22 +0200 Subject: [PATCH 14/47] Wayland: Cleanup --- src/wl_window.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index af00c5ab..e48e71d5 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -401,7 +401,8 @@ static void surfaceHandleLeave(void* userData, checkScaleChange(window); } -static const struct wl_surface_listener surfaceListener = { +static const struct wl_surface_listener surfaceListener = +{ surfaceHandleEnter, surfaceHandleLeave }; @@ -557,7 +558,8 @@ static void xdgSurfaceHandleConfigure(void* userData, } } -static const struct xdg_surface_listener xdgSurfaceListener = { +static const struct xdg_surface_listener xdgSurfaceListener = +{ xdgSurfaceHandleConfigure }; From 75295f48781fb2209f4d7cb1a021b299f338996a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 12 Jun 2022 18:47:30 +0200 Subject: [PATCH 15/47] Wayland: Remove unused code path --- src/wl_window.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index e48e71d5..4d7e44ba 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -192,12 +192,10 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image) static void createDecoration(_GLFWdecorationWayland* decoration, struct wl_surface* parent, - struct wl_buffer* buffer, GLFWbool opaque, + struct wl_buffer* buffer, int x, int y, int width, int height) { - struct wl_region* region; - decoration->surface = wl_compositor_create_surface(_glfw.wl.compositor); decoration->subsurface = wl_subcompositor_get_subsurface(_glfw.wl.subcompositor, @@ -208,23 +206,17 @@ static void createDecoration(_GLFWdecorationWayland* decoration, wp_viewport_set_destination(decoration->viewport, width, height); wl_surface_attach(decoration->surface, buffer, 0, 0); - if (opaque) - { - region = wl_compositor_create_region(_glfw.wl.compositor); - wl_region_add(region, 0, 0, width, height); - wl_surface_set_opaque_region(decoration->surface, region); - wl_surface_commit(decoration->surface); - wl_region_destroy(region); - } - else - wl_surface_commit(decoration->surface); + struct wl_region* region = wl_compositor_create_region(_glfw.wl.compositor); + wl_region_add(region, 0, 0, width, height); + wl_surface_set_opaque_region(decoration->surface, region); + wl_surface_commit(decoration->surface); + wl_region_destroy(region); } static void createDecorations(_GLFWwindow* window) { unsigned char data[] = { 224, 224, 224, 255 }; const GLFWimage image = { 1, 1, data }; - GLFWbool opaque = (data[3] == 255); if (!_glfw.wl.viewporter || !window->decorated || window->wl.decorations.serverSide) return; @@ -235,19 +227,19 @@ static void createDecorations(_GLFWwindow* window) return; createDecoration(&window->wl.decorations.top, window->wl.surface, - window->wl.decorations.buffer, opaque, + window->wl.decorations.buffer, 0, -_GLFW_DECORATION_TOP, window->wl.width, _GLFW_DECORATION_TOP); createDecoration(&window->wl.decorations.left, window->wl.surface, - window->wl.decorations.buffer, opaque, + window->wl.decorations.buffer, -_GLFW_DECORATION_WIDTH, -_GLFW_DECORATION_TOP, _GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP); createDecoration(&window->wl.decorations.right, window->wl.surface, - window->wl.decorations.buffer, opaque, + window->wl.decorations.buffer, window->wl.width, -_GLFW_DECORATION_TOP, _GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP); createDecoration(&window->wl.decorations.bottom, window->wl.surface, - window->wl.decorations.buffer, opaque, + window->wl.decorations.buffer, -_GLFW_DECORATION_WIDTH, window->wl.height, window->wl.width + _GLFW_DECORATION_HORIZONTAL, _GLFW_DECORATION_WIDTH); } From 24cdc5afda8f36981eb46ae5c8189478774a325f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 16 Jun 2022 01:35:59 +0200 Subject: [PATCH 16/47] Wayland: Rename window frame size constants --- src/wl_platform.h | 5 ---- src/wl_window.c | 58 ++++++++++++++++++++++++----------------------- 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/src/wl_platform.h b/src/wl_platform.h index 0c64bf2b..7c66c736 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -198,11 +198,6 @@ typedef xkb_keysym_t (* PFN_xkb_compose_state_get_one_sym)(struct xkb_compose_st #define xkb_compose_state_get_status _glfw.wl.xkb.compose_state_get_status #define xkb_compose_state_get_one_sym _glfw.wl.xkb.compose_state_get_one_sym -#define _GLFW_DECORATION_WIDTH 4 -#define _GLFW_DECORATION_TOP 24 -#define _GLFW_DECORATION_VERTICAL (_GLFW_DECORATION_TOP + _GLFW_DECORATION_WIDTH) -#define _GLFW_DECORATION_HORIZONTAL (2 * _GLFW_DECORATION_WIDTH) - typedef enum _GLFWdecorationSideWayland { mainWindow, diff --git a/src/wl_window.c b/src/wl_window.c index 4d7e44ba..f3c7aab4 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -49,6 +49,8 @@ #include "wayland-pointer-constraints-unstable-v1-client-protocol.h" #include "wayland-idle-inhibit-unstable-v1-client-protocol.h" +#define GLFW_BORDER_SIZE 4 +#define GLFW_CAPTION_HEIGHT 24 static int createTmpfileCloexec(char* tmpname) { @@ -228,20 +230,20 @@ static void createDecorations(_GLFWwindow* window) createDecoration(&window->wl.decorations.top, window->wl.surface, window->wl.decorations.buffer, - 0, -_GLFW_DECORATION_TOP, - window->wl.width, _GLFW_DECORATION_TOP); + 0, -GLFW_CAPTION_HEIGHT, + window->wl.width, GLFW_CAPTION_HEIGHT); createDecoration(&window->wl.decorations.left, window->wl.surface, window->wl.decorations.buffer, - -_GLFW_DECORATION_WIDTH, -_GLFW_DECORATION_TOP, - _GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP); + -GLFW_BORDER_SIZE, -GLFW_CAPTION_HEIGHT, + GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT); createDecoration(&window->wl.decorations.right, window->wl.surface, window->wl.decorations.buffer, - window->wl.width, -_GLFW_DECORATION_TOP, - _GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP); + window->wl.width, -GLFW_CAPTION_HEIGHT, + GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT); createDecoration(&window->wl.decorations.bottom, window->wl.surface, window->wl.decorations.buffer, - -_GLFW_DECORATION_WIDTH, window->wl.height, - window->wl.width + _GLFW_DECORATION_HORIZONTAL, _GLFW_DECORATION_WIDTH); + -GLFW_BORDER_SIZE, window->wl.height, + window->wl.width + GLFW_BORDER_SIZE * 2, GLFW_BORDER_SIZE); } static void destroyDecoration(_GLFWdecorationWayland* decoration) @@ -312,23 +314,23 @@ static void resizeWindow(_GLFWwindow* window) return; wp_viewport_set_destination(window->wl.decorations.top.viewport, - window->wl.width, _GLFW_DECORATION_TOP); + window->wl.width, GLFW_CAPTION_HEIGHT); wl_surface_commit(window->wl.decorations.top.surface); wp_viewport_set_destination(window->wl.decorations.left.viewport, - _GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP); + GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT); wl_surface_commit(window->wl.decorations.left.surface); wl_subsurface_set_position(window->wl.decorations.right.subsurface, - window->wl.width, -_GLFW_DECORATION_TOP); + window->wl.width, -GLFW_CAPTION_HEIGHT); wp_viewport_set_destination(window->wl.decorations.right.viewport, - _GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP); + GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT); wl_surface_commit(window->wl.decorations.right.surface); wl_subsurface_set_position(window->wl.decorations.bottom.subsurface, - -_GLFW_DECORATION_WIDTH, window->wl.height); + -GLFW_BORDER_SIZE, window->wl.height); wp_viewport_set_destination(window->wl.decorations.bottom.viewport, - window->wl.width + _GLFW_DECORATION_HORIZONTAL, _GLFW_DECORATION_WIDTH); + window->wl.width + GLFW_BORDER_SIZE * 2, GLFW_BORDER_SIZE); wl_surface_commit(window->wl.decorations.bottom.surface); } @@ -1057,27 +1059,27 @@ static void pointerHandleMotion(void* userData, _glfw.wl.cursorPreviousName = NULL; return; case topDecoration: - if (y < _GLFW_DECORATION_WIDTH) + if (y < GLFW_BORDER_SIZE) cursorName = "n-resize"; else cursorName = "left_ptr"; break; case leftDecoration: - if (y < _GLFW_DECORATION_WIDTH) + if (y < GLFW_BORDER_SIZE) cursorName = "nw-resize"; else cursorName = "w-resize"; break; case rightDecoration: - if (y < _GLFW_DECORATION_WIDTH) + if (y < GLFW_BORDER_SIZE) cursorName = "ne-resize"; else cursorName = "e-resize"; break; case bottomDecoration: - if (x < _GLFW_DECORATION_WIDTH) + if (x < GLFW_BORDER_SIZE) cursorName = "sw-resize"; - else if (x > window->wl.width + _GLFW_DECORATION_WIDTH) + else if (x > window->wl.width + GLFW_BORDER_SIZE) cursorName = "se-resize"; else cursorName = "s-resize"; @@ -1109,27 +1111,27 @@ static void pointerHandleButton(void* userData, case mainWindow: break; case topDecoration: - if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH) + if (window->wl.cursorPosY < GLFW_BORDER_SIZE) edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP; else xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial); break; case leftDecoration: - if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH) + if (window->wl.cursorPosY < GLFW_BORDER_SIZE) edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; else edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT; break; case rightDecoration: - if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH) + if (window->wl.cursorPosY < GLFW_BORDER_SIZE) edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT; else edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; break; case bottomDecoration: - if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH) + if (window->wl.cursorPosX < GLFW_BORDER_SIZE) edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT; - else if (window->wl.cursorPosX > window->wl.width + _GLFW_DECORATION_WIDTH) + else if (window->wl.cursorPosX > window->wl.width + GLFW_BORDER_SIZE) edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT; else edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM; @@ -1898,13 +1900,13 @@ void _glfwGetWindowFrameSizeWayland(_GLFWwindow* window, if (window->decorated && !window->monitor && !window->wl.decorations.serverSide) { if (top) - *top = _GLFW_DECORATION_TOP; + *top = GLFW_CAPTION_HEIGHT; if (left) - *left = _GLFW_DECORATION_WIDTH; + *left = GLFW_BORDER_SIZE; if (right) - *right = _GLFW_DECORATION_WIDTH; + *right = GLFW_BORDER_SIZE; if (bottom) - *bottom = _GLFW_DECORATION_WIDTH; + *bottom = GLFW_BORDER_SIZE; } } From 0f5b095042842006747f8dc04aded64ea3e05d2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 16 Jun 2022 01:36:55 +0200 Subject: [PATCH 17/47] Wayland: Fix erratic fallback decoration behavior The handler for xdg_toplevel::configure treated the provided size as the content area size when instead it is the size of the bounding rectangle of the wl_surface and all its subsurfaces. This caused the fallback decorations to try positioning themselves outside themselves, causing feedback loops during interactive resizing. Fixes #1991 Fixes #2115 Closes #2127 Related to #1914 --- CONTRIBUTORS.md | 2 ++ README.md | 2 ++ src/wl_window.c | 13 +++++++++++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 50f77fa5..1498d01e 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -24,6 +24,7 @@ video tutorials. - Waris Boonyasiriwat - Kyle Brenneman - Rok Breulj + - TheBrokenRail - Kai Burjack - Martin Capitanio - Nicolas Caramelli @@ -145,6 +146,7 @@ video tutorials. - Pierre Moulon - Martins Mozeiko - Pascal Muetschard + - James Murphy - Julian Møller - ndogxj - n3rdopolis diff --git a/README.md b/README.md index 5e75122e..3fd1a353 100644 --- a/README.md +++ b/README.md @@ -343,6 +343,8 @@ information on what to include when reporting a bug. - [Wayland] Bugfix: A window content scale event would be emitted every time the window resized - [Wayland] Bugfix: If `glfwInit` failed it would close stdin + - [Wayland] Bugfix: Manual resizing with fallback decorations behaved erratically + (#1991,#2115,#2127) - [POSIX] Removed use of deprecated function `gettimeofday` - [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled - [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072) diff --git a/src/wl_window.c b/src/wl_window.c index f3c7aab4..900aae2a 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -495,8 +495,17 @@ static void xdgToplevelHandleConfigure(void* userData, if (width && height) { - window->wl.pending.width = width; - window->wl.pending.height = height; + if (window->wl.decorations.top.surface) + { + window->wl.pending.width = _glfw_max(0, width - GLFW_BORDER_SIZE * 2); + window->wl.pending.height = + _glfw_max(0, height - GLFW_BORDER_SIZE - GLFW_CAPTION_HEIGHT); + } + else + { + window->wl.pending.width = width; + window->wl.pending.height = height; + } } else { From a7b6f355008237c28faad86c2188cc5f132aec64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 12 Jun 2022 21:36:26 +0200 Subject: [PATCH 18/47] Wayland: Fix size limits for fallback decorations The size limits set on our XDG surface did not include the sizes of the fallback decorations on all sides, when in use. This led to its content area being too small. Related to #2127 --- README.md | 1 + src/wl_window.c | 53 ++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 3fd1a353..6a76c298 100644 --- a/README.md +++ b/README.md @@ -345,6 +345,7 @@ information on what to include when reporting a bug. - [Wayland] Bugfix: If `glfwInit` failed it would close stdin - [Wayland] Bugfix: Manual resizing with fallback decorations behaved erratically (#1991,#2115,#2127) + - [Wayland] Bugfix: Size limits included frame size for fallback decorations - [POSIX] Removed use of deprecated function `gettimeofday` - [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled - [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072) diff --git a/src/wl_window.c b/src/wl_window.c index 900aae2a..a32ccfb6 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -617,13 +617,6 @@ static GLFWbool createXdgSurface(_GLFWwindow* window) if (window->wl.title) xdg_toplevel_set_title(window->wl.xdg.toplevel, window->wl.title); - if (window->minwidth != GLFW_DONT_CARE && window->minheight != GLFW_DONT_CARE) - xdg_toplevel_set_min_size(window->wl.xdg.toplevel, - window->minwidth, window->minheight); - if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE) - xdg_toplevel_set_max_size(window->wl.xdg.toplevel, - window->maxwidth, window->maxheight); - if (window->monitor) { xdg_toplevel_set_fullscreen(window->wl.xdg.toplevel, @@ -642,6 +635,34 @@ static GLFWbool createXdgSurface(_GLFWwindow* window) setXdgDecorations(window); } + if (window->minwidth != GLFW_DONT_CARE && window->minheight != GLFW_DONT_CARE) + { + int minwidth = window->minwidth; + int minheight = window->minheight; + + if (window->wl.decorations.top.surface) + { + minwidth += GLFW_BORDER_SIZE * 2; + minheight += GLFW_CAPTION_HEIGHT + GLFW_BORDER_SIZE; + } + + xdg_toplevel_set_min_size(window->wl.xdg.toplevel, minwidth, minheight); + } + + if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE) + { + int maxwidth = window->maxwidth; + int maxheight = window->maxheight; + + if (window->wl.decorations.top.surface) + { + maxwidth += GLFW_BORDER_SIZE * 2; + maxheight += GLFW_CAPTION_HEIGHT + GLFW_BORDER_SIZE; + } + + xdg_toplevel_set_max_size(window->wl.xdg.toplevel, maxwidth, maxheight); + } + wl_surface_commit(window->wl.surface); wl_display_roundtrip(_glfw.wl.display); @@ -1877,8 +1898,26 @@ void _glfwSetWindowSizeLimitsWayland(_GLFWwindow* window, { if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) minwidth = minheight = 0; + else + { + if (window->wl.decorations.top.surface) + { + minwidth += GLFW_BORDER_SIZE * 2; + minheight += GLFW_CAPTION_HEIGHT + GLFW_BORDER_SIZE; + } + } + if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE) maxwidth = maxheight = 0; + else + { + if (window->wl.decorations.top.surface) + { + maxwidth += GLFW_BORDER_SIZE * 2; + maxheight += GLFW_CAPTION_HEIGHT + GLFW_BORDER_SIZE; + } + } + xdg_toplevel_set_min_size(window->wl.xdg.toplevel, minwidth, minheight); xdg_toplevel_set_max_size(window->wl.xdg.toplevel, maxwidth, maxheight); wl_surface_commit(window->wl.surface); From 18df0baea60ed17d744eb4b714b8b9363776c0cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Sun, 12 Jun 2022 23:16:16 +0200 Subject: [PATCH 19/47] Wayland: Cleanup --- src/wl_window.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index a32ccfb6..cdb36718 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -623,14 +623,11 @@ static GLFWbool createXdgSurface(_GLFWwindow* window) window->monitor->wl.output); setIdleInhibitor(window, GLFW_TRUE); } - else if (window->wl.maximized) - { - xdg_toplevel_set_maximized(window->wl.xdg.toplevel); - setIdleInhibitor(window, GLFW_FALSE); - setXdgDecorations(window); - } else { + if (window->wl.maximized) + xdg_toplevel_set_maximized(window->wl.xdg.toplevel); + setIdleInhibitor(window, GLFW_FALSE); setXdgDecorations(window); } From c28d420060a60d579e15afb812d5bd054891179a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 13 Jun 2022 15:12:52 +0200 Subject: [PATCH 20/47] Wayland: Remove duplicate fullscreen check This check is already performed in shared code. --- src/wl_window.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index cdb36718..0fea1a10 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -2098,13 +2098,10 @@ void _glfwSetWindowResizableWayland(_GLFWwindow* window, GLFWbool enabled) void _glfwSetWindowDecoratedWayland(_GLFWwindow* window, GLFWbool enabled) { - if (!window->monitor) - { - if (enabled) - createDecorations(window); - else - destroyDecorations(window); - } + if (enabled) + createDecorations(window); + else + destroyDecorations(window); } void _glfwSetWindowFloatingWayland(_GLFWwindow* window, GLFWbool enabled) From 229d628ec47073c3778ba2e37c02c8d94140be77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 13 Jun 2022 19:37:34 +0200 Subject: [PATCH 21/47] Wayland: Fix toggling of server-side decorations This is a temporary local fix to have updates to GLFW_DECORATED mostly work as intended. The whole decoration state machine needs to be restructured, but not by this commit. --- README.md | 2 ++ src/wl_window.c | 20 +++++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6a76c298..8f3f74d9 100644 --- a/README.md +++ b/README.md @@ -346,6 +346,8 @@ information on what to include when reporting a bug. - [Wayland] Bugfix: Manual resizing with fallback decorations behaved erratically (#1991,#2115,#2127) - [Wayland] Bugfix: Size limits included frame size for fallback decorations + - [Wayland] Bugfix: Updating `GLFW_DECORATED` had no effect on server-side + decorations - [POSIX] Removed use of deprecated function `gettimeofday` - [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled - [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072) diff --git a/src/wl_window.c b/src/wl_window.c index 0fea1a10..82fcfcd2 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -2098,10 +2098,24 @@ void _glfwSetWindowResizableWayland(_GLFWwindow* window, GLFWbool enabled) void _glfwSetWindowDecoratedWayland(_GLFWwindow* window, GLFWbool enabled) { - if (enabled) - createDecorations(window); + if (window->wl.xdg.decoration) + { + uint32_t mode; + + if (enabled) + mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; + else + mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; + + zxdg_toplevel_decoration_v1_set_mode(window->wl.xdg.decoration, mode); + } else - destroyDecorations(window); + { + if (enabled) + createDecorations(window); + else + destroyDecorations(window); + } } void _glfwSetWindowFloatingWayland(_GLFWwindow* window, GLFWbool enabled) From 33d37782c6551fe67c553dd077ad7ee79f1b76f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 14 Jun 2022 18:12:49 +0200 Subject: [PATCH 22/47] Wayland: Cleanup --- src/wl_init.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/wl_init.c b/src/wl_init.c index 867bf670..2ce6f7f9 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -184,11 +184,9 @@ static void registryHandleGlobalRemove(void* userData, struct wl_registry* registry, uint32_t name) { - _GLFWmonitor* monitor; - for (int i = 0; i < _glfw.monitorCount; ++i) { - monitor = _glfw.monitors[i]; + _GLFWmonitor* monitor = _glfw.monitors[i]; if (monitor->wl.name == name) { _glfwInputMonitor(monitor, GLFW_DISCONNECTED, 0); From 209f6cf0935412e067e6595790cf3d3d5866923d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 14 Jun 2022 18:20:56 +0200 Subject: [PATCH 23/47] Wayland: Add support for wl_output::name We now use wl_output::name as the GLFW monitor name, on compositors that provide this event. --- README.md | 1 + src/wl_monitor.c | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8f3f74d9..07d2e547 100644 --- a/README.md +++ b/README.md @@ -298,6 +298,7 @@ information on what to include when reporting a bug. - [Wayland] Added dynamic loading of all Wayland libraries - [Wayland] Added support for key names via xkbcommon - [Wayland] Added support for file path drop events (#2040) + - [Wayland] Added support for more human-readable monitor names where available - [Wayland] Removed support for `wl_shell` (#1443) - [Wayland] Bugfix: The `GLFW_HAND_CURSOR` shape used the wrong image (#1432) - [Wayland] Bugfix: `CLOCK_MONOTONIC` was not correctly enabled diff --git a/src/wl_monitor.c b/src/wl_monitor.c index 96572f46..37712ad5 100644 --- a/src/wl_monitor.c +++ b/src/wl_monitor.c @@ -55,7 +55,8 @@ static void outputHandleGeometry(void* userData, monitor->widthMM = physicalWidth; monitor->heightMM = physicalHeight; - snprintf(monitor->name, sizeof(monitor->name), "%s %s", make, model); + if (strlen(monitor->name) == 0) + snprintf(monitor->name, sizeof(monitor->name), "%s %s", make, model); } static void outputHandleMode(void* userData, @@ -108,12 +109,33 @@ static void outputHandleScale(void* userData, monitor->wl.scale = factor; } +#ifdef WL_OUTPUT_NAME_SINCE_VERSION + +void outputHandleName(void* userData, struct wl_output* wl_output, const char* name) +{ + struct _GLFWmonitor* monitor = userData; + + strncpy(monitor->name, name, sizeof(monitor->name) - 1); +} + +void outputHandleDescription(void* userData, + struct wl_output* wl_output, + const char* description) +{ +} + +#endif // WL_OUTPUT_NAME_SINCE_VERSION + static const struct wl_output_listener outputListener = { outputHandleGeometry, outputHandleMode, outputHandleDone, outputHandleScale, +#ifdef WL_OUTPUT_NAME_SINCE_VERSION + outputHandleName, + outputHandleDescription, +#endif }; @@ -130,10 +152,16 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version) return; } +#ifdef WL_OUTPUT_NAME_SINCE_VERSION + version = _glfw_min(version, WL_OUTPUT_NAME_SINCE_VERSION); +#else + version = 2; +#endif + struct wl_output* output = wl_registry_bind(_glfw.wl.registry, name, &wl_output_interface, - 2); + version); if (!output) return; From c3ad3d49ed8b436582a6fbba1c3e64f97087e362 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 14 Jun 2022 18:44:24 +0200 Subject: [PATCH 24/47] Wayland: Fix duplicate monitor connection events GLFW would report a monitor as connected each time its wl_output received an update, for example if its scale changed. This would also cause the monitor to be added to the monitor array again, causing glfwTerminate to segfault when it attempted to destroy its already destroyed wl_output. --- README.md | 4 ++++ src/wl_monitor.c | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/README.md b/README.md index 07d2e547..70f94f13 100644 --- a/README.md +++ b/README.md @@ -349,6 +349,10 @@ information on what to include when reporting a bug. - [Wayland] Bugfix: Size limits included frame size for fallback decorations - [Wayland] Bugfix: Updating `GLFW_DECORATED` had no effect on server-side decorations + - [Wayland] Bugfix: A monitor would be reported as connected again if its scale + changed + - [Wayland] Bugfix: `glfwTerminate` would segfault if any monitor had changed + scale - [POSIX] Removed use of deprecated function `gettimeofday` - [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled - [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072) diff --git a/src/wl_monitor.c b/src/wl_monitor.c index 37712ad5..c1afd016 100644 --- a/src/wl_monitor.c +++ b/src/wl_monitor.c @@ -97,6 +97,12 @@ static void outputHandleDone(void* userData, struct wl_output* output) monitor->heightMM = (int) (mode->height * 25.4f / 96.f); } + for (int i = 0; i < _glfw.monitorCount; i++) + { + if (_glfw.monitors[i] == monitor) + return; + } + _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST); } From e37ba80b1343f46d1b380fd3b9816e1260d8ee0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 14 Jun 2022 18:46:47 +0200 Subject: [PATCH 25/47] Wayland: Fix reporting of monitor scale changes Content scale events would be emitted when a window surface entered or left an output, but not when one of a window's current outputs had its scale changed. --- README.md | 2 ++ src/wl_monitor.c | 12 ++++++++++++ src/wl_platform.h | 1 + src/wl_window.c | 6 +++--- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 70f94f13..ccc3eae6 100644 --- a/README.md +++ b/README.md @@ -353,6 +353,8 @@ information on what to include when reporting a bug. changed - [Wayland] Bugfix: `glfwTerminate` would segfault if any monitor had changed scale + - [Wayland] Bugfix: Window content scale events were not emitted when monitor + scale changed - [POSIX] Removed use of deprecated function `gettimeofday` - [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled - [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072) diff --git a/src/wl_monitor.c b/src/wl_monitor.c index c1afd016..336681fd 100644 --- a/src/wl_monitor.c +++ b/src/wl_monitor.c @@ -113,6 +113,18 @@ static void outputHandleScale(void* userData, struct _GLFWmonitor* monitor = userData; monitor->wl.scale = factor; + + for (_GLFWwindow* window = _glfw.windowListHead; window; window = window->next) + { + for (int i = 0; i < window->wl.monitorsCount; i++) + { + if (window->wl.monitors[i] == monitor) + { + _glfwUpdateContentScaleWayland(window); + break; + } + } + } } #ifdef WL_OUTPUT_NAME_SINCE_VERSION diff --git a/src/wl_platform.h b/src/wl_platform.h index 7c66c736..03acb261 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -507,6 +507,7 @@ GLFWbool _glfwGetGammaRampWayland(_GLFWmonitor* monitor, GLFWgammaramp* ramp); void _glfwSetGammaRampWayland(_GLFWmonitor* monitor, const GLFWgammaramp* ramp); void _glfwAddOutputWayland(uint32_t name, uint32_t version); +void _glfwUpdateContentScaleWayland(_GLFWwindow* window); GLFWbool _glfwInputTextWayland(_GLFWwindow* window, uint32_t scancode); void _glfwAddSeatListenerWayland(struct wl_seat* seat); diff --git a/src/wl_window.c b/src/wl_window.c index 82fcfcd2..73938e90 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -334,7 +334,7 @@ static void resizeWindow(_GLFWwindow* window) wl_surface_commit(window->wl.decorations.bottom.surface); } -static void checkScaleChange(_GLFWwindow* window) +void _glfwUpdateContentScaleWayland(_GLFWwindow* window) { if (_glfw.wl.compositorVersion < WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION) return; @@ -372,7 +372,7 @@ static void surfaceHandleEnter(void* userData, window->wl.monitors[window->wl.monitorsCount++] = monitor; - checkScaleChange(window); + _glfwUpdateContentScaleWayland(window); } static void surfaceHandleLeave(void* userData, @@ -392,7 +392,7 @@ static void surfaceHandleLeave(void* userData, } window->wl.monitors[--window->wl.monitorsCount] = NULL; - checkScaleChange(window); + _glfwUpdateContentScaleWayland(window); } static const struct wl_surface_listener surfaceListener = From 91f18fb57697c57bf9da64ad546eed5c60518618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 14 Jun 2022 20:37:31 +0200 Subject: [PATCH 26/47] Wayland: Fix error from glfwSetWindowAspectRatio The aspect ratio was applied during resize but any call to glfwSetWindowAspectRatio emitted a GLFW_FEATURE_UNIMPLEMENTED error. --- README.md | 2 ++ src/wl_window.c | 18 ++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ccc3eae6..6a10ae5c 100644 --- a/README.md +++ b/README.md @@ -355,6 +355,8 @@ information on what to include when reporting a bug. scale - [Wayland] Bugfix: Window content scale events were not emitted when monitor scale changed + - [Wayland] Bugfix: `glfwSetWindowAspectRatio` reported an error instead of + applying the specified ratio - [POSIX] Removed use of deprecated function `gettimeofday` - [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled - [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072) diff --git a/src/wl_window.c b/src/wl_window.c index 73938e90..f3dd2de1 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -1923,10 +1923,20 @@ void _glfwSetWindowSizeLimitsWayland(_GLFWwindow* window, void _glfwSetWindowAspectRatioWayland(_GLFWwindow* window, int numer, int denom) { - // TODO: find out how to trigger a resize. - // The actual limits are checked in the xdg_toplevel::configure handler. - _glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, - "Wayland: Window aspect ratio not yet implemented"); + if (window->wl.maximized || window->wl.fullscreen) + return; + + if (numer != GLFW_DONT_CARE && denom != GLFW_DONT_CARE) + { + const float aspectRatio = (float) window->wl.width / (float) window->wl.height; + const float targetRatio = (float) numer / (float) denom; + if (aspectRatio < targetRatio) + window->wl.height = window->wl.width / targetRatio; + else if (aspectRatio > targetRatio) + window->wl.width = window->wl.height * targetRatio; + + resizeWindow(window); + } } void _glfwGetFramebufferSizeWayland(_GLFWwindow* window, int* width, int* height) From 5002522f7340e2ffb5fae07690b6091cb13ee960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 14 Jun 2022 22:22:49 +0200 Subject: [PATCH 27/47] Wayland: Cleanup Make Wayland code use 'native' in the same senses as the rest of GLFW. --- src/wl_platform.h | 5 ++++- src/wl_window.c | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/wl_platform.h b/src/wl_platform.h index 03acb261..6f092136 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -233,9 +233,12 @@ typedef struct _GLFWwindowWayland GLFWbool hovered; GLFWbool transparent; struct wl_surface* surface; - struct wl_egl_window* native; struct wl_callback* callback; + struct { + struct wl_egl_window* window; + } egl; + struct { int width, height; } pending; diff --git a/src/wl_window.c b/src/wl_window.c index f3dd2de1..74f4adfb 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -305,7 +305,7 @@ static void resizeWindow(_GLFWwindow* window) int scale = window->wl.scale; int scaledWidth = window->wl.width * scale; int scaledHeight = window->wl.height * scale; - wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0); + wl_egl_window_resize(window->wl.egl.window, scaledWidth, scaledHeight, 0, 0); if (!window->wl.transparent) setOpaqueRegion(window); _glfwInputFramebufferSize(window, scaledWidth, scaledHeight); @@ -666,9 +666,9 @@ static GLFWbool createXdgSurface(_GLFWwindow* window) return GLFW_TRUE; } -static GLFWbool createSurface(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig, - const _GLFWfbconfig* fbconfig) +static GLFWbool createNativeSurface(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig) { window->wl.surface = wl_compositor_create_surface(_glfw.wl.compositor); if (!window->wl.surface) @@ -680,10 +680,10 @@ static GLFWbool createSurface(_GLFWwindow* window, wl_surface_set_user_data(window->wl.surface, window); - window->wl.native = wl_egl_window_create(window->wl.surface, - wndconfig->width, - wndconfig->height); - if (!window->wl.native) + window->wl.egl.window = wl_egl_window_create(window->wl.surface, + wndconfig->width, + wndconfig->height); + if (!window->wl.egl.window) return GLFW_FALSE; window->wl.width = wndconfig->width; @@ -1759,7 +1759,7 @@ GLFWbool _glfwCreateWindowWayland(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { - if (!createSurface(window, wndconfig, fbconfig)) + if (!createNativeSurface(window, wndconfig, fbconfig)) return GLFW_FALSE; if (ctxconfig->client != GLFW_NO_API) @@ -1816,8 +1816,8 @@ void _glfwDestroyWindowWayland(_GLFWwindow* window) if (window->wl.decorations.buffer) wl_buffer_destroy(window->wl.decorations.buffer); - if (window->wl.native) - wl_egl_window_destroy(window->wl.native); + if (window->wl.egl.window) + wl_egl_window_destroy(window->wl.egl.window); if (window->wl.xdg.toplevel) xdg_toplevel_destroy(window->wl.xdg.toplevel); @@ -2707,7 +2707,7 @@ EGLNativeDisplayType _glfwGetEGLNativeDisplayWayland(void) EGLNativeWindowType _glfwGetEGLNativeWindowWayland(_GLFWwindow* window) { - return window->wl.native; + return window->wl.egl.window; } void _glfwGetRequiredInstanceExtensionsWayland(char** extensions) From 9ad9f5c52a9e89c598d39ffaa918106c1a096e7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 14 Jun 2022 22:28:05 +0200 Subject: [PATCH 28/47] Wayland: Fix missing error reporting --- src/wl_window.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/wl_window.c b/src/wl_window.c index 74f4adfb..14ea103b 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -672,7 +672,10 @@ static GLFWbool createNativeSurface(_GLFWwindow* window, { window->wl.surface = wl_compositor_create_surface(_glfw.wl.compositor); if (!window->wl.surface) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Failed to create window surface"); return GLFW_FALSE; + } wl_surface_add_listener(window->wl.surface, &surfaceListener, @@ -684,7 +687,10 @@ static GLFWbool createNativeSurface(_GLFWwindow* window, wndconfig->width, wndconfig->height); if (!window->wl.egl.window) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Failed to create EGL window"); return GLFW_FALSE; + } window->wl.width = wndconfig->width; window->wl.height = wndconfig->height; From 85f5a51912c3329137377cd2ba0f0a7a34887ed7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 15 Jun 2022 17:57:54 +0200 Subject: [PATCH 29/47] Wayland: Fix events emitted before ack_configure Window iconfication and maximization events were being emitted before xdg_surface::configure, making it possible for user code to indirectly commit surface changes from those event callbacks before xdg_surface::ack_configure. This postpones those events until after the ack has been sent. --- src/wl_platform.h | 4 ++++ src/wl_window.c | 51 ++++++++++++++++++++++++++--------------------- 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/wl_platform.h b/src/wl_platform.h index 6f092136..d8d94822 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -241,6 +241,10 @@ typedef struct _GLFWwindowWayland struct { int width, height; + GLFWbool maximized; + GLFWbool iconified; + GLFWbool activated; + GLFWbool fullscreen; } pending; struct { diff --git a/src/wl_window.c b/src/wl_window.c index 14ea103b..53175699 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -456,43 +456,29 @@ static void xdgToplevelHandleConfigure(void* userData, { _GLFWwindow* window = userData; uint32_t* state; - GLFWbool maximized = GLFW_FALSE; - GLFWbool fullscreen = GLFW_FALSE; - GLFWbool activated = GLFW_FALSE; + + window->wl.pending.activated = GLFW_FALSE; + window->wl.pending.maximized = GLFW_FALSE; + window->wl.pending.fullscreen = GLFW_FALSE; wl_array_for_each(state, states) { switch (*state) { case XDG_TOPLEVEL_STATE_MAXIMIZED: - maximized = GLFW_TRUE; + window->wl.pending.maximized = GLFW_TRUE; break; case XDG_TOPLEVEL_STATE_FULLSCREEN: - fullscreen = GLFW_TRUE; + window->wl.pending.fullscreen = GLFW_TRUE; break; case XDG_TOPLEVEL_STATE_RESIZING: break; case XDG_TOPLEVEL_STATE_ACTIVATED: - activated = GLFW_TRUE; + window->wl.pending.activated = GLFW_TRUE; break; } } - if (window->wl.activated && !activated) - { - if (window->monitor && window->autoIconify) - _glfwIconifyWindowWayland(window); - } - - if (window->wl.maximized && !maximized) - _glfwInputWindowMaximize(window, GLFW_FALSE); - else if (maximized && !window->wl.maximized) - _glfwInputWindowMaximize(window, GLFW_TRUE); - - window->wl.activated = activated; - window->wl.maximized = maximized; - window->wl.fullscreen = fullscreen; - if (width && height) { if (window->wl.decorations.top.surface) @@ -532,11 +518,30 @@ static void xdgSurfaceHandleConfigure(void* userData, uint32_t serial) { _GLFWwindow* window = userData; - int width = window->wl.pending.width; - int height = window->wl.pending.height; xdg_surface_ack_configure(surface, serial); + if (window->wl.activated != window->wl.pending.activated) + { + window->wl.activated = window->wl.pending.activated; + if (!window->wl.activated) + { + if (window->monitor && window->autoIconify) + xdg_toplevel_set_minimized(window->wl.xdg.toplevel); + } + } + + if (window->wl.maximized != window->wl.pending.maximized) + { + window->wl.maximized = window->wl.pending.maximized; + _glfwInputWindowMaximize(window, window->wl.maximized); + } + + window->wl.fullscreen = window->wl.pending.fullscreen; + + int width = window->wl.pending.width; + int height = window->wl.pending.height; + if (!window->wl.maximized && !window->wl.fullscreen) { if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE) From 203002ef2c6a8518138eed981ba1e95cfe59c59c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 15 Jun 2022 14:12:32 +0200 Subject: [PATCH 30/47] Wayland: Fix latent bug for glfwGetWindowTitle --- src/wl_window.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index 53175699..cc4a75bd 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -1845,9 +1845,10 @@ void _glfwDestroyWindowWayland(_GLFWwindow* window) void _glfwSetWindowTitleWayland(_GLFWwindow* window, const char* title) { - if (window->wl.title) - _glfw_free(window->wl.title); - window->wl.title = _glfw_strdup(title); + char* copy = _glfw_strdup(title); + _glfw_free(window->wl.title); + window->wl.title = copy; + if (window->wl.xdg.toplevel) xdg_toplevel_set_title(window->wl.xdg.toplevel, title); } From 55fcfb1bb642485b1c14fa8e20388fa2ac9fb8c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 15 Jun 2022 14:39:30 +0200 Subject: [PATCH 31/47] Wayland: Fix error for setting GLFW_FLOATING --- src/wl_window.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index cc4a75bd..19a493a3 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -2142,9 +2142,8 @@ void _glfwSetWindowDecoratedWayland(_GLFWwindow* window, GLFWbool enabled) void _glfwSetWindowFloatingWayland(_GLFWwindow* window, GLFWbool enabled) { - // TODO - _glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, - "Wayland: Window attribute setting not implemented yet"); + _glfwInputError(GLFW_FEATURE_UNAVAILABLE, + "Wayland: Platform does not support making a window floating"); } void _glfwSetWindowMousePassthroughWayland(_GLFWwindow* window, GLFWbool enabled) From e52046955d551a1a07bd213f5ada657f83a49fcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 15 Jun 2022 14:41:46 +0200 Subject: [PATCH 32/47] Wayland: Cleanup --- src/wl_window.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wl_window.c b/src/wl_window.c index 19a493a3..e25c1048 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -2156,6 +2156,7 @@ void _glfwSetWindowMousePassthroughWayland(_GLFWwindow* window, GLFWbool enabled } else wl_surface_set_input_region(window->wl.surface, 0); + wl_surface_commit(window->wl.surface); } From 77819c0c549fa9c1aa40ff74289bd7cfae61f296 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 15 Jun 2022 18:20:16 +0200 Subject: [PATCH 33/47] Wayland: Fix maximized state lost while hidden If a window was created as maximized, or created as hidden and then iconified or maximized before first being shown, that state was lost and the window was shown as restored. --- README.md | 2 ++ src/wl_window.c | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6a10ae5c..d4a60417 100644 --- a/README.md +++ b/README.md @@ -357,6 +357,8 @@ information on what to include when reporting a bug. scale changed - [Wayland] Bugfix: `glfwSetWindowAspectRatio` reported an error instead of applying the specified ratio + - [Wayland] Bugfix: `GLFW_MAXIMIZED` window hint had no effect + - [Wayland] Bugfix: `glfwRestoreWindow` had no effect before first show - [POSIX] Removed use of deprecated function `gettimeofday` - [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled - [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072) diff --git a/src/wl_window.c b/src/wl_window.c index e25c1048..efad74d9 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -702,6 +702,8 @@ static GLFWbool createNativeSurface(_GLFWwindow* window, window->wl.scale = 1; window->wl.title = _glfw_strdup(wndconfig->title); + window->wl.maximized = wndconfig->maximized; + window->wl.transparent = fbconfig->transparent; if (!window->wl.transparent) setOpaqueRegion(window); @@ -2003,10 +2005,12 @@ void _glfwRestoreWindowWayland(_GLFWwindow* window) { // We assume we are not minimized and acto only on maximization - if (window->wl.xdg.toplevel) + if (window->wl.maximized) { - if (window->wl.maximized) + if (window->wl.xdg.toplevel) xdg_toplevel_unset_maximized(window->wl.xdg.toplevel); + else + window->wl.maximized = GLFW_FALSE; } } } @@ -2015,6 +2019,8 @@ void _glfwMaximizeWindowWayland(_GLFWwindow* window) { if (window->wl.xdg.toplevel) xdg_toplevel_set_maximized(window->wl.xdg.toplevel); + else + window->wl.maximized = GLFW_TRUE; } void _glfwShowWindowWayland(_GLFWwindow* window) From 0cd1916de39b67878ae178f211921e5606c4485d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 15 Jun 2022 20:16:40 +0200 Subject: [PATCH 34/47] Wayland: Remove function only called once --- src/wl_window.c | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index efad74d9..d9fc1b4f 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -571,27 +571,6 @@ static const struct xdg_surface_listener xdgSurfaceListener = xdgSurfaceHandleConfigure }; -static void setXdgDecorations(_GLFWwindow* window) -{ - if (_glfw.wl.decorationManager) - { - window->wl.xdg.decoration = - zxdg_decoration_manager_v1_get_toplevel_decoration( - _glfw.wl.decorationManager, window->wl.xdg.toplevel); - zxdg_toplevel_decoration_v1_add_listener(window->wl.xdg.decoration, - &xdgDecorationListener, - window); - zxdg_toplevel_decoration_v1_set_mode( - window->wl.xdg.decoration, - ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); - } - else - { - window->wl.decorations.serverSide = GLFW_FALSE; - createDecorations(window); - } -} - static GLFWbool createXdgSurface(_GLFWwindow* window) { window->wl.xdg.surface = xdg_wm_base_get_xdg_surface(_glfw.wl.wmBase, @@ -634,7 +613,24 @@ static GLFWbool createXdgSurface(_GLFWwindow* window) xdg_toplevel_set_maximized(window->wl.xdg.toplevel); setIdleInhibitor(window, GLFW_FALSE); - setXdgDecorations(window); + + if (_glfw.wl.decorationManager) + { + window->wl.xdg.decoration = + zxdg_decoration_manager_v1_get_toplevel_decoration( + _glfw.wl.decorationManager, window->wl.xdg.toplevel); + zxdg_toplevel_decoration_v1_add_listener(window->wl.xdg.decoration, + &xdgDecorationListener, + window); + zxdg_toplevel_decoration_v1_set_mode( + window->wl.xdg.decoration, + ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + } + else + { + window->wl.decorations.serverSide = GLFW_FALSE; + createDecorations(window); + } } if (window->minwidth != GLFW_DONT_CARE && window->minheight != GLFW_DONT_CARE) From eb9c3bee71edd2f72cf212105cb8a9ff5c77a673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 20 Jun 2022 00:27:04 +0200 Subject: [PATCH 35/47] Wayland: Rename fallback decoration functions We are soon going to have three kinds of decorations; XDG, libdecor and our last resort fallback ones. --- src/wl_window.c | 70 ++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index d9fc1b4f..a83bde1b 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -192,11 +192,11 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image) return buffer; } -static void createDecoration(_GLFWdecorationWayland* decoration, - struct wl_surface* parent, - struct wl_buffer* buffer, - int x, int y, - int width, int height) +static void createFallbackDecoration(_GLFWdecorationWayland* decoration, + struct wl_surface* parent, + struct wl_buffer* buffer, + int x, int y, + int width, int height) { decoration->surface = wl_compositor_create_surface(_glfw.wl.compositor); decoration->subsurface = @@ -215,7 +215,7 @@ static void createDecoration(_GLFWdecorationWayland* decoration, wl_region_destroy(region); } -static void createDecorations(_GLFWwindow* window) +static void createFallbackDecorations(_GLFWwindow* window) { unsigned char data[] = { 224, 224, 224, 255 }; const GLFWimage image = { 1, 1, data }; @@ -228,25 +228,25 @@ static void createDecorations(_GLFWwindow* window) if (!window->wl.decorations.buffer) return; - createDecoration(&window->wl.decorations.top, window->wl.surface, - window->wl.decorations.buffer, - 0, -GLFW_CAPTION_HEIGHT, - window->wl.width, GLFW_CAPTION_HEIGHT); - createDecoration(&window->wl.decorations.left, window->wl.surface, - window->wl.decorations.buffer, - -GLFW_BORDER_SIZE, -GLFW_CAPTION_HEIGHT, - GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT); - createDecoration(&window->wl.decorations.right, window->wl.surface, - window->wl.decorations.buffer, - window->wl.width, -GLFW_CAPTION_HEIGHT, - GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT); - createDecoration(&window->wl.decorations.bottom, window->wl.surface, - window->wl.decorations.buffer, - -GLFW_BORDER_SIZE, window->wl.height, - window->wl.width + GLFW_BORDER_SIZE * 2, GLFW_BORDER_SIZE); + createFallbackDecoration(&window->wl.decorations.top, window->wl.surface, + window->wl.decorations.buffer, + 0, -GLFW_CAPTION_HEIGHT, + window->wl.width, GLFW_CAPTION_HEIGHT); + createFallbackDecoration(&window->wl.decorations.left, window->wl.surface, + window->wl.decorations.buffer, + -GLFW_BORDER_SIZE, -GLFW_CAPTION_HEIGHT, + GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT); + createFallbackDecoration(&window->wl.decorations.right, window->wl.surface, + window->wl.decorations.buffer, + window->wl.width, -GLFW_CAPTION_HEIGHT, + GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT); + createFallbackDecoration(&window->wl.decorations.bottom, window->wl.surface, + window->wl.decorations.buffer, + -GLFW_BORDER_SIZE, window->wl.height, + window->wl.width + GLFW_BORDER_SIZE * 2, GLFW_BORDER_SIZE); } -static void destroyDecoration(_GLFWdecorationWayland* decoration) +static void destroyFallbackDecoration(_GLFWdecorationWayland* decoration) { if (decoration->subsurface) wl_subsurface_destroy(decoration->subsurface); @@ -259,12 +259,12 @@ static void destroyDecoration(_GLFWdecorationWayland* decoration) decoration->viewport = NULL; } -static void destroyDecorations(_GLFWwindow* window) +static void destroyFallbackDecorations(_GLFWwindow* window) { - destroyDecoration(&window->wl.decorations.top); - destroyDecoration(&window->wl.decorations.left); - destroyDecoration(&window->wl.decorations.right); - destroyDecoration(&window->wl.decorations.bottom); + destroyFallbackDecoration(&window->wl.decorations.top); + destroyFallbackDecoration(&window->wl.decorations.left); + destroyFallbackDecoration(&window->wl.decorations.right); + destroyFallbackDecoration(&window->wl.decorations.bottom); } static void xdgDecorationHandleConfigure(void* userData, @@ -276,7 +276,7 @@ static void xdgDecorationHandleConfigure(void* userData, window->wl.decorations.serverSide = (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); if (!window->wl.decorations.serverSide) - createDecorations(window); + createFallbackDecorations(window); } static const struct zxdg_toplevel_decoration_v1_listener xdgDecorationListener = @@ -432,7 +432,7 @@ static void acquireMonitor(_GLFWwindow* window) setIdleInhibitor(window, GLFW_TRUE); if (!window->wl.decorations.serverSide) - destroyDecorations(window); + destroyFallbackDecorations(window); } // Remove the window and restore the original video mode @@ -445,7 +445,7 @@ static void releaseMonitor(_GLFWwindow* window) setIdleInhibitor(window, GLFW_FALSE); if (!_glfw.wl.decorationManager) - createDecorations(window); + createFallbackDecorations(window); } static void xdgToplevelHandleConfigure(void* userData, @@ -629,7 +629,7 @@ static GLFWbool createXdgSurface(_GLFWwindow* window) else { window->wl.decorations.serverSide = GLFW_FALSE; - createDecorations(window); + createFallbackDecorations(window); } } @@ -1818,7 +1818,7 @@ void _glfwDestroyWindowWayland(_GLFWwindow* window) if (window->context.destroy) window->context.destroy(window); - destroyDecorations(window); + destroyFallbackDecorations(window); if (window->wl.xdg.decoration) zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration); @@ -2136,9 +2136,9 @@ void _glfwSetWindowDecoratedWayland(_GLFWwindow* window, GLFWbool enabled) else { if (enabled) - createDecorations(window); + createFallbackDecorations(window); else - destroyDecorations(window); + destroyFallbackDecorations(window); } } From 83a134a92fa8642fe50c6e9b2400044e442d038a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 20 Jun 2022 00:43:24 +0200 Subject: [PATCH 36/47] Wayland: Fix mapping failure on wlroots compositor When showing a window that had already been shown once (and so already had its shell objects), GLFW would attach a new buffer and commit it before waiting for the next configure event. This was a violation of the XDG shell protocol. This was allowed to work as intended on GNOME and KDE without error. However wlroots based compositors would (correctly) emit an error. Unfortunately, I haven't been able to find a way to get both KDE, GNOME and Sway to send the configure event we need in order to map the wl_surface again while keeping our existing shell objects, so with this commit we now create them for each call to glfwShowWindow and destroy them for each call to glfwHideWindow. Fixes #1268 --- README.md | 2 ++ src/wl_window.c | 52 +++++++++++++++++++++++++++++++------------------ 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index d4a60417..b58dbe76 100644 --- a/README.md +++ b/README.md @@ -359,6 +359,8 @@ information on what to include when reporting a bug. applying the specified ratio - [Wayland] Bugfix: `GLFW_MAXIMIZED` window hint had no effect - [Wayland] Bugfix: `glfwRestoreWindow` had no effect before first show + - [Wayland] Bugfix: Hiding and then showing a window caused program abort on + wlroots compositors (#1268) - [POSIX] Removed use of deprecated function `gettimeofday` - [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled - [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072) diff --git a/src/wl_window.c b/src/wl_window.c index a83bde1b..8e61a70b 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -562,6 +562,14 @@ static void xdgSurfaceHandleConfigure(void* userData, resizeWindow(window); _glfwInputWindowSize(window, width, height); + + if (window->wl.visible) + _glfwInputWindowDamage(window); + } + + if (!window->wl.visible) + { + window->wl.visible = GLFW_TRUE; _glfwInputWindowDamage(window); } } @@ -571,7 +579,7 @@ static const struct xdg_surface_listener xdgSurfaceListener = xdgSurfaceHandleConfigure }; -static GLFWbool createXdgSurface(_GLFWwindow* window) +static GLFWbool createShellObjects(_GLFWwindow* window) { window->wl.xdg.surface = xdg_wm_base_get_xdg_surface(_glfw.wl.wmBase, window->wl.surface); @@ -667,6 +675,24 @@ static GLFWbool createXdgSurface(_GLFWwindow* window) return GLFW_TRUE; } +static void destroyShellObjects(_GLFWwindow* window) +{ + destroyFallbackDecorations(window); + + if (window->wl.xdg.decoration) + zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration); + + if (window->wl.xdg.toplevel) + xdg_toplevel_destroy(window->wl.xdg.toplevel); + + if (window->wl.xdg.surface) + xdg_surface_destroy(window->wl.xdg.surface); + + window->wl.xdg.decoration = NULL; + window->wl.xdg.toplevel = NULL; + window->wl.xdg.surface = NULL; +} + static GLFWbool createNativeSurface(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWfbconfig* fbconfig) @@ -706,10 +732,8 @@ static GLFWbool createNativeSurface(_GLFWwindow* window, if (window->monitor || wndconfig->visible) { - if (!createXdgSurface(window)) + if (!createShellObjects(window)) return GLFW_FALSE; - - window->wl.visible = GLFW_TRUE; } return GLFW_TRUE; @@ -1818,9 +1842,7 @@ void _glfwDestroyWindowWayland(_GLFWwindow* window) if (window->context.destroy) window->context.destroy(window); - destroyFallbackDecorations(window); - if (window->wl.xdg.decoration) - zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration); + destroyShellObjects(window); if (window->wl.decorations.buffer) wl_buffer_destroy(window->wl.decorations.buffer); @@ -1828,12 +1850,6 @@ void _glfwDestroyWindowWayland(_GLFWwindow* window) if (window->wl.egl.window) wl_egl_window_destroy(window->wl.egl.window); - if (window->wl.xdg.toplevel) - xdg_toplevel_destroy(window->wl.xdg.toplevel); - - if (window->wl.xdg.surface) - xdg_surface_destroy(window->wl.xdg.surface); - if (window->wl.surface) wl_surface_destroy(window->wl.surface); @@ -2021,15 +2037,11 @@ void _glfwMaximizeWindowWayland(_GLFWwindow* window) void _glfwShowWindowWayland(_GLFWwindow* window) { - if (!window->wl.visible) + if (!window->wl.xdg.toplevel) { // NOTE: The XDG surface and role are created here so command-line applications // with off-screen windows do not appear in for example the Unity dock - if (!window->wl.xdg.toplevel) - createXdgSurface(window); - - window->wl.visible = GLFW_TRUE; - _glfwInputWindowDamage(window); + createShellObjects(window); } } @@ -2038,6 +2050,8 @@ void _glfwHideWindowWayland(_GLFWwindow* window) if (window->wl.visible) { window->wl.visible = GLFW_FALSE; + destroyShellObjects(window); + wl_surface_attach(window->wl.surface, NULL, 0, 0); wl_surface_commit(window->wl.surface); } From 2df0ce07faead09b1d305d30cf68d95c1145c37c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 20 Jun 2022 22:20:56 +0200 Subject: [PATCH 37/47] Wayland: Store and act on XDG decoration mode Refer to the XDG decoration mode (or the lack of one) directly instead of setting a boolean in a struct meant for the fallback decorations. This makes things a bit more verbose but is in preparation for a refactoring of all decoration paths. --- src/wl_platform.h | 2 +- src/wl_window.c | 16 +++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/wl_platform.h b/src/wl_platform.h index d8d94822..b3d23da0 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -251,6 +251,7 @@ typedef struct _GLFWwindowWayland struct xdg_surface* surface; struct xdg_toplevel* toplevel; struct zxdg_toplevel_decoration_v1* decoration; + uint32_t decorationMode; } xdg; _GLFWcursor* currentCursor; @@ -273,7 +274,6 @@ typedef struct _GLFWwindowWayland struct zwp_idle_inhibitor_v1* idleInhibitor; struct { - GLFWbool serverSide; struct wl_buffer* buffer; _GLFWdecorationWayland top, left, right, bottom; int focus; diff --git a/src/wl_window.c b/src/wl_window.c index 8e61a70b..44f1df7b 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -220,7 +220,7 @@ static void createFallbackDecorations(_GLFWwindow* window) unsigned char data[] = { 224, 224, 224, 255 }; const GLFWimage image = { 1, 1, data }; - if (!_glfw.wl.viewporter || !window->decorated || window->wl.decorations.serverSide) + if (!_glfw.wl.viewporter || !window->decorated) return; if (!window->wl.decorations.buffer) @@ -273,9 +273,9 @@ static void xdgDecorationHandleConfigure(void* userData, { _GLFWwindow* window = userData; - window->wl.decorations.serverSide = (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + window->wl.xdg.decorationMode = mode; - if (!window->wl.decorations.serverSide) + if (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE) createFallbackDecorations(window); } @@ -431,7 +431,7 @@ static void acquireMonitor(_GLFWwindow* window) setIdleInhibitor(window, GLFW_TRUE); - if (!window->wl.decorations.serverSide) + if (window->wl.decorations.top.surface) destroyFallbackDecorations(window); } @@ -444,7 +444,7 @@ static void releaseMonitor(_GLFWwindow* window) setIdleInhibitor(window, GLFW_FALSE); - if (!_glfw.wl.decorationManager) + if (window->wl.xdg.decorationMode != ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE) createFallbackDecorations(window); } @@ -635,10 +635,7 @@ static GLFWbool createShellObjects(_GLFWwindow* window) ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); } else - { - window->wl.decorations.serverSide = GLFW_FALSE; createFallbackDecorations(window); - } } if (window->minwidth != GLFW_DONT_CARE && window->minheight != GLFW_DONT_CARE) @@ -689,6 +686,7 @@ static void destroyShellObjects(_GLFWwindow* window) xdg_surface_destroy(window->wl.xdg.surface); window->wl.xdg.decoration = NULL; + window->wl.xdg.decorationMode = 0; window->wl.xdg.toplevel = NULL; window->wl.xdg.surface = NULL; } @@ -1978,7 +1976,7 @@ void _glfwGetWindowFrameSizeWayland(_GLFWwindow* window, int* left, int* top, int* right, int* bottom) { - if (window->decorated && !window->monitor && !window->wl.decorations.serverSide) + if (window->decorated && !window->monitor && window->wl.decorations.top.surface) { if (top) *top = GLFW_CAPTION_HEIGHT; From 3203599cac774c4aa48dc17eb963f4a90c6d70ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 20 Jun 2022 22:21:41 +0200 Subject: [PATCH 38/47] Wayland: Fix map before XDG decoration configure If the xdg_toplevel has a decoration, we need to wait for its first configure event as well before we are allowed to attach the first buffer. It seems racy to assume that this will always happen inside the first surface configure sequence, so this commit makes that condition explicit. This may turn out to have been overly defensive. --- src/wl_window.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index 44f1df7b..737274f7 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -569,8 +569,13 @@ static void xdgSurfaceHandleConfigure(void* userData, if (!window->wl.visible) { - window->wl.visible = GLFW_TRUE; - _glfwInputWindowDamage(window); + // Allow the window to be mapped only if it either has no XDG + // decorations or they have already received a configure event + if (!window->wl.xdg.decoration || window->wl.xdg.decorationMode) + { + window->wl.visible = GLFW_TRUE; + _glfwInputWindowDamage(window); + } } } From f35e2274cbf253b659e9847354fe72d7b45dcc9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 20 Jun 2022 22:36:23 +0200 Subject: [PATCH 39/47] Wayland: Fix GLFW_DECORATED for XDG decorations On a compositor that supports server-side decorations, they were always enabled in windowed mode, even if GLFW_DECORATED was cleared. --- README.md | 2 ++ src/wl_window.c | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b58dbe76..be47a336 100644 --- a/README.md +++ b/README.md @@ -361,6 +361,8 @@ information on what to include when reporting a bug. - [Wayland] Bugfix: `glfwRestoreWindow` had no effect before first show - [Wayland] Bugfix: Hiding and then showing a window caused program abort on wlroots compositors (#1268) + - [Wayland] Bugfix: `GLFW_DECORATED` was ignored when showing a window with XDG + decorations - [POSIX] Removed use of deprecated function `gettimeofday` - [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled - [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072) diff --git a/src/wl_window.c b/src/wl_window.c index 737274f7..a3d9601b 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -635,9 +635,15 @@ static GLFWbool createShellObjects(_GLFWwindow* window) zxdg_toplevel_decoration_v1_add_listener(window->wl.xdg.decoration, &xdgDecorationListener, window); - zxdg_toplevel_decoration_v1_set_mode( - window->wl.xdg.decoration, - ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + + uint32_t mode; + + if (window->decorated) + mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; + else + mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; + + zxdg_toplevel_decoration_v1_set_mode(window->wl.xdg.decoration, mode); } else createFallbackDecorations(window); From 29b7669bc6a42de729a59abc96ce8849654751c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 20 Jun 2022 22:48:35 +0200 Subject: [PATCH 40/47] Wayland: Fix transition to server-side decorations --- src/wl_window.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wl_window.c b/src/wl_window.c index a3d9601b..300dc571 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -277,6 +277,8 @@ static void xdgDecorationHandleConfigure(void* userData, if (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE) createFallbackDecorations(window); + else + destroyFallbackDecorations(window); } static const struct zxdg_toplevel_decoration_v1_listener xdgDecorationListener = From 80dc0533cf7234517328537a54b7675f0588713c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 20 Jun 2022 22:57:18 +0200 Subject: [PATCH 41/47] Wayland: Use enum type to store enum value --- src/wl_platform.h | 2 +- src/wl_window.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wl_platform.h b/src/wl_platform.h index b3d23da0..b85d79a5 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -276,7 +276,7 @@ typedef struct _GLFWwindowWayland struct { struct wl_buffer* buffer; _GLFWdecorationWayland top, left, right, bottom; - int focus; + _GLFWdecorationSideWayland focus; } decorations; } _GLFWwindowWayland; diff --git a/src/wl_window.c b/src/wl_window.c index 300dc571..bf646a21 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -976,9 +976,9 @@ static char* readDataOfferAsString(struct wl_data_offer* offer, const char* mime } static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface, - int* which) + _GLFWdecorationSideWayland* which) { - int focus; + _GLFWdecorationSideWayland focus; _GLFWwindow* window = _glfw.windowListHead; if (!which) which = &focus; @@ -1020,7 +1020,7 @@ static void pointerHandleEnter(void* userData, if (!surface) return; - int focus = 0; + _GLFWdecorationSideWayland focus = mainWindow; _GLFWwindow* window = wl_surface_get_user_data(surface); if (!window) { From 47193f15de529b6e7c182168b1c17f29bda9de4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 21 Jun 2022 15:23:32 +0200 Subject: [PATCH 42/47] Wayland: Rename function to its purpose --- src/wl_window.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index bf646a21..4b393756 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -287,7 +287,7 @@ static const struct zxdg_toplevel_decoration_v1_listener xdgDecorationListener = }; // Makes the surface considered as XRGB instead of ARGB. -static void setOpaqueRegion(_GLFWwindow* window) +static void setContentAreaOpaque(_GLFWwindow* window) { struct wl_region* region; @@ -309,7 +309,7 @@ static void resizeWindow(_GLFWwindow* window) int scaledHeight = window->wl.height * scale; wl_egl_window_resize(window->wl.egl.window, scaledWidth, scaledHeight, 0, 0); if (!window->wl.transparent) - setOpaqueRegion(window); + setContentAreaOpaque(window); _glfwInputFramebufferSize(window, scaledWidth, scaledHeight); if (!window->wl.decorations.top.surface) @@ -739,7 +739,7 @@ static GLFWbool createNativeSurface(_GLFWwindow* window, window->wl.transparent = fbconfig->transparent; if (!window->wl.transparent) - setOpaqueRegion(window); + setContentAreaOpaque(window); if (window->monitor || wndconfig->visible) { From be7f4513c05a45e6252f940408e139741a462986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 21 Jun 2022 17:37:37 +0200 Subject: [PATCH 43/47] Wayland: Remove premature surface commit calls Note that the handling of configure events, acks and commits is still not ideal. This is just a small step in, hopefully, a good direction. Fullscreen toggling via glfwSetWindowMonitor now works on Weston, but mostly incidentally. --- src/wl_window.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index 4b393756..fb576310 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -297,7 +297,6 @@ static void setContentAreaOpaque(_GLFWwindow* window) wl_region_add(region, 0, 0, window->wl.width, window->wl.height); wl_surface_set_opaque_region(window->wl.surface, region); - wl_surface_commit(window->wl.surface); wl_region_destroy(region); } @@ -2183,8 +2182,6 @@ void _glfwSetWindowMousePassthroughWayland(_GLFWwindow* window, GLFWbool enabled } else wl_surface_set_input_region(window->wl.surface, 0); - - wl_surface_commit(window->wl.surface); } float _glfwGetWindowOpacityWayland(_GLFWwindow* window) @@ -2247,7 +2244,6 @@ void _glfwSetCursorPosWayland(_GLFWwindow* window, double x, double y) zwp_locked_pointer_v1_set_cursor_position_hint( window->wl.pointerLock.lockedPointer, wl_fixed_from_double(x), wl_fixed_from_double(y)); - wl_surface_commit(window->wl.surface); } } From c4fbe80d90ac7f4bd2fc0f02afccdc4d45489cbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 21 Jun 2022 19:37:35 +0200 Subject: [PATCH 44/47] Wayland: Make function behavior match name The logic that checks the decorated attribute belongs on the outside along with other related checks (fullscreen, monitor, decoration mode). --- src/wl_window.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index fb576310..d131534e 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -220,7 +220,7 @@ static void createFallbackDecorations(_GLFWwindow* window) unsigned char data[] = { 224, 224, 224, 255 }; const GLFWimage image = { 1, 1, data }; - if (!_glfw.wl.viewporter || !window->decorated) + if (!_glfw.wl.viewporter) return; if (!window->wl.decorations.buffer) @@ -276,7 +276,10 @@ static void xdgDecorationHandleConfigure(void* userData, window->wl.xdg.decorationMode = mode; if (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE) - createFallbackDecorations(window); + { + if (window->decorated) + createFallbackDecorations(window); + } else destroyFallbackDecorations(window); } @@ -446,7 +449,10 @@ static void releaseMonitor(_GLFWwindow* window) setIdleInhibitor(window, GLFW_FALSE); if (window->wl.xdg.decorationMode != ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE) - createFallbackDecorations(window); + { + if (window->decorated) + createFallbackDecorations(window); + } } static void xdgToplevelHandleConfigure(void* userData, @@ -647,7 +653,10 @@ static GLFWbool createShellObjects(_GLFWwindow* window) zxdg_toplevel_decoration_v1_set_mode(window->wl.xdg.decoration, mode); } else - createFallbackDecorations(window); + { + if (window->decorated) + createFallbackDecorations(window); + } } if (window->minwidth != GLFW_DONT_CARE && window->minheight != GLFW_DONT_CARE) From 74b4ceb8354bbe3eb4d225bcc07c4ed4023ca1f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 21 Jun 2022 19:48:28 +0200 Subject: [PATCH 45/47] Wayland: Cleanup This moves what is effectively showing the window to where that is done on other platforms, i.e. last in the platform CreateWindow function. --- src/wl_window.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index d131534e..072b3ba7 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -749,12 +749,6 @@ static GLFWbool createNativeSurface(_GLFWwindow* window, if (!window->wl.transparent) setContentAreaOpaque(window); - if (window->monitor || wndconfig->visible) - { - if (!createShellObjects(window)) - return GLFW_FALSE; - } - return GLFW_TRUE; } @@ -1839,6 +1833,12 @@ GLFWbool _glfwCreateWindowWayland(_GLFWwindow* window, if (wndconfig->mousePassthrough) _glfwSetWindowMousePassthroughWayland(window, GLFW_TRUE); + if (window->monitor || wndconfig->visible) + { + if (!createShellObjects(window)) + return GLFW_FALSE; + } + return GLFW_TRUE; } From d578c2ddfeb6a31c532ddc29de289762745548d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 21 Jun 2022 19:52:39 +0200 Subject: [PATCH 46/47] Wayland: Only create EGL window if using EGL --- src/wl_window.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/wl_window.c b/src/wl_window.c index 072b3ba7..e33076bb 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -309,7 +309,9 @@ static void resizeWindow(_GLFWwindow* window) int scale = window->wl.scale; int scaledWidth = window->wl.width * scale; int scaledHeight = window->wl.height * scale; - wl_egl_window_resize(window->wl.egl.window, scaledWidth, scaledHeight, 0, 0); + + if (window->wl.egl.window) + wl_egl_window_resize(window->wl.egl.window, scaledWidth, scaledHeight, 0, 0); if (!window->wl.transparent) setContentAreaOpaque(window); _glfwInputFramebufferSize(window, scaledWidth, scaledHeight); @@ -729,15 +731,6 @@ static GLFWbool createNativeSurface(_GLFWwindow* window, wl_surface_set_user_data(window->wl.surface, window); - window->wl.egl.window = wl_egl_window_create(window->wl.surface, - wndconfig->width, - wndconfig->height); - if (!window->wl.egl.window) - { - _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Failed to create EGL window"); - return GLFW_FALSE; - } - window->wl.width = wndconfig->width; window->wl.height = wndconfig->height; window->wl.scale = 1; @@ -1813,6 +1806,16 @@ GLFWbool _glfwCreateWindowWayland(_GLFWwindow* window, if (ctxconfig->source == GLFW_EGL_CONTEXT_API || ctxconfig->source == GLFW_NATIVE_CONTEXT_API) { + window->wl.egl.window = wl_egl_window_create(window->wl.surface, + wndconfig->width, + wndconfig->height); + if (!window->wl.egl.window) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to create EGL window"); + return GLFW_FALSE; + } + if (!_glfwInitEGL()) return GLFW_FALSE; if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) From da6713cd096a40a4512f468b34c189017e73f987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 21 Jun 2022 20:50:48 +0200 Subject: [PATCH 47/47] Wayland: Do not decorate fullscreen windows If a fullscreen window with GLFW_DECORATED set had its XDG decorations changed to client mode by the compositor, it would seemingly receive GLFW fallback decorations as if it was windowed mode. This is possibly related to #2001. --- src/wl_window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wl_window.c b/src/wl_window.c index e33076bb..b2930c5e 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -277,7 +277,7 @@ static void xdgDecorationHandleConfigure(void* userData, if (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE) { - if (window->decorated) + if (window->decorated && !window->monitor) createFallbackDecorations(window); } else