diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 953660012a3..21937308477 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1583,6 +1583,8 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) { // optimization static auto* const ACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.active_border")->data.get(); static auto* const INACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.inactive_border")->data.get(); + static auto* const GROUPACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.group_border_active")->data.get(); + static auto* const GROUPINACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.group_border")->data.get(); static auto* const PINACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:inactive_opacity")->floatValue; static auto* const PACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:active_opacity")->floatValue; static auto* const PFULLSCREENALPHA = &g_pConfigManager->getConfigValuePtr("decoration:fullscreen_opacity")->floatValue; @@ -1604,13 +1606,19 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) { const auto RENDERDATA = g_pLayoutManager->getCurrentLayout()->requestRenderHints(pWindow); if (RENDERDATA.isBorderGradient) setBorderColor(*RENDERDATA.borderGradient); - else - setBorderColor(pWindow == m_pLastWindow ? (pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying() >= 0 ? - CGradientValueData(CColor(pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying())) : - *ACTIVECOL) : - (pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying() >= 0 ? - CGradientValueData(CColor(pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying())) : - *INACTIVECOL)); + else { + if (pWindow == m_pLastWindow) { + const auto* const ACTIVECOLOR = !pWindow->m_sGroupData.pNextWindow ? ACTIVECOL : GROUPACTIVECOL; + setBorderColor(pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying() >= 0 ? + CGradientValueData(CColor(pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying())) : + *ACTIVECOLOR); + } else { + const auto* const INACTIVECOLOR = !pWindow->m_sGroupData.pNextWindow ? INACTIVECOL : GROUPINACTIVECOL; + setBorderColor(pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying() >= 0 ? + CGradientValueData(CColor(pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying())) : + *INACTIVECOLOR); + } + } // tick angle if it's not running (aka dead) if (!pWindow->m_fBorderAngleAnimationProgress.isBeingAnimated()) diff --git a/src/Window.cpp b/src/Window.cpp index e7d4a02a619..1ca35ab34e3 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -468,3 +468,71 @@ bool CWindow::hasPopupAt(const Vector2D& pos) { return resultSurf; } + +CWindow* CWindow::getGroupHead() { + CWindow* curr = this; + while (!curr->m_sGroupData.head) + curr = curr->m_sGroupData.pNextWindow; + return curr; +} + +CWindow* CWindow::getGroupTail() { + CWindow* curr = this; + while (!curr->m_sGroupData.pNextWindow->m_sGroupData.head) + curr = curr->m_sGroupData.pNextWindow; + return curr; +} + +CWindow* CWindow::getGroupCurrent() { + CWindow* curr = this; + while (curr->isHidden()) + curr = curr->m_sGroupData.pNextWindow; + return curr; +} + +void CWindow::setGroupCurrent(CWindow* pWindow) { + CWindow* curr = this->m_sGroupData.pNextWindow; + bool isMember = false; + while (curr != this) { + if (curr == pWindow) { + isMember = true; + break; + } + curr = curr->m_sGroupData.pNextWindow; + } + + if (!isMember && pWindow != this) + return; + + const auto PCURRENT = getGroupCurrent(); + + const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goalv(); + const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goalv(); + + const auto CURRENTISFOCUS = PCURRENT == g_pCompositor->m_pLastWindow; + + PCURRENT->setHidden(true); + pWindow->setHidden(false); + + g_pLayoutManager->getCurrentLayout()->replaceWindowDataWith(PCURRENT, pWindow); + + if (PCURRENT->m_bIsFloating) { + pWindow->m_vRealPosition.setValueAndWarp(PWINDOWPOS); + pWindow->m_vRealSize.setValueAndWarp(PWINDOWSIZE); + } + + g_pCompositor->updateAllWindowsAnimatedDecorationValues(); + + if (CURRENTISFOCUS) + g_pCompositor->focusWindow(pWindow); +} + +void CWindow::insertWindowToGroup(CWindow* pWindow) { + const auto PHEAD = getGroupHead(); + const auto PTAIL = getGroupTail(); + + PTAIL->m_sGroupData.pNextWindow = pWindow; + pWindow->m_sGroupData.pNextWindow = PHEAD; + + setGroupCurrent(pWindow); +} \ No newline at end of file diff --git a/src/Window.hpp b/src/Window.hpp index 658bdcebdfc..65ac78f5e37 100644 --- a/src/Window.hpp +++ b/src/Window.hpp @@ -273,6 +273,12 @@ class CWindow { // for idle inhibiting windows eIdleInhibitMode m_eIdleInhibitMode = IDLEINHIBIT_NONE; + // for groups + struct SGroupData { + CWindow* pNextWindow = nullptr; // nullptr means no grouping. Self means single group. + bool head = false; + } m_sGroupData; + // For the list lookup bool operator==(const CWindow& rhs) { return m_uSurface.xdg == rhs.m_uSurface.xdg && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && @@ -303,6 +309,12 @@ class CWindow { bool isInCurvedCorner(double x, double y); bool hasPopupAt(const Vector2D& pos); + CWindow* getGroupHead(); + CWindow* getGroupTail(); + CWindow* getGroupCurrent(); + void setGroupCurrent(CWindow* pWindow); + void insertWindowToGroup(CWindow* pWindow); + private: // For hidden windows and stuff bool m_bHidden = false; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index f463f9e629b..018eb4207fd 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -13,8 +13,8 @@ CConfigManager::CConfigManager() { configValues["general:col.active_border"].data = std::make_shared(0xffffffff); configValues["general:col.inactive_border"].data = std::make_shared(0xff444444); - configValues["dwindle:col.group_border"].data = std::make_shared(0x66777700); - configValues["dwindle:col.group_border_active"].data = std::make_shared(0x66ffff00); + configValues["general:col.group_border"].data = std::make_shared(0x66777700); + configValues["general:col.group_border_active"].data = std::make_shared(0x66ffff00); setDefaultVars(); setDefaultAnimationVars(); @@ -44,6 +44,8 @@ void CConfigManager::setDefaultVars() { configValues["general:gaps_out"].intValue = 20; ((CGradientValueData*)configValues["general:col.active_border"].data.get())->reset(0xffffffff); ((CGradientValueData*)configValues["general:col.inactive_border"].data.get())->reset(0xff444444); + ((CGradientValueData*)configValues["general:col.group_border"].data.get())->reset(0x66777700); + ((CGradientValueData*)configValues["general:col.group_border_active"].data.get())->reset(0x66ffff00); configValues["general:cursor_inactive_timeout"].intValue = 0; configValues["general:no_cursor_warps"].intValue = 0; configValues["general:resize_on_border"].intValue = 0; @@ -102,8 +104,6 @@ void CConfigManager::setDefaultVars() { configValues["decoration:dim_around"].floatValue = 0.4f; configValues["decoration:screen_shader"].strValue = STRVAL_EMPTY; - ((CGradientValueData*)configValues["dwindle:col.group_border"].data.get())->reset(0x66777700); - ((CGradientValueData*)configValues["dwindle:col.group_border_active"].data.get())->reset(0x66ffff00); configValues["dwindle:pseudotile"].intValue = 0; configValues["dwindle:force_split"].intValue = 0; configValues["dwindle:preserve_split"].intValue = 0; diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 9e2a60124c1..22889efd50b 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -45,64 +45,6 @@ void SDwindleNodeData::getAllChildrenRecursive(std::deque* pD } } -bool SDwindleNodeData::isGroupMember() { - return pNextGroupMember && pNextGroupMember != this; -} - -SDwindleNodeData* SDwindleNodeData::getGroupHead() { - SDwindleNodeData* current = this->pNextGroupMember; - - while (current != this) { - if (current->groupHead) { - return current; - } - - current = current->pNextGroupMember; - } - - this->groupHead = true; - - return this; -} - -SDwindleNodeData* SDwindleNodeData::getGroupVisible() { - SDwindleNodeData* current = this->pNextGroupMember; - - while (current != this) { - if (!current->pWindow->isHidden()) { - return current; - } - - current = current->pNextGroupMember; - } - - return this; -} - -void SDwindleNodeData::setGroupFocusedNode(SDwindleNodeData* pMember) { - SDwindleNodeData* current = this->pNextGroupMember; - - while (current != this) { - current->pWindow->setHidden(current != pMember); - current = current->pNextGroupMember; - } - - this->pWindow->setHidden(pMember != this); -} - -int SDwindleNodeData::getGroupMemberCount() { - SDwindleNodeData* current = this->pNextGroupMember; - - int no = 1; - - while (current != this) { - current = current->pNextGroupMember; - no++; - } - - return no; -} - int CHyprDwindleLayout::getNodesOnWorkspace(const int& id) { int no = 0; for (auto& n : m_lDwindleNodesData) { @@ -189,8 +131,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for const auto NODESONWORKSPACE = getNodesOnWorkspace(PWINDOW->m_iWorkspaceID); if (*PNOGAPSWHENONLY && !g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID) && - (NODESONWORKSPACE == 1 || (pNode->isGroupMember() && pNode->getGroupMemberCount() == NODESONWORKSPACE) || - (PWINDOW->m_bIsFullscreen && g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) { + (NODESONWORKSPACE == 1 || (PWINDOW->m_bIsFullscreen && g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) { PWINDOW->m_vRealPosition = calcPos - Vector2D(*PBORDERSIZE, *PBORDERSIZE); PWINDOW->m_vRealSize = calcSize + Vector2D(2 * *PBORDERSIZE, 2 * *PBORDERSIZE); @@ -262,14 +203,6 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for g_pHyprRenderer->damageWindow(PWINDOW); } - if (pNode->isGroupMember() && pNode->groupHead) { - // update visible node - const auto PVISNODE = pNode->getGroupVisible(); - - PVISNODE->pWindow->m_vRealSize = PWINDOW->m_vRealSize.goalv(); - PVISNODE->pWindow->m_vRealPosition = PWINDOW->m_vRealPosition.goalv(); - } - PWINDOW->updateWindowDecos(); } @@ -359,23 +292,10 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) { } // if it's a group, add the window - if (OPENINGON->isGroupMember()) { - const auto PHEAD = OPENINGON->getGroupHead(); - - const auto PTAIL = PHEAD->pPreviousGroupMember; - - PHEAD->pPreviousGroupMember = PNODE; - PTAIL->pNextGroupMember = PNODE; - - PNODE->pNextGroupMember = PHEAD; - PNODE->pPreviousGroupMember = PTAIL; - - PHEAD->setGroupFocusedNode(PNODE); - - PNODE->position = PHEAD->position; - PNODE->size = PHEAD->size; + if (OPENINGON->pWindow->m_sGroupData.pNextWindow) { + m_lDwindleNodesData.remove(*PNODE); - applyNodeDataToWindow(PNODE); + OPENINGON->pWindow->insertWindowToGroup(pWindow); pWindow->m_dWindowDecorations.emplace_back(std::make_unique(pWindow)); @@ -479,51 +399,6 @@ void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) { if (pWindow->m_bIsFullscreen) g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL); - // check if it was grouped - if (PNODE->isGroupMember()) { - // get shit - const auto PPREV = PNODE->pPreviousGroupMember; - const auto PNEXT = PNODE->pNextGroupMember; - - PPREV->pNextGroupMember = PNEXT; - PNEXT->pPreviousGroupMember = PPREV; - - if (PNODE->groupHead) { - PNEXT->groupHead = true; - PNEXT->pParent = PNODE->pParent; - - if (PNODE->pParent) { - if (PNODE->pParent->children[0] == PNODE) { - PNODE->pParent->children[0] = PNEXT; - } else { - PNODE->pParent->children[1] = PNEXT; - } - } - - PNEXT->position = PNODE->position; - PNEXT->size = PNODE->size; - } else { - const auto PHEAD = PNODE->getGroupHead(); - - PNEXT->position = PHEAD->position; - PNEXT->size = PHEAD->size; - } - - PNEXT->setGroupFocusedNode(PNEXT); - PNEXT->pWindow->setHidden(false); - - m_lDwindleNodesData.remove(*PNODE); - - applyNodeDataToWindow(PNEXT); - - if (!PNEXT->isGroupMember()) { - // means we dissolved the group - recalculateMonitor(PNEXT->pWindow->m_iMonitorID); - } - - return; - } - const auto PPARENT = PNODE->pParent; if (!PPARENT) { @@ -538,17 +413,6 @@ void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) { PSIBLING->size = PPARENT->size; PSIBLING->pParent = PPARENT->pParent; - if (PSIBLING->isGroupMember()) { - // apply to all group members - SDwindleNodeData* current = PSIBLING->pNextGroupMember; - - while (current != PSIBLING) { - current->position = PPARENT->position; - current->size = PPARENT->size; - current = current->pNextGroupMember; - } - } - if (PPARENT->pParent != nullptr) { if (PPARENT->pParent->children[0] == PPARENT) { PPARENT->pParent->children[0] = PSIBLING; @@ -819,252 +683,14 @@ void addToDequeRecursive(std::deque* pDeque, std::dequewindowValidMapped(pWindow)) - return; - - // get the node - const auto PNODE = getNodeFromWindow(pWindow); - - if (!PNODE) { - Debug::log(LOG, "Rejecting to group a floating window"); - return; - } - - const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PNODE->workspaceID); - - if (PWORKSPACE->m_bHasFullscreenWindow && !PNODE->isGroupMember()) { - Debug::log(ERR, "Cannot enable group on a fullscreen window"); - return; - } - - if (PNODE->isGroupMember()) { - // dissolve group - const auto PHEAD = PNODE->getGroupHead(); - - SDwindleNodeData* current = PNODE->pNextGroupMember; - - PNODE->pWindow->m_bIsFloating = PHEAD->pWindow->m_bIsFloating; - - std::deque toAddWindows; - - const auto PWINDOWNODE = PNODE->pWindow; - toAddWindows.push_back(PWINDOWNODE); - - while (current != PNODE) { - const auto PWINDOW = current->pWindow; - current = current->pNextGroupMember; - - toAddWindows.push_back(PWINDOW); - - PWINDOW->setHidden(false); - } - - if (PHEAD->pPreviousGroupMember) - PHEAD->pPreviousGroupMember->pNextGroupMember = PHEAD->pNextGroupMember; - - if (PHEAD->pNextGroupMember) - PHEAD->pNextGroupMember->pPreviousGroupMember = PHEAD->pPreviousGroupMember; - - PHEAD->pPreviousGroupMember = nullptr; - PHEAD->pNextGroupMember = nullptr; - - onWindowRemoved(PHEAD->pWindow); - - for (auto& pw : toAddWindows) { - const auto PNODE = getNodeFromWindow(pw); - if (PNODE) - m_lDwindleNodesData.remove(*PNODE); - - pw->m_vPosition = Vector2D(-1000000, -1000000); - } - - for (auto& pw : toAddWindows) { - onWindowCreated(pw); - pw->removeDecorationByType(DECORATION_GROUPBAR); - } - - recalculateMonitor(PWORKSPACE->m_iMonitorID); - } else { - // create group - - if (!PNODE->pParent) { - Debug::log(LOG, "Rejecting to group a solitary window"); - return; - } - - PNODE->groupHead = true; - - std::deque newGroupMembers; - std::deque nodesToRemove; - - newGroupMembers.emplace_back(PNODE); - - addToDequeRecursive(&newGroupMembers, &nodesToRemove, PNODE->pParent->children[0] == PNODE ? PNODE->pParent->children[1] : PNODE->pParent->children[0]); - - for (auto& n : newGroupMembers) { - if (n->isGroupMember()) { - Debug::log(LOG, "Rejecting to nest groups"); - return; - } - } - - for (auto& nd : nodesToRemove) { - m_lDwindleNodesData.remove(*nd); - } - - PNODE->position = PNODE->pParent->position; - PNODE->size = PNODE->pParent->size; - - applyNodeDataToWindow(PNODE); - - if (PNODE->pParent->pParent) { - if (PNODE->pParent->pParent->children[0] == PNODE->pParent) { - PNODE->pParent->pParent->children[0] = PNODE; - } else { - PNODE->pParent->pParent->children[1] = PNODE; - } - } - - const auto PPARENT2 = PNODE->pParent->pParent; - - m_lDwindleNodesData.remove(*PNODE->pParent); - - PNODE->pParent = PPARENT2; - - // now remove everyone but head from tree - // and set order - for (int i = 0; i < (int)newGroupMembers.size(); ++i) { - if (i != 0) { - newGroupMembers[i]->groupHead = false; - newGroupMembers[i]->pParent = PNODE->pParent; - } - - const auto PREVMEMBER = i == 0 ? newGroupMembers[newGroupMembers.size() - 1] : newGroupMembers[i - 1]; - const auto NEXTMEMBER = i == (int)newGroupMembers.size() - 1 ? newGroupMembers[0] : newGroupMembers[i + 1]; - - newGroupMembers[i]->pPreviousGroupMember = PREVMEMBER; - newGroupMembers[i]->pNextGroupMember = NEXTMEMBER; - - // add the deco - newGroupMembers[i]->pWindow->m_dWindowDecorations.emplace_back(std::make_unique(newGroupMembers[i]->pWindow)); - } - - // focus - PNODE->setGroupFocusedNode(PNODE); - - // required for no_gaps_when_only to work - applyNodeDataToWindow(PNODE); - } - - g_pCompositor->updateAllWindowsAnimatedDecorationValues(); - - g_pInputManager->refocus(); -} - -std::deque CHyprDwindleLayout::getGroupMembers(CWindow* pWindow) { - - std::deque result; - - if (!g_pCompositor->windowExists(pWindow)) - return result; // reject with empty - - // get the node - const auto PNODE = getNodeFromWindow(pWindow); - - if (!PNODE || !PNODE->isGroupMember()) - return result; // reject with empty - - const auto HEAD = PNODE->getGroupHead(); - SDwindleNodeData* current = HEAD->pNextGroupMember; - - result.push_back(HEAD->pWindow); - - while (current != HEAD) { - result.push_back(current->pWindow); - current = current->pNextGroupMember; - } - - return result; -} - -void CHyprDwindleLayout::switchGroupWindow(CWindow* pWindow, bool forward, CWindow* forceTo) { - if (!g_pCompositor->windowValidMapped(pWindow)) - return; // reject - - const auto PNODE = getNodeFromWindow(pWindow); - - if (!PNODE || !PNODE->isGroupMember()) - return; // reject - - const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PNODE->workspaceID); - - SDwindleNodeData* pNewNode; - - if (forward) - pNewNode = PNODE->pNextGroupMember; - else - pNewNode = PNODE->pPreviousGroupMember; - - if (forceTo) { - const auto NODETO = getNodeFromWindow(forceTo); - - if (NODETO) - pNewNode = NODETO; - } - - PNODE->setGroupFocusedNode(pNewNode); - - pNewNode->position = PNODE->position; - pNewNode->size = PNODE->size; - pNewNode->workspaceID = PNODE->workspaceID; - - applyNodeDataToWindow(pNewNode); - - pNewNode->pWindow->m_vRealSize.warp(); - pNewNode->pWindow->m_vRealPosition.warp(); - - g_pCompositor->focusWindow(pNewNode->pWindow); - - pNewNode->pWindow->m_bIsFloating = PNODE->pWindow->m_bIsFloating; - - if (PNODE->pWindow->m_bIsFullscreen) { - PNODE->pWindow->setHidden(false); - g_pCompositor->setWindowFullscreen(PNODE->pWindow, false, PWORKSPACE->m_efFullscreenMode); - PNODE->pWindow->setHidden(true); - g_pCompositor->setWindowFullscreen(pNewNode->pWindow, true, PWORKSPACE->m_efFullscreenMode); - - pNewNode->pWindow->m_vRealSize.warp(); - pNewNode->pWindow->m_vRealPosition.warp(); - } - - pNewNode->pWindow->updateWindowDecos(); - PNODE->pWindow->updateWindowDecos(); - - g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID)); -} - SWindowRenderLayoutHints CHyprDwindleLayout::requestRenderHints(CWindow* pWindow) { // window should be valid, insallah - SWindowRenderLayoutHints hints; - static auto* const PGROUPCOLACTIVE = &g_pConfigManager->getConfigValuePtr("dwindle:col.group_border_active")->data; - static auto* const PGROUPCOLINACTIVE = &g_pConfigManager->getConfigValuePtr("dwindle:col.group_border")->data; - const auto PNODE = getNodeFromWindow(pWindow); if (!PNODE) return hints; // left for the future, maybe floating funkiness - if (PNODE->isGroupMember()) { - hints.isBorderGradient = true; - - if (pWindow == g_pCompositor->m_pLastWindow) - hints.borderGradient = (CGradientValueData*)PGROUPCOLACTIVE->get(); - else - hints.borderGradient = (CGradientValueData*)PGROUPCOLINACTIVE->get(); - } - return hints; } @@ -1081,65 +707,9 @@ void CHyprDwindleLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) { SDwindleNodeData* ACTIVE1 = nullptr; SDwindleNodeData* ACTIVE2 = nullptr; - if (PNODE2->isGroupMember() || PNODE->isGroupMember()) { - - if (PNODE->workspaceID != PNODE2->workspaceID) { - Debug::log(ERR, "Groups are confined to a monitor"); - return; - } - - if (PNODE->isGroupMember()) { - ACTIVE1 = PNODE; - PNODE = PNODE->getGroupHead(); - } - - if (PNODE2->isGroupMember()) { - ACTIVE2 = PNODE2; - PNODE2 = PNODE2->getGroupHead(); - } - - if (PNODE2->pParent == PNODE->pParent) { - const auto PPARENT = PNODE->pParent; - - if (PPARENT->children[0] == PNODE) { - PPARENT->children[0] = PNODE2; - PPARENT->children[1] = PNODE; - } else { - PPARENT->children[0] = PNODE; - PPARENT->children[1] = PNODE2; - } - } else { - if (PNODE->pParent) { - const auto PPARENT = PNODE->pParent; - - if (PPARENT->children[0] == PNODE) { - PPARENT->children[0] = PNODE2; - } else { - PPARENT->children[1] = PNODE2; - } - } - - if (PNODE2->pParent) { - const auto PPARENT = PNODE2->pParent; - - if (PPARENT->children[0] == PNODE2) { - PPARENT->children[0] = PNODE; - } else { - PPARENT->children[1] = PNODE; - } - } - } - - const auto PPARENTNODE2 = PNODE2->pParent; - PNODE2->pParent = PNODE->pParent; - PNODE->pParent = PPARENTNODE2; - - std::swap(PNODE2->workspaceID, PNODE->workspaceID); - } else { - // swap the windows and recalc - PNODE2->pWindow = pWindow; - PNODE->pWindow = pWindow2; - } + // swap the windows and recalc + PNODE2->pWindow = pWindow; + PNODE->pWindow = pWindow2; if (PNODE->workspaceID != PNODE2->workspaceID) { std::swap(pWindow2->m_iMonitorID, pWindow->m_iMonitorID); @@ -1176,7 +746,7 @@ void CHyprDwindleLayout::alterSplitRatio(CWindow* pWindow, float ratio, bool exa const auto PNODE = getNodeFromWindow(pWindow); - if (!PNODE || !PNODE->pParent || (PNODE->isGroupMember() && PNODE->getGroupMemberCount() == g_pCompositor->getWindowsOnWorkspace(PNODE->workspaceID))) + if (!PNODE || !PNODE->pParent) return; float newRatio = exact ? ratio : PNODE->pParent->splitRatio + ratio; @@ -1186,18 +756,8 @@ void CHyprDwindleLayout::alterSplitRatio(CWindow* pWindow, float ratio, bool exa } std::any CHyprDwindleLayout::layoutMessage(SLayoutMessageHeader header, std::string message) { - if (message == "togglegroup") - toggleWindowGroup(header.pWindow); - else if (message == "changegroupactivef") - switchGroupWindow(header.pWindow, true); - else if (message == "changegroupactiveb") - switchGroupWindow(header.pWindow, false); - else if (message == "togglesplit") + if (message == "togglesplit") toggleSplit(header.pWindow); - else if (message == "groupinfo") { - auto res = getGroupMembers(header.pWindow ? header.pWindow : g_pCompositor->m_pLastWindow); - return res; - } return ""; } @@ -1213,6 +773,17 @@ void CHyprDwindleLayout::toggleSplit(CWindow* pWindow) { PNODE->pParent->recalcSizePosRecursive(); } +void CHyprDwindleLayout::replaceWindowDataWith(CWindow* from, CWindow* to) { + const auto PNODE = getNodeFromWindow(from); + + if (!PNODE) + return; + + PNODE->pWindow = to; + + applyNodeDataToWindow(PNODE, true); +} + std::string CHyprDwindleLayout::getLayoutName() { return "dwindle"; } diff --git a/src/layout/DwindleLayout.hpp b/src/layout/DwindleLayout.hpp index 3c34287c831..d0142ec7dae 100644 --- a/src/layout/DwindleLayout.hpp +++ b/src/layout/DwindleLayout.hpp @@ -19,10 +19,6 @@ struct SDwindleNodeData { bool splitTop = false; // for preserve_split - bool groupHead = false; - SDwindleNodeData* pNextGroupMember = nullptr; - SDwindleNodeData* pPreviousGroupMember = nullptr; - Vector2D position; Vector2D size; @@ -40,11 +36,6 @@ struct SDwindleNodeData { void recalcSizePosRecursive(bool force = false); void getAllChildrenRecursive(std::deque*); - bool isGroupMember(); - SDwindleNodeData* getGroupHead(); - SDwindleNodeData* getGroupVisible(); - int getGroupMemberCount(); - void setGroupFocusedNode(SDwindleNodeData*); CHyprDwindleLayout* layout = nullptr; }; @@ -62,6 +53,7 @@ class CHyprDwindleLayout : public IHyprLayout { virtual void switchWindows(CWindow*, CWindow*); virtual void alterSplitRatio(CWindow*, float, bool); virtual std::string getLayoutName(); + virtual void replaceWindowDataWith(CWindow* from, CWindow* to); virtual void onEnable(); virtual void onDisable(); @@ -75,10 +67,7 @@ class CHyprDwindleLayout : public IHyprLayout { SDwindleNodeData* getFirstNodeOnWorkspace(const int&); SDwindleNodeData* getMasterNodeOnWorkspace(const int&); - void toggleWindowGroup(CWindow*); - void switchGroupWindow(CWindow*, bool forward, CWindow* to = nullptr); void toggleSplit(CWindow*); - std::deque getGroupMembers(CWindow*); friend struct SDwindleNodeData; }; diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index d62556d500f..60a0e2fff5e 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -24,6 +24,36 @@ void IHyprLayout::onWindowRemoved(CWindow* pWindow) { if (pWindow->m_bIsFullscreen) g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL); + if (pWindow->m_sGroupData.pNextWindow) { + if (pWindow->m_sGroupData.pNextWindow == pWindow) + pWindow->m_sGroupData.pNextWindow = nullptr; + else { + // find last window and update + CWindow* curr = pWindow; + const auto CURRWASVISIBLE = curr->getGroupCurrent() == curr; + + while (curr->m_sGroupData.pNextWindow != pWindow) + curr = curr->m_sGroupData.pNextWindow; + + if (CURRWASVISIBLE) + curr->setGroupCurrent(curr); + + curr->m_sGroupData.pNextWindow = pWindow->m_sGroupData.pNextWindow; + + pWindow->m_sGroupData.pNextWindow = nullptr; + + if (pWindow->m_sGroupData.head) { + pWindow->m_sGroupData.head = false; + curr->m_sGroupData.head = true; + } + + if (pWindow == m_pLastTiledWindow) + m_pLastTiledWindow = nullptr; + + return; + } + } + if (pWindow->m_bIsFloating) { onWindowRemovedFloating(pWindow); } else { diff --git a/src/layout/IHyprLayout.hpp b/src/layout/IHyprLayout.hpp index 3ee193a46c1..f0704298aad 100644 --- a/src/layout/IHyprLayout.hpp +++ b/src/layout/IHyprLayout.hpp @@ -143,6 +143,11 @@ interface IHyprLayout { */ virtual void onWindowFocusChange(CWindow*); + /* + Called for replacing any data a layout has for a new window + */ + virtual void replaceWindowDataWith(CWindow * from, CWindow * to) = 0; + private: Vector2D m_vBeginDragXY; Vector2D m_vLastDragXY; diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index e349d650e89..5c310ed92c2 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -83,6 +83,20 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow) { const auto WINDOWSONWORKSPACE = getNodesOnWorkspace(PNODE->workspaceID); float lastSplitPercent = 0.5f; + auto OPENINGON = isWindowTiled(g_pCompositor->m_pLastWindow) && g_pCompositor->m_pLastWindow->m_iWorkspaceID == pWindow->m_iWorkspaceID ? + getNodeFromWindow(g_pCompositor->m_pLastWindow) : + getMasterNodeOnWorkspace(pWindow->m_iWorkspaceID); + + if (OPENINGON && OPENINGON->pWindow->m_sGroupData.pNextWindow && OPENINGON != PNODE) { + m_lMasterNodesData.remove(*PNODE); + + OPENINGON->pWindow->insertWindowToGroup(pWindow); + + pWindow->m_dWindowDecorations.emplace_back(std::make_unique(pWindow)); + + return; + } + if (*PNEWISMASTER || WINDOWSONWORKSPACE == 1) { for (auto& nd : m_lMasterNodesData) { if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) { @@ -1011,6 +1025,17 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri return 0; } +void CHyprMasterLayout::replaceWindowDataWith(CWindow* from, CWindow* to) { + const auto PNODE = getNodeFromWindow(from); + + if (!PNODE) + return; + + PNODE->pWindow = to; + + applyNodeDataToWindow(PNODE); +} + void CHyprMasterLayout::onEnable() { for (auto& w : g_pCompositor->m_vWindows) { if (w->m_bIsFloating || !w->m_bMappedX11 || !w->m_bIsMapped || w->isHidden()) diff --git a/src/layout/MasterLayout.hpp b/src/layout/MasterLayout.hpp index 95948ead195..2e2746d3435 100644 --- a/src/layout/MasterLayout.hpp +++ b/src/layout/MasterLayout.hpp @@ -58,6 +58,7 @@ class CHyprMasterLayout : public IHyprLayout { virtual void switchWindows(CWindow*, CWindow*); virtual void alterSplitRatio(CWindow*, float, bool); virtual std::string getLayoutName(); + virtual void replaceWindowDataWith(CWindow* from, CWindow* to); virtual void onEnable(); virtual void onDisable(); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 76c08611f6e..305cd9d6587 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -635,11 +635,25 @@ void CKeybindManager::toggleActiveFloating(std::string args) { if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID)) return; - PWINDOW->m_bIsFloating = !PWINDOW->m_bIsFloating; + if (PWINDOW->m_sGroupData.pNextWindow && PWINDOW->m_sGroupData.pNextWindow != PWINDOW) { - PWINDOW->updateDynamicRules(); + const auto PCURRENT = PWINDOW->getGroupCurrent(); + PCURRENT->m_bIsFloating = !PCURRENT->m_bIsFloating; + g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(PCURRENT); + + CWindow* curr = PCURRENT->m_sGroupData.pNextWindow; + while (curr != PCURRENT) { + curr->m_bIsFloating = PCURRENT->m_bIsFloating; + curr->updateDynamicRules(); + curr = curr->m_sGroupData.pNextWindow; + } + } else { + PWINDOW->m_bIsFloating = !PWINDOW->m_bIsFloating; + + PWINDOW->updateDynamicRules(); - g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(PWINDOW); + g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(PWINDOW); + } } void CKeybindManager::centerWindow(std::string args) { @@ -1246,18 +1260,63 @@ void CKeybindManager::moveActiveTo(std::string args) { } void CKeybindManager::toggleGroup(std::string args) { - SLayoutMessageHeader header; - header.pWindow = g_pCompositor->m_pLastWindow; - g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "togglegroup"); + const auto PWINDOW = g_pCompositor->m_pLastWindow; + + if (!PWINDOW) + return; + + if (!PWINDOW->m_sGroupData.pNextWindow) { + PWINDOW->m_sGroupData.pNextWindow = PWINDOW; + PWINDOW->m_sGroupData.head = true; + + PWINDOW->m_dWindowDecorations.emplace_back(std::make_unique(PWINDOW)); + + PWINDOW->updateWindowDecos(); + } else { + if (PWINDOW->m_sGroupData.pNextWindow == PWINDOW) { + PWINDOW->m_sGroupData.pNextWindow = nullptr; + PWINDOW->updateWindowDecos(); + } else { + // enum all windows, remove their group state, readd to layout. + CWindow* curr = PWINDOW; + std::vector members; + do { + const auto PLASTWIN = curr; + curr = curr->m_sGroupData.pNextWindow; + PLASTWIN->m_sGroupData.pNextWindow = nullptr; + curr->setHidden(false); + members.push_back(curr); + } while (curr != PWINDOW); + + for (auto& w : members) { + if (w->m_sGroupData.head) + g_pLayoutManager->getCurrentLayout()->onWindowRemoved(curr); + w->m_sGroupData.head = false; + } + + for (auto& w : members) { + g_pLayoutManager->getCurrentLayout()->onWindowCreated(w); + w->updateWindowDecos(); + } + } + } + + g_pCompositor->updateAllWindowsAnimatedDecorationValues(); } void CKeybindManager::changeGroupActive(std::string args) { - SLayoutMessageHeader header; - header.pWindow = g_pCompositor->m_pLastWindow; - if (args == "b") - g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "changegroupactiveb"); - else - g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "changegroupactivef"); + const auto PWINDOW = g_pCompositor->m_pLastWindow; + + if (!PWINDOW) + return; + + if (!PWINDOW->m_sGroupData.pNextWindow) + return; + + if (PWINDOW->m_sGroupData.pNextWindow == PWINDOW) + return; + + PWINDOW->setGroupCurrent(PWINDOW->m_sGroupData.pNextWindow); } void CKeybindManager::toggleSplit(std::string args) { diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 7b7c1576505..ca9d1b7244f 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -33,24 +33,29 @@ void CHyprGroupBarDecoration::updateWindow(CWindow* pWindow) { m_vLastWindowSize = pWindow->m_vRealSize.vec(); } - // let's check if the window group is different. - - if (g_pLayoutManager->getCurrentLayout()->getLayoutName() != "dwindle") { - // ???? + if (!m_pWindow->m_sGroupData.pNextWindow) { m_pWindow->m_vDecosToRemove.push_back(this); return; } - // get the group info - SLayoutMessageHeader header; - header.pWindow = m_pWindow; + m_dwGroupMembers.clear(); + CWindow* curr = pWindow; + CWindow* head = nullptr; + while (!curr->m_sGroupData.head) { + curr = curr->m_sGroupData.pNextWindow; + } - m_dwGroupMembers = std::any_cast>(g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "groupinfo")); + head = curr; + m_dwGroupMembers.push_back(curr); + curr = curr->m_sGroupData.pNextWindow; + while (curr != head) { + m_dwGroupMembers.push_back(curr); + curr = curr->m_sGroupData.pNextWindow; + } damageEntire(); if (m_dwGroupMembers.size() == 0) { - // remove m_pWindow->m_vDecosToRemove.push_back(this); return; } @@ -86,8 +91,8 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& scaleBox(&rect, pMonitor->scale); - static auto* const PGROUPCOLACTIVE = &g_pConfigManager->getConfigValuePtr("dwindle:col.group_border_active")->data; - static auto* const PGROUPCOLINACTIVE = &g_pConfigManager->getConfigValuePtr("dwindle:col.group_border")->data; + static auto* const PGROUPCOLACTIVE = &g_pConfigManager->getConfigValuePtr("general:col.group_border_active")->data; + static auto* const PGROUPCOLINACTIVE = &g_pConfigManager->getConfigValuePtr("general:col.group_border")->data; CColor color = m_dwGroupMembers[i] == g_pCompositor->m_pLastWindow ? ((CGradientValueData*)PGROUPCOLACTIVE->get())->m_vColors[0] : ((CGradientValueData*)PGROUPCOLINACTIVE->get())->m_vColors[0];