diff --git a/src/Window.hpp b/src/Window.hpp index 21169796..0ee164dc 100644 --- a/src/Window.hpp +++ b/src/Window.hpp @@ -118,6 +118,9 @@ public: // For hidden windows and stuff bool m_bHidden = false; + // for proper cycling. While cycling we can't just move the pointers, so we need to keep track of the last cycled window. + CWindow* m_pLastCycledWindow = nullptr; + // Foreign Toplevel proto wlr_foreign_toplevel_handle_v1* m_phForeignToplevel = nullptr; diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index f8ee4b78..9c143a13 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -452,8 +452,80 @@ void CHyprMasterLayout::alterSplitRatioBy(CWindow* pWindow, float ratio) { recalculateMonitor(pWindow->m_iMonitorID); } +CWindow* CHyprMasterLayout::getNextWindow(CWindow* pWindow, bool next) { + if (!isWindowTiled(pWindow)) + return nullptr; + + const auto PNODE = getNodeFromWindow(pWindow); + + if (next) { + if (PNODE->isMaster) { + // focus the first non master + for (auto n : m_lMasterNodesData) { + if (n.pWindow != pWindow && n.workspaceID == pWindow->m_iWorkspaceID) { + return n.pWindow; + } + } + } else { + // focus next + bool reached = false; + bool found = false; + for (auto n : m_lMasterNodesData) { + if (n.pWindow == pWindow) { + reached = true; + continue; + } + + if (n.workspaceID == pWindow->m_iWorkspaceID && reached) { + return n.pWindow; + } + } + if (!found) { + const auto PMASTER = getMasterNodeOnWorkspace(pWindow->m_iWorkspaceID); + + if (PMASTER) + return PMASTER->pWindow; + } + } + } else { + if (PNODE->isMaster) { + // focus the first non master + for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) { + if (it->pWindow != pWindow && it->workspaceID == pWindow->m_iWorkspaceID) { + return it->pWindow; + } + } + } else { + // focus next + bool reached = false; + bool found = false; + for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) { + if (it->pWindow == pWindow) { + reached = true; + continue; + } + + if (it->workspaceID == pWindow->m_iWorkspaceID && reached) { + return it->pWindow; + } + } + if (!found) { + const auto PMASTER = getMasterNodeOnWorkspace(pWindow->m_iWorkspaceID); + + if (PMASTER) + return PMASTER->pWindow; + } + } + } + + return nullptr; +} + std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::string message) { auto switchToWindow = [&](CWindow* PWINDOWTOCHANGETO) { + if (!g_pCompositor->windowValidMapped(PWINDOWTOCHANGETO)) + return; + g_pCompositor->focusWindow(PWINDOWTOCHANGETO); Vector2D middle = PWINDOWTOCHANGETO->m_vRealPosition.goalv() + PWINDOWTOCHANGETO->m_vRealSize.goalv() / 2.f; wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, middle.x, middle.y); @@ -479,80 +551,40 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri } else if (message == "cyclenext") { const auto PWINDOW = header.pWindow; - if (!isWindowTiled(PWINDOW)) - return 0; - - const auto PNODE = getNodeFromWindow(PWINDOW); - - if (PNODE->isMaster) { - // focus the first non master - for (auto n : m_lMasterNodesData) { - if (n.pWindow != PWINDOW && n.workspaceID == PWINDOW->m_iWorkspaceID) { - switchToWindow(n.pWindow); - break; - } - } - } else { - // focus next - bool reached = false; - bool found = false; - for (auto n : m_lMasterNodesData) { - if (n.pWindow == PWINDOW) { - reached = true; - continue; - } - - if (n.workspaceID == PWINDOW->m_iWorkspaceID && reached) { - switchToWindow(n.pWindow); - found = true; - break; - } - } - if (!found) { - const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID); - - if (PMASTER) - switchToWindow(PMASTER->pWindow); - } - } + switchToWindow(getNextWindow(PWINDOW, true)); } else if (message == "cycleprev") { const auto PWINDOW = header.pWindow; - if (!isWindowTiled(PWINDOW)) + switchToWindow(getNextWindow(PWINDOW, false)); + } else if (message == "swapnext") { + if (!g_pCompositor->windowValidMapped(header.pWindow)) return 0; - const auto PNODE = getNodeFromWindow(PWINDOW); + if (header.pWindow->m_bIsFloating) { + g_pKeybindManager->m_mDispatchers["swapnext"](""); + return 0; + } - if (PNODE->isMaster) { - // focus the first non master - for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) { - if (it->pWindow != PWINDOW && it->workspaceID == PWINDOW->m_iWorkspaceID) { - switchToWindow(it->pWindow); - break; - } - } - } else { - // focus next - bool reached = false; - bool found = false; - for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) { - if (it->pWindow == PWINDOW) { - reached = true; - continue; - } + const auto PWINDOWTOSWAPWITH = getNextWindow(header.pWindow, true); - if (it->workspaceID == PWINDOW->m_iWorkspaceID && reached) { - switchToWindow(it->pWindow); - found = true; - break; - } - } - if (!found) { - const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID); + if (PWINDOWTOSWAPWITH) { + switchWindows(header.pWindow, PWINDOWTOSWAPWITH); + g_pCompositor->focusWindow(header.pWindow); + } + } else if (message == "swapprev") { + if (!g_pCompositor->windowValidMapped(header.pWindow)) + return 0; - if (PMASTER) - switchToWindow(PMASTER->pWindow); - } + if (header.pWindow->m_bIsFloating) { + g_pKeybindManager->m_mDispatchers["swapnext"]("prev"); + return 0; + } + + const auto PWINDOWTOSWAPWITH = getNextWindow(header.pWindow, false); + + if (PWINDOWTOSWAPWITH) { + switchWindows(header.pWindow, PWINDOWTOSWAPWITH); + g_pCompositor->focusWindow(header.pWindow); } } diff --git a/src/layout/MasterLayout.hpp b/src/layout/MasterLayout.hpp index f7f40ea4..73a2c362 100644 --- a/src/layout/MasterLayout.hpp +++ b/src/layout/MasterLayout.hpp @@ -51,6 +51,7 @@ private: SMasterNodeData* getNodeFromWindow(CWindow*); SMasterNodeData* getMasterNodeOnWorkspace(const int&); void calculateWorkspace(const int&); + CWindow* getNextWindow(CWindow*, bool); friend struct SMasterNodeData; }; \ No newline at end of file diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index b1b51dd7..e3799a7c 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -39,6 +39,7 @@ CKeybindManager::CKeybindManager() { m_mDispatchers["dpms"] = dpms; m_mDispatchers["movewindowpixel"] = moveWindow; m_mDispatchers["resizewindowpixel"] = resizeWindow; + m_mDispatchers["swapnext"] = swapnext; m_tScrollTimer.reset(); } @@ -1437,3 +1438,34 @@ void CKeybindManager::dpms(std::string arg) { g_pCompositor->m_bDPMSStateON = enable; } + +void CKeybindManager::swapnext(std::string arg) { + + CWindow* toSwap = nullptr; + + if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow)) + return; + + const auto PLASTWINDOW = g_pCompositor->m_pLastWindow; + + const auto PLASTCYCLED = g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow->m_pLastCycledWindow) && g_pCompositor->m_pLastWindow->m_pLastCycledWindow->m_iWorkspaceID == PLASTWINDOW->m_iWorkspaceID ? g_pCompositor->m_pLastWindow->m_pLastCycledWindow : nullptr; + + if (arg == "last" || arg == "l" || arg == "prev" || arg == "p") + toSwap = g_pCompositor->getPrevWindowOnWorkspace(PLASTCYCLED ? PLASTCYCLED : PLASTWINDOW); + else + toSwap = g_pCompositor->getNextWindowOnWorkspace(PLASTCYCLED ? PLASTCYCLED : PLASTWINDOW); + + // sometimes we may come back to ourselves. + if (toSwap == PLASTWINDOW) { + if (arg == "last" || arg == "l" || arg == "prev" || arg == "p") + toSwap = g_pCompositor->getPrevWindowOnWorkspace(PLASTWINDOW); + else + toSwap = g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW); + } + + g_pLayoutManager->getCurrentLayout()->switchWindows(PLASTWINDOW, toSwap); + + PLASTWINDOW->m_pLastCycledWindow = toSwap; + + g_pCompositor->focusWindow(PLASTWINDOW); +} diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 29ebc7a1..2462f7a3 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -107,6 +107,7 @@ private: static void layoutmsg(std::string); static void toggleOpaque(std::string); static void dpms(std::string); + static void swapnext(std::string); friend class CCompositor; friend class CInputManager;