From b6a93b2f0383fc8f084c7757f0f67b8c0ebeccc7 Mon Sep 17 00:00:00 2001 From: vaxerski <43317083+vaxerski@users.noreply.github.com> Date: Tue, 12 Apr 2022 16:44:18 +0200 Subject: [PATCH] Added window grouping for dwindle furthermore, added LayoutRenderHints. --- src/Compositor.cpp | 15 +-- src/Window.hpp | 3 + src/config/ConfigManager.cpp | 2 + src/layout/DwindleLayout.cpp | 167 ++++++++++++++++++++++++++++-- src/layout/DwindleLayout.hpp | 10 ++ src/layout/IHyprLayout.hpp | 23 ++++ src/managers/AnimationManager.cpp | 4 +- src/managers/KeybindManager.cpp | 10 ++ src/managers/KeybindManager.hpp | 2 + src/render/Renderer.cpp | 3 + 10 files changed, 221 insertions(+), 18 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index dca964b6..88553570 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -253,13 +253,13 @@ CWindow* CCompositor::vectorToWindow(const Vector2D& pos) { // first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter. for (auto w = m_lWindows.rbegin(); w != m_lWindows.rend(); w++) { wlr_box box = {w->m_vRealPosition.x, w->m_vRealPosition.y, w->m_vRealSize.x, w->m_vRealSize.y}; - if (wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID)) + if (wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->m_bHidden) return &(*w); } for (auto& w : m_lWindows) { wlr_box box = {w.m_vRealPosition.x, w.m_vRealPosition.y, w.m_vRealSize.x, w.m_vRealSize.y}; - if (wlr_box_contains_point(&box, pos.x, pos.y) && w.m_bIsMapped && !w.m_bIsFloating && PMONITOR->activeWorkspace == w.m_iWorkspaceID) + if (wlr_box_contains_point(&box, pos.x, pos.y) && w.m_bIsMapped && !w.m_bIsFloating && PMONITOR->activeWorkspace == w.m_iWorkspaceID && !w.m_bHidden) return &w; } @@ -270,7 +270,7 @@ CWindow* CCompositor::vectorToWindowTiled(const Vector2D& pos) { const auto PMONITOR = getMonitorFromVector(pos); for (auto& w : m_lWindows) { wlr_box box = {w.m_vPosition.x, w.m_vPosition.y, w.m_vSize.x, w.m_vSize.y}; - if (w.m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && w.m_iWorkspaceID == PMONITOR->activeWorkspace && !w.m_bIsFloating) + if (w.m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && w.m_iWorkspaceID == PMONITOR->activeWorkspace && !w.m_bIsFloating && !w.m_bHidden) return &w; } @@ -282,13 +282,13 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) { // first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter. for (auto w = m_lWindows.rbegin(); w != m_lWindows.rend(); w++) { wlr_box box = {w->m_vRealPosition.x, w->m_vRealPosition.y, w->m_vRealSize.x, w->m_vRealSize.y}; - if (w->m_bIsFloating && w->m_bIsMapped && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && isWorkspaceVisible(w->m_iWorkspaceID)) + if (w->m_bIsFloating && w->m_bIsMapped && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && isWorkspaceVisible(w->m_iWorkspaceID) && !w->m_bHidden) return &(*w); } for (auto& w : m_lWindows) { wlr_box box = {w.m_vPosition.x, w.m_vPosition.y, w.m_vSize.x, w.m_vSize.y}; - if (!w.m_bIsFloating && w.m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && w.m_iWorkspaceID == PMONITOR->activeWorkspace) + if (!w.m_bIsFloating && w.m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && w.m_iWorkspaceID == PMONITOR->activeWorkspace && !w.m_bHidden) return &w; } @@ -317,7 +317,7 @@ CWindow* CCompositor::windowFromCursor() { CWindow* CCompositor::windowFloatingFromCursor() { for (auto w = m_lWindows.rbegin(); w != m_lWindows.rend(); w++) { wlr_box box = {w->m_vRealPosition.x, w->m_vRealPosition.y, w->m_vRealSize.x, w->m_vRealSize.y}; - if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID)) + if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->m_bHidden) return &(*w); } @@ -424,6 +424,9 @@ bool CCompositor::windowValidMapped(CWindow* pWindow) { if (!pWindow->m_bIsMapped) return false; + if (pWindow->m_bHidden) + return false; + if (!g_pXWaylandManager->getWindowSurface(pWindow)) return false; diff --git a/src/Window.hpp b/src/Window.hpp index d34a5d06..216773fb 100644 --- a/src/Window.hpp +++ b/src/Window.hpp @@ -73,6 +73,9 @@ public: bool m_bFadingOut = false; bool m_bReadyToDelete = false; + // For hidden windows and stuff + bool m_bHidden = false; + // For the list lookup bool operator==(const CWindow& rhs) { diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 59d9566a..97dae134 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -28,6 +28,8 @@ CConfigManager::CConfigManager() { configValues["decoration:blur_passes"].intValue = 1; configValues["dwindle:pseudotile"].intValue = 0; + configValues["dwindle:col.group_border"].intValue = 0x66777700; + configValues["dwindle:col.group_border_active"].intValue = 0x66ffff00; configValues["animations:enabled"].intValue = 1; configValues["animations:speed"].floatValue = 7.f; diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index b497388a..b007ae8e 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -2,6 +2,23 @@ #include "../Compositor.hpp" void SDwindleNodeData::recalcSizePosRecursive() { + + // check the group, if we are in one and not active, ignore. + if (pGroupParent && pGroupParent->groupMembers[pGroupParent->groupMemberActive] != this) { + if (pWindow) + pWindow->m_bHidden = true; + return; + } else { + if (pWindow) + pWindow->m_bHidden = false; + } + + if (pGroupParent) { + // means we are in a group and focused. let's just act like the full window in this + size = pGroupParent->size; + position = pGroupParent->position; + } + if (children[0]) { const auto REVERSESPLITRATIO = 2.f - splitRatio; @@ -20,19 +37,22 @@ void SDwindleNodeData::recalcSizePosRecursive() { children[1]->size = Vector2D(size.x, size.y / 2.f * REVERSESPLITRATIO); } - if (children[0]->isNode) - children[0]->recalcSizePosRecursive(); - else - layout->applyNodeDataToWindow(children[0]); - if (children[1]->isNode) - children[1]->recalcSizePosRecursive(); - else - layout->applyNodeDataToWindow(children[1]); + children[0]->recalcSizePosRecursive(); + children[1]->recalcSizePosRecursive(); } else { layout->applyNodeDataToWindow(this); } } +void SDwindleNodeData::getAllChildrenRecursive(std::deque* pDeque) { + if (children[0]) { + children[0]->getAllChildrenRecursive(pDeque); + children[1]->getAllChildrenRecursive(pDeque); + } else { + pDeque->push_back(this); + } +} + int CHyprDwindleLayout::getNodesOnWorkspace(const int& id) { int no = 0; for (auto& n : m_lDwindleNodesData) { @@ -217,10 +237,19 @@ void CHyprDwindleLayout::onWindowCreated(CWindow* pWindow) { OPENINGON->pParent = NEWPARENT; PNODE->pParent = NEWPARENT; - NEWPARENT->recalcSizePosRecursive(); + if (OPENINGON->pGroupParent) { + // means we opened on a group + PNODE->pGroupParent = OPENINGON->pGroupParent; + PNODE->pGroupParent->groupMembers.push_back(PNODE); + PNODE->pGroupParent->groupMemberActive = PNODE->pGroupParent->groupMembers.size() - 1; - applyNodeDataToWindow(PNODE); - applyNodeDataToWindow(OPENINGON); + PNODE->pGroupParent->recalcSizePosRecursive(); + } else { + NEWPARENT->recalcSizePosRecursive(); + + applyNodeDataToWindow(PNODE); + applyNodeDataToWindow(OPENINGON); + } pWindow->m_vRealPosition = PNODE->position + PNODE->size / 2.f; pWindow->m_vRealSize = Vector2D(5,5); @@ -259,6 +288,30 @@ void CHyprDwindleLayout::onWindowRemoved(CWindow* pWindow) { else PSIBLING->recalcSizePosRecursive(); + // check if it was grouped + if (PNODE->pGroupParent) { + const auto MEMBERSCOPY = PNODE->pGroupParent->groupMembers; + PNODE->pGroupParent->groupMembers.clear(); + for (auto& c : MEMBERSCOPY) { + if (c != PNODE) { + PNODE->pGroupParent->groupMembers.push_back(c); + } + } + + if ((long unsigned int)PNODE->pGroupParent->groupMemberActive >= PNODE->pGroupParent->groupMembers.size()) + PNODE->pGroupParent->groupMemberActive = 0; + + if (PNODE->pGroupParent->groupMembers.size() <= 1) { + PNODE->pGroupParent->isGroup = false; + PSIBLING->pGroupParent = nullptr; + PNODE->pGroupParent->groupMembers.clear(); + + PSIBLING->recalcSizePosRecursive(); + } else { + PNODE->pGroupParent->recalcSizePosRecursive(); + } + } + m_lDwindleNodesData.remove(*PPARENT); m_lDwindleNodesData.remove(*PNODE); @@ -557,4 +610,96 @@ void CHyprDwindleLayout::recalculateWindow(CWindow* pWindow) { return; PNODE->recalcSizePosRecursive(); +} + +void CHyprDwindleLayout::toggleWindowGroup(CWindow* pWindow) { + if (!g_pCompositor->windowValidMapped(pWindow)) + return; + + // get the node + const auto PNODE = getNodeFromWindow(pWindow); + + if (!PNODE) + return; // reject + + const auto PGROUPPARENT = PNODE->pGroupParent; + + if (PGROUPPARENT) { + // if there is a parent, release it + for (auto& node : PGROUPPARENT->groupMembers) + node->pGroupParent = nullptr; + + PGROUPPARENT->groupMembers.clear(); + + PGROUPPARENT->isGroup = false; + + PGROUPPARENT->recalcSizePosRecursive(); + } else { + // if there is no parent, let's make one + + const auto PPARENT = PNODE->pParent; + + if (!PPARENT) + return; // reject making group on single window + + + PPARENT->isGroup = true; + + // recursively get all members + std::deque allChildren; + PPARENT->getAllChildrenRecursive(&allChildren); + + PPARENT->groupMembers = allChildren; + + for (auto& c : PPARENT->groupMembers) + c->pGroupParent = PPARENT; + + PPARENT->groupMemberActive = 0; + + PPARENT->recalcSizePosRecursive(); + } +} + +void CHyprDwindleLayout::switchGroupWindow(CWindow* pWindow) { + if (!g_pCompositor->windowValidMapped(pWindow)) + return; // reject + + const auto PNODE = getNodeFromWindow(pWindow); + + if (!PNODE) + return; // reject + + if (!PNODE->pGroupParent) + return; // reject + + PNODE->pGroupParent->groupMemberActive++; + + if ((long unsigned int)PNODE->pGroupParent->groupMemberActive >= PNODE->pGroupParent->groupMembers.size()) + PNODE->pGroupParent->groupMemberActive = 0; + + PNODE->pGroupParent->recalcSizePosRecursive(); + + // focus + g_pCompositor->focusWindow(PNODE->pGroupParent->groupMembers[PNODE->pGroupParent->groupMemberActive]->pWindow); +} + +SWindowRenderLayoutHints CHyprDwindleLayout::requestRenderHints(CWindow* pWindow) { + // window should be valid, insallah + + SWindowRenderLayoutHints hints; + + const auto PNODE = getNodeFromWindow(pWindow); + if (!PNODE) + return hints; // left for the future, maybe floating funkiness + + if (PNODE->pGroupParent) { + hints.isBorderColor = true; + + if (pWindow == g_pCompositor->m_pLastWindow) + hints.borderColor = CColor(g_pConfigManager->getInt("dwindle:col.group_border_active")); + else + hints.borderColor = CColor(g_pConfigManager->getInt("dwindle:col.group_border")); + } + + return hints; } \ No newline at end of file diff --git a/src/layout/DwindleLayout.hpp b/src/layout/DwindleLayout.hpp index 8d849bcf..47da6cd3 100644 --- a/src/layout/DwindleLayout.hpp +++ b/src/layout/DwindleLayout.hpp @@ -2,6 +2,7 @@ #include "IHyprLayout.hpp" #include +#include class CHyprDwindleLayout; @@ -13,6 +14,11 @@ struct SDwindleNodeData { std::array children = { nullptr, nullptr }; + bool isGroup = false; + int groupMemberActive = 0; + std::deque groupMembers; + SDwindleNodeData* pGroupParent = nullptr; + Vector2D position; Vector2D size; @@ -26,6 +32,7 @@ struct SDwindleNodeData { } void recalcSizePosRecursive(); + void getAllChildrenRecursive(std::deque*); CHyprDwindleLayout* layout = nullptr; }; @@ -41,6 +48,9 @@ public: virtual void onMouseMove(const Vector2D&); virtual void onWindowCreatedFloating(CWindow*); virtual void fullscreenRequestForWindow(CWindow*); + virtual void toggleWindowGroup(CWindow*); + virtual void switchGroupWindow(CWindow*); + virtual SWindowRenderLayoutHints requestRenderHints(CWindow*); private: diff --git a/src/layout/IHyprLayout.hpp b/src/layout/IHyprLayout.hpp index 3e85cc24..16414895 100644 --- a/src/layout/IHyprLayout.hpp +++ b/src/layout/IHyprLayout.hpp @@ -3,6 +3,11 @@ #include "../defines.hpp" #include "../Window.hpp" +struct SWindowRenderLayoutHints { + bool isBorderColor = false; + CColor borderColor; +}; + interface IHyprLayout { public: @@ -61,4 +66,22 @@ public: */ virtual void fullscreenRequestForWindow(CWindow*) = 0; + /* + Called when the user requests a window to be made into a group, + or when they want the group to be released. + Everything else is free to interpret by the layout. + */ + virtual void toggleWindowGroup(CWindow*) = 0; + + /* + Called when the user requests a group window switch + */ + virtual void switchGroupWindow(CWindow*) = 0; + + /* + Required to be handled, but may return just SWindowRenderLayoutHints() + Called when the renderer requests any special draw flags for + a specific window, e.g. border color for groups. + */ + virtual SWindowRenderLayoutHints requestRenderHints(CWindow*) = 0; }; \ No newline at end of file diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 4495214a..48d56148 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -52,7 +52,9 @@ void CAnimationManager::tick() { continue; // process the borders - const auto& COLOR = g_pCompositor->isWindowActive(&w) ? BORDERACTIVECOL : BORDERINACTIVECOL; + const auto RENDERHINTS = g_pLayoutManager->getCurrentLayout()->requestRenderHints(&w); + + const auto& COLOR = RENDERHINTS.isBorderColor ? RENDERHINTS.borderColor : g_pCompositor->isWindowActive(&w) ? BORDERACTIVECOL : BORDERINACTIVECOL; if (BORDERSENABLED) { if (!deltazero(COLOR, w.m_cRealBorderColor)) { diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 331273c3..54d5b605 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -54,6 +54,8 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const xkb_keysym_t else if (k.handler == "movetoworkspace") { moveActiveToWorkspace(k.arg); } else if (k.handler == "pseudo") { toggleActivePseudo(k.arg); } else if (k.handler == "movefocus") { moveFocusTo(k.arg); } + else if (k.handler == "togglegroup") { toggleGroup(k.arg); } + else if (k.handler == "changegroupactive") { changeGroupActive(k.arg); } found = true; } @@ -289,4 +291,12 @@ void CKeybindManager::moveFocusTo(std::string args) { Vector2D middle = PWINDOWTOCHANGETO->m_vPosition + PWINDOWTOCHANGETO->m_vSize / 2.f; wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, middle.x, middle.y); } +} + +void CKeybindManager::toggleGroup(std::string args) { + g_pLayoutManager->getCurrentLayout()->toggleWindowGroup(g_pCompositor->m_pLastWindow); +} + +void CKeybindManager::changeGroupActive(std::string args) { + g_pLayoutManager->getCurrentLayout()->switchGroupWindow(g_pCompositor->m_pLastWindow); } \ No newline at end of file diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index de4e8fa3..edd43a26 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -32,6 +32,8 @@ private: void fullscreenActive(std::string); void moveActiveToWorkspace(std::string); void moveFocusTo(std::string); + void toggleGroup(std::string); + void changeGroupActive(std::string); }; inline std::unique_ptr g_pKeybindManager; \ No newline at end of file diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index d4ee312a..922229ea 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -89,6 +89,9 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(SMonitor* pMonitor, CWor } void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec* time, bool decorate) { + if (pWindow->m_bHidden) + return; + if (pWindow->m_bFadingOut) { g_pHyprOpenGL->renderSnapshot(&pWindow); return;