From 5b1b79c29c5e0ea974b2a9da5d122dd0f3bedca6 Mon Sep 17 00:00:00 2001 From: John Mylchreest Date: Thu, 8 Jan 2026 21:27:00 +0000 Subject: fix: handle fullscreen windows on special workspaces (#12851) * fix: handle fullscreen windows on special workspaces inFullscreenMode() only checked m_activeWorkspace, missing fullscreen windows on special workspaces. This caused crashes and incorrect behavior when fullscreen windows were on special workspaces. Changes: - inFullscreenMode() now checks special workspace first since it renders on top of regular workspaces - Added getFullscreenWindow() helper to safely get fullscreen window from either active or special workspace - Updated callers (shouldSkipScheduleFrameOnMouseEvent, Renderer, getFSImageDescription) to use the new helper - Reset m_aboveFullscreen for layer surfaces when opening, closing, or stealing special workspaces between monitors * test: add special workspace fullscreen detection tests Add tests for the new special workspace fullscreen handling introduced in the previous commit. The tests cover: 1. Fullscreen detection on special workspace - verifies that a window made fullscreen on a special workspace is correctly detected 2. Special workspace fullscreen precedence - verifies that when both regular and special workspaces have fullscreen windows, the special workspace window can be focused when the special workspace is opened 3. Toggle special workspace behavior - verifies that toggling the special workspace off properly hides it and returns focus to the regular workspace's fullscreen window These tests exercise the key code paths modified in the fix: - inFullscreenMode() checking special workspace first - getFullscreenWindow() helper returning correct window - Layer surface m_aboveFullscreen reset on special workspace toggle --- hyprtester/src/tests/main/workspaces.cpp | 87 ++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) (limited to 'hyprtester/src/tests/main/workspaces.cpp') diff --git a/hyprtester/src/tests/main/workspaces.cpp b/hyprtester/src/tests/main/workspaces.cpp index c1b9690a..036ddaf5 100644 --- a/hyprtester/src/tests/main/workspaces.cpp +++ b/hyprtester/src/tests/main/workspaces.cpp @@ -20,6 +20,91 @@ using namespace Hyprutils::Utils; #define UP CUniquePointer #define SP CSharedPointer +static bool testSpecialWorkspaceFullscreen() { + NLog::log("{}Testing special workspace fullscreen detection", Colors::YELLOW); + + CScopeGuard guard = {[&]() { + NLog::log("{}Cleaning up special workspace fullscreen test", Colors::YELLOW); + // Close special workspace if open + auto monitors = getFromSocket("/monitors"); + if (monitors.contains("(special:test_fs_special)") && !monitors.contains("special workspace: 0 ()")) + getFromSocket("/dispatch togglespecialworkspace test_fs_special"); + Tests::killAllWindows(); + OK(getFromSocket("/reload")); + }}; + + getFromSocket("/dispatch workspace 1"); + EXPECT(Tests::windowCount(), 0); + + NLog::log("{}Test 1: Fullscreen detection on special workspace", Colors::YELLOW); + + OK(getFromSocket("/dispatch workspace special:test_fs_special")); + + if (!Tests::spawnKitty("kitty_special")) + return false; + + { + auto str = getFromSocket("/activewindow"); + EXPECT_CONTAINS(str, "class: kitty_special"); + EXPECT_CONTAINS(str, "(special:test_fs_special)"); + } + + OK(getFromSocket("/dispatch fullscreen 0")); + + { + auto str = getFromSocket("/activewindow"); + EXPECT_CONTAINS(str, "fullscreen: 2"); + } + + { + auto str = getFromSocket("/monitors"); + EXPECT_CONTAINS(str, "(special:test_fs_special)"); + } + + NLog::log("{}Test 2: Special workspace fullscreen precedence", Colors::YELLOW); + + // Close special workspace before spawning on regular workspace + OK(getFromSocket("/dispatch togglespecialworkspace test_fs_special")); + getFromSocket("/dispatch workspace 1"); + + if (!Tests::spawnKitty("kitty_regular")) + return false; + + OK(getFromSocket("/dispatch fullscreen 0")); + + { + auto str = getFromSocket("/activewindow"); + EXPECT_CONTAINS(str, "class: kitty_regular"); + EXPECT_CONTAINS(str, "fullscreen: 2"); + } + + OK(getFromSocket("/dispatch togglespecialworkspace test_fs_special")); + OK(getFromSocket("/dispatch focuswindow class:kitty_special")); + + { + auto str = getFromSocket("/activewindow"); + EXPECT_CONTAINS(str, "class: kitty_special"); + } + + NLog::log("{}Test 3: Toggle special workspace hides it", Colors::YELLOW); + + OK(getFromSocket("/dispatch togglespecialworkspace test_fs_special")); + OK(getFromSocket("/dispatch focuswindow class:kitty_regular")); + + { + auto str = getFromSocket("/activewindow"); + EXPECT_CONTAINS(str, "class: kitty_regular"); + EXPECT_CONTAINS(str, "fullscreen: 2"); + } + + { + auto str = getFromSocket("/monitors"); + EXPECT_CONTAINS(str, "special workspace: 0 ()"); + } + + return true; +} + static bool testAsymmetricGaps() { NLog::log("{}Testing asymmetric gap splits", Colors::YELLOW); { @@ -449,6 +534,8 @@ static bool test() { NLog::log("{}Killing all windows", Colors::YELLOW); Tests::killAllWindows(); + testSpecialWorkspaceFullscreen(); + testAsymmetricGaps(); NLog::log("{}Expecting 0 windows", Colors::YELLOW); -- cgit v1.2.3