diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 2ed1a951..c51b06d0 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1,4 +1,5 @@ #include "Compositor.hpp" +#include "desktop/DesktopTypes.hpp" #include "helpers/Splashes.hpp" #include "config/ConfigValue.hpp" #include "managers/CursorManager.hpp" @@ -6,6 +7,7 @@ #include "managers/PointerManager.hpp" #include "managers/SeatManager.hpp" #include "managers/eventLoop/EventLoopManager.hpp" +#include #include #include #include "debug/HyprCtl.hpp" @@ -671,6 +673,30 @@ CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) { return mon.get(); } +SP CCompositor::getNextMonitor(uint64_t curID, bool reverse) { + const auto LN = m_vMonitors.size(); + if (LN == 1) { + return m_vMonitors[0]; + } + + size_t curPos = LN + 1; + for (size_t i = 0; i < LN; i++) { + if (m_vMonitors[i]->ID == curID) { + curPos = i; + } + } + + if (curPos == LN && !reverse) { + return m_vMonitors[0]; + } + + if (curPos == 0 && reverse) { + return m_vMonitors[LN - 1]; + } + + return reverse ? m_vMonitors[curPos - 1] : m_vMonitors[curPos + 1]; +} + void CCompositor::removeWindowFromVectorSafe(PHLWINDOW pWindow) { if (!pWindow->m_bFadingOut) { EMIT_HOOK_EVENT("destroyWindow", pWindow); @@ -1565,29 +1591,14 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { return nullptr; } +bool isWindowMatch(PHLWINDOW pWindow, bool focusableOnly, std::optional floating, const PHLWINDOW& w) { + return (!floating.has_value() || w->m_bIsFloating == floating.value()) && w != pWindow && w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && + (!focusableOnly || !w->m_sAdditionalConfigData.noFocus); +} + PHLWINDOW CCompositor::getNextWindowOnWorkspace(PHLWINDOW pWindow, bool focusableOnly, std::optional floating) { - bool gotToWindow = false; - for (auto& w : m_vWindows) { - if (w != pWindow && !gotToWindow) - continue; - - if (w == pWindow) { - gotToWindow = true; - continue; - } - - if (floating.has_value() && w->m_bIsFloating != floating.value()) - continue; - - if (w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus)) - return w; - } - - for (auto& w : m_vWindows) { - if (floating.has_value() && w->m_bIsFloating != floating.value()) - continue; - - if (w != pWindow && w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus)) + for (const auto& w : m_vWindows) { + if (isWindowMatch(pWindow, focusableOnly, floating, w)) return w; } @@ -1595,29 +1606,50 @@ PHLWINDOW CCompositor::getNextWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl } PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusableOnly, std::optional floating) { - bool gotToWindow = false; - for (auto& w : m_vWindows | std::views::reverse) { - if (w != pWindow && !gotToWindow) - continue; - - if (w == pWindow) { - gotToWindow = true; - continue; - } - - if (floating.has_value() && w->m_bIsFloating != floating.value()) - continue; - - if (w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus)) + for (const auto& w : m_vWindows | std::views::reverse) { + if (isWindowMatch(pWindow, focusableOnly, floating, w)) return w; } - for (auto& w : m_vWindows | std::views::reverse) { - if (floating.has_value() && w->m_bIsFloating != floating.value()) - continue; + return nullptr; +} - if (w != pWindow && w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus)) +PHLWINDOW CCompositor::getNextVisibleWindow(PHLWINDOW pWindow, bool focusableOnly, std::optional floating) { + if (pWindow == getTopLeftWindowOnWorkspace(pWindow->workspaceID())) + if (const auto& w = getWindowOnAnotherMonitor(pWindow->m_iMonitorID, floating, true); w && m_pLastWindow->m_iMonitorID == w->m_iMonitorID) return w; + + for (const auto& w : m_vWindows) { + if (isWindowMatch(pWindow, focusableOnly, floating, w)) + return w; + } + + return nullptr; +} + +PHLWINDOW CCompositor::getPrevVisibleWindow(PHLWINDOW pWindow, bool focusableOnly, std::optional floating) { + if (pWindow == getTopLeftWindowOnWorkspace(pWindow->workspaceID())) + if (const auto& w = getWindowOnAnotherMonitor(pWindow->m_iMonitorID, floating, true); w && m_pLastWindow->m_iMonitorID == w->m_iMonitorID) + return w; + + for (const auto& w : m_vWindows | std::views::reverse) { + if (isWindowMatch(pWindow, focusableOnly, floating, w)) + return w; + } + + return nullptr; +} + +PHLWINDOW CCompositor::getWindowOnAnotherMonitor(uint64_t curMonID, std::optional floating, bool reverse) { + for (auto mon = getNextMonitor(curMonID, reverse); mon->ID != curMonID; mon = getNextMonitor(curMonID, reverse)) { + if (mon->activeWorkspace == nullptr) { + curMonID = mon->ID; + continue; + } + + if (const auto w = mon->activeWorkspace->getLastFocusedWindow(); w && (!floating.has_value() || floating.value() == w->m_bIsFloating)) { + return w; + } } return nullptr; diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 5a1d8a64..06289664 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -107,6 +107,7 @@ class CCompositor { CMonitor* getMonitorFromDesc(const std::string&); CMonitor* getMonitorFromCursor(); CMonitor* getMonitorFromVector(const Vector2D&); + SP getNextMonitor(uint64_t cur, bool reverse = false); void removeWindowFromVectorSafe(PHLWINDOW); void focusWindow(PHLWINDOW, SP pSurface = nullptr); void focusSurface(SP, PHLWINDOW pWindowOwner = nullptr); @@ -139,8 +140,11 @@ class CCompositor { void changeWindowZOrder(PHLWINDOW, bool); void cleanupFadingOut(const int& monid); PHLWINDOW getWindowInDirection(PHLWINDOW, char); + PHLWINDOW getNextVisibleWindow(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}); + PHLWINDOW getPrevVisibleWindow(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}); PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}); PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}); + PHLWINDOW getWindowOnAnotherMonitor(uint64_t curMonID, std::optional floating = {}, bool reverse = false); int getNextAvailableNamedWorkspace(); bool isPointOnAnyMonitor(const Vector2D&); bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 02438d43..ca0ac30a 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -11,6 +11,7 @@ #include "debug/Log.hpp" #include "helpers/varlist/VarList.hpp" +#include #include #include #include @@ -91,6 +92,7 @@ CKeybindManager::CKeybindManager() { m_mDispatchers["resizeactive"] = resizeActive; m_mDispatchers["moveactive"] = moveActive; m_mDispatchers["cyclenext"] = circleNext; + m_mDispatchers["cyclenextvisible"] = circleNextVisible; m_mDispatchers["focuswindowbyclass"] = focusWindow; m_mDispatchers["focuswindow"] = focusWindow; m_mDispatchers["tagwindow"] = tagWindow; @@ -311,8 +313,10 @@ bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) { } void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) { - const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); + if (PWINDOWTOCHANGETO == nullptr) + return; + const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); if (PWINDOWTOCHANGETO == PLASTWINDOW || !PWINDOWTOCHANGETO) return; @@ -330,23 +334,23 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) { if (!PWINDOWTOCHANGETO->m_bPinned) g_pCompositor->setWindowFullscreen(PWINDOWTOCHANGETO, true, FSMODE); - } else { - updateRelativeCursorCoords(); - g_pCompositor->focusWindow(PWINDOWTOCHANGETO); - PWINDOWTOCHANGETO->warpCursor(); - - g_pInputManager->m_pForcedFocus = PWINDOWTOCHANGETO; - g_pInputManager->simulateMouseMovement(); - g_pInputManager->m_pForcedFocus.reset(); - - if (PLASTWINDOW && PLASTWINDOW->m_iMonitorID != PWINDOWTOCHANGETO->m_iMonitorID) { - // event - const auto PNEWMON = g_pCompositor->getMonitorFromID(PWINDOWTOCHANGETO->m_iMonitorID); - - g_pCompositor->setActiveMonitor(PNEWMON); - } + return; } -}; + updateRelativeCursorCoords(); + g_pCompositor->focusWindow(PWINDOWTOCHANGETO); + PWINDOWTOCHANGETO->warpCursor(); + + g_pInputManager->m_pForcedFocus = PWINDOWTOCHANGETO; + g_pInputManager->simulateMouseMovement(); + g_pInputManager->m_pForcedFocus.reset(); + + if (!PLASTWINDOW || PLASTWINDOW->m_iMonitorID == PWINDOWTOCHANGETO->m_iMonitorID) + return; + + // event + const auto PNEWMON = g_pCompositor->getMonitorFromID(PWINDOWTOCHANGETO->m_iMonitorID); + g_pCompositor->setActiveMonitor(PNEWMON); +} bool CKeybindManager::onKeyEvent(std::any event, SP pKeyboard) { if (!g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) { @@ -1904,31 +1908,48 @@ void CKeybindManager::resizeWindow(std::string args) { PWINDOW->setHidden(false); } +std::optional getFloatStatus(CVarList args) { + if (args.contains("tile") || args.contains("tiled")) + return false; + if (args.contains("float") || args.contains("floating")) + return true; + + return std::nullopt; +} + +bool argsIsPrevious(CVarList args) { + return args.contains("prev") || args.contains("p") || args.contains("last") || args.contains("l"); +} + void CKeybindManager::circleNext(std::string arg) { - if (g_pCompositor->m_pLastWindow.expired()) { - // if we have a clear focus, find the first window and get the next focusable. - if (g_pCompositor->getWindowsOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspaceID()) > 0) { - const auto PWINDOW = g_pCompositor->getFirstWindowOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspaceID()); + if (g_pCompositor->getWindowsOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspaceID()) <= 0) + return; // if we have a clear focus, find the first window and get the next focusable. - switchToWindow(PWINDOW); - } - - return; + const auto PWINDOW = g_pCompositor->getFirstWindowOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspaceID()); + switchToWindow(PWINDOW); } - CVarList args{arg, 0, 's', true}; - - std::optional floatStatus = {}; - if (args.contains("tile") || args.contains("tiled")) - floatStatus = false; - else if (args.contains("float") || args.contains("floating")) - floatStatus = true; - - if (args.contains("prev") || args.contains("p") || args.contains("last") || args.contains("l")) - switchToWindow(g_pCompositor->getPrevWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, floatStatus)); + CVarList args{arg, 0, 's', true}; + if (argsIsPrevious(arg)) + switchToWindow(g_pCompositor->getPrevWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, getFloatStatus(arg))); else - switchToWindow(g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, floatStatus)); + switchToWindow(g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, getFloatStatus(arg))); +} + +void CKeybindManager::circleNextVisible(std::string arg) { + if (g_pCompositor->m_pLastWindow.expired()) { + if (g_pCompositor->getWindowsOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspaceID()) <= 0) + return; // if we have a clear focus, find the first window and get the next focusable. + const auto PWINDOW = g_pCompositor->getFirstWindowOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspaceID()); + switchToWindow(PWINDOW); + } + + CVarList args{arg, 0, 's', true}; + if (argsIsPrevious(args)) + switchToWindow(g_pCompositor->getPrevVisibleWindow(g_pCompositor->m_pLastWindow.lock(), true, getFloatStatus(args))); + else + switchToWindow(g_pCompositor->getNextVisibleWindow(g_pCompositor->m_pLastWindow.lock(), true, getFloatStatus(args))); } void CKeybindManager::focusWindow(std::string regexp) { diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 2a256760..60c649b3 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -182,6 +182,7 @@ class CKeybindManager { static void moveWindow(std::string); static void resizeWindow(std::string); static void circleNext(std::string); + static void circleNextVisible(std::string); static void focusWindow(std::string); static void tagWindow(std::string); static void setSubmap(std::string);