diff --git a/hyprtester/src/tests/main/window.cpp b/hyprtester/src/tests/main/window.cpp index 374427904..0a2e31d05 100644 --- a/hyprtester/src/tests/main/window.cpp +++ b/hyprtester/src/tests/main/window.cpp @@ -373,6 +373,41 @@ static void testMaximizeSize() { EXPECT(Tests::windowCount(), 0); } +static void testGroupFallbackFocus() { + NLog::log("{}Testing group fallback focus", Colors::GREEN); + + EXPECT(spawnKitty("kitty_A"), true); + + OK(getFromSocket("/dispatch togglegroup")); + + EXPECT(spawnKitty("kitty_B"), true); + EXPECT(spawnKitty("kitty_C"), true); + EXPECT(spawnKitty("kitty_D"), true); + + { + auto str = getFromSocket("/activewindow"); + EXPECT(str.contains("class: kitty_D"), true); + } + + OK(getFromSocket("/dispatch focuswindow class:kitty_B")); + OK(getFromSocket("/dispatch focuswindow class:kitty_D")); + OK(getFromSocket("/dispatch killactive")); + + Tests::waitUntilWindowsN(3); + + // Focus must return to the last focus, in this case B. + { + auto str = getFromSocket("/activewindow"); + EXPECT(str.contains("class: kitty_B"), true); + } + + NLog::log("{}Killing all windows", Colors::YELLOW); + Tests::killAllWindows(); + + NLog::log("{}Expecting 0 windows", Colors::YELLOW); + EXPECT(Tests::windowCount(), 0); +} + static void testBringActiveToTopMouseMovement() { NLog::log("{}Testing bringactivetotop mouse movement", Colors::GREEN); @@ -847,6 +882,8 @@ static bool test() { testBringActiveToTopMouseMovement(); + testGroupFallbackFocus(); + NLog::log("{}Reloading config", Colors::YELLOW); OK(getFromSocket("/reload")); diff --git a/src/desktop/view/Window.cpp b/src/desktop/view/Window.cpp index 695ba81f9..b0e6a365a 100644 --- a/src/desktop/view/Window.cpp +++ b/src/desktop/view/Window.cpp @@ -2437,7 +2437,24 @@ void CWindow::unmapWindow() { } bool wasLastWindow = false; - PHLWINDOW nextInGroup = m_groupData.pNextWindow ? m_groupData.pNextWindow.lock() : nullptr; + PHLWINDOW nextInGroup = [this] -> PHLWINDOW { + if (!m_groupData.pNextWindow) + return nullptr; + + // walk the history to find a suitable window + const auto HISTORY = Desktop::History::windowTracker()->fullHistory(); + for (const auto& w : HISTORY | std::views::reverse) { + if (!w || !w->m_isMapped || w == m_self) + continue; + + if (!hasInGroup(w.lock())) + continue; + + return w.lock(); + } + + return nullptr; + }(); if (m_self.lock() == Desktop::focusState()->window()) { wasLastWindow = true;