Completely rewrote Dwindle group code

This commit is contained in:
Vaxry 2022-08-11 19:29:39 +02:00
parent cd75606f42
commit c319a2aba9
3 changed files with 232 additions and 138 deletions

View file

@ -2,23 +2,6 @@
#include "../Compositor.hpp"
void SDwindleNodeData::recalcSizePosRecursive(bool force) {
// 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;
@ -60,6 +43,37 @@ void SDwindleNodeData::getAllChildrenRecursive(std::deque<SDwindleNodeData*>* 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;
}
void SDwindleNodeData::setGroupFocusedNode(SDwindleNodeData* pMember) {
SDwindleNodeData* current = this->pNextGroupMember;
while (current != this) {
current->pWindow->m_bHidden = current != pMember;
current = current->pNextGroupMember;
}
this->pWindow->m_bHidden = pMember != this;
}
int CHyprDwindleLayout::getNodesOnWorkspace(const int& id) {
int no = 0;
for (auto& n : m_lDwindleNodesData) {
@ -129,7 +143,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
const auto PWINDOW = pNode->pWindow;
if (!g_pCompositor->windowValidMapped(PWINDOW)) {
if (!g_pCompositor->windowExists(PWINDOW) || !PWINDOW->m_bIsMapped) {
Debug::log(ERR, "Node %x holding invalid window %x!!", pNode, PWINDOW);
return;
}
@ -266,6 +280,28 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
return;
}
// 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;
applyNodeDataToWindow(PNODE);
return;
}
// If it's not, get the node under our cursor
m_lDwindleNodesData.push_back(SDwindleNodeData());
@ -338,23 +374,10 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
OPENINGON->pParent = NEWPARENT;
PNODE->pParent = NEWPARENT;
if (OPENINGON->pGroupParent) {
// means we opened on a group
NEWPARENT->recalcSizePosRecursive();
// add the group deco
pWindow->m_dWindowDecorations.emplace_back(std::make_unique<CHyprGroupBarDecoration>(pWindow));
PNODE->pGroupParent = OPENINGON->pGroupParent;
PNODE->pGroupParent->groupMembers.push_back(PNODE);
PNODE->pGroupParent->groupMemberActive = PNODE->pGroupParent->groupMembers.size() - 1;
PNODE->pGroupParent->recalcSizePosRecursive();
} else {
NEWPARENT->recalcSizePosRecursive();
applyNodeDataToWindow(PNODE);
applyNodeDataToWindow(OPENINGON);
}
applyNodeDataToWindow(PNODE);
applyNodeDataToWindow(OPENINGON);
}
void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) {
@ -364,6 +387,47 @@ void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) {
if (!PNODE)
return;
// 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;
applyNodeDataToWindow(PNEXT);
} else {
const auto PHEAD = PNODE->getGroupHead();
PNEXT->position = PHEAD->position;
PNEXT->size = PHEAD->size;
applyNodeDataToWindow(PNEXT);
}
PNEXT->setGroupFocusedNode(PNEXT);
PNEXT->pWindow->m_bHidden = false;
m_lDwindleNodesData.remove(*PNODE);
return;
}
const auto PPARENT = PNODE->pParent;
if (!PPARENT) {
@ -385,29 +449,6 @@ void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) {
}
}
// check if it was grouped
if (PNODE->pGroupParent) {
PNODE->pGroupParent->groupMembers.erase(PNODE->pGroupParent->groupMembers.begin() + PNODE->pGroupParent->groupMemberActive);
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();
}
// if the parent is to be removed, remove the group
if (PPARENT == PNODE->pGroupParent) {
toggleWindowGroup(PPARENT->groupMembers[PPARENT->groupMemberActive]->pWindow);
}
}
PPARENT->valid = false;
PNODE->valid = false;
@ -647,6 +688,16 @@ void CHyprDwindleLayout::recalculateWindow(CWindow* pWindow) {
PNODE->recalcSizePosRecursive();
}
void addToDequeRecursive(std::deque<SDwindleNodeData*>* pDeque, std::deque<SDwindleNodeData*>* pParents, SDwindleNodeData* node) {
if (node->isNode) {
pParents->push_back(node);
addToDequeRecursive(pDeque, pParents, node->children[0]);
addToDequeRecursive(pDeque, pParents, node->children[1]);
} else {
pDeque->emplace_back(node);
}
}
void CHyprDwindleLayout::toggleWindowGroup(CWindow* pWindow) {
if (!g_pCompositor->windowValidMapped(pWindow))
return;
@ -662,61 +713,105 @@ void CHyprDwindleLayout::toggleWindowGroup(CWindow* pWindow) {
if (PWORKSPACE->m_bHasFullscreenWindow)
fullscreenRequestForWindow(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), FULLSCREEN_FULL, false);
const auto PGROUPPARENT = PNODE->pGroupParent;
if (PNODE->isGroupMember()) {
// dissolve group
if (PGROUPPARENT) {
// if there is a parent, release it
const auto INACTIVEBORDERCOL = CColor(g_pConfigManager->getInt("general:col.inactive_border"));
for (auto& node : PGROUPPARENT->groupMembers) {
node->pGroupParent = nullptr;
node->pWindow->m_cRealBorderColor.setValueAndWarp(INACTIVEBORDERCOL); // no anim here because they pop in
const auto PHEAD = PNODE->getGroupHead();
for (auto& wd : node->pWindow->m_dWindowDecorations) {
wd->updateWindow(node->pWindow);
SDwindleNodeData* current = PNODE->pNextGroupMember;
PNODE->pWindow->m_bIsFloating = PHEAD->pWindow->m_bIsFloating;
std::deque<CWindow*> 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->m_bHidden = false;
}
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);
}
recalculateMonitor(PWORKSPACE->m_iMonitorID);
} else {
// create group
if (!PNODE->pParent)
return;
PNODE->groupHead = true;
std::deque<SDwindleNodeData*> newGroupMembers;
std::deque<SDwindleNodeData*> nodesToRemove;
newGroupMembers.emplace_back(PNODE);
addToDequeRecursive(&newGroupMembers, &nodesToRemove, PNODE->pParent->children[0] == PNODE ? PNODE->pParent->children[1] : PNODE->pParent->children[0]);
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;
}
}
PGROUPPARENT->groupMembers.clear();
const auto PPARENT2 = PNODE->pParent->pParent;
PGROUPPARENT->isGroup = false;
m_lDwindleNodesData.remove(*PNODE->pParent);
PGROUPPARENT->recalcSizePosRecursive();
PNODE->pParent = PPARENT2;
if (g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow))
g_pCompositor->m_pLastWindow->m_cRealBorderColor = CColor(g_pConfigManager->getInt("general:col.active_border"));
} else {
// if there is no parent, let's make one
// 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 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];
if (!PPARENT)
return; // reject making group on single window
PPARENT->isGroup = true;
// recursively get all members
std::deque<SDwindleNodeData*> allChildren;
PPARENT->getAllChildrenRecursive(&allChildren);
PPARENT->groupMembers = allChildren;
const auto GROUPINACTIVEBORDERCOL = CColor(g_pConfigManager->getInt("dwinle:col.group_border"));
for (auto& c : PPARENT->groupMembers) {
c->pGroupParent = PPARENT;
c->pWindow->m_cRealBorderColor = GROUPINACTIVEBORDERCOL;
c->pWindow->m_dWindowDecorations.push_back(std::make_unique<CHyprGroupBarDecoration>(c->pWindow));
if (c->pWindow == g_pCompositor->m_pLastWindow)
c->pWindow->m_cRealBorderColor = CColor(g_pConfigManager->getInt("dwindle:col.group_border_active"));
newGroupMembers[i]->pPreviousGroupMember = PREVMEMBER;
newGroupMembers[i]->pNextGroupMember = NEXTMEMBER;
}
PPARENT->groupMemberActive = 0;
PPARENT->recalcSizePosRecursive();
// focus
PNODE->setGroupFocusedNode(PNODE);
}
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
g_pInputManager->refocus();
}
@ -733,13 +828,13 @@ std::deque<CWindow*> CHyprDwindleLayout::getGroupMembers(CWindow* pWindow) {
if (!PNODE)
return result; // reject with empty
const auto PGROUPPARENT = PNODE->pGroupParent;
SDwindleNodeData* current = PNODE->pNextGroupMember;
if (!PGROUPPARENT)
return result; // reject with empty
result.push_back(pWindow);
for (auto& node : PGROUPPARENT->groupMembers) {
result.push_back(node->pWindow);
while (current != PNODE) {
result.push_back(current->pWindow);
current = current->pNextGroupMember;
}
return result;
@ -751,45 +846,40 @@ void CHyprDwindleLayout::switchGroupWindow(CWindow* pWindow, bool forward) {
const auto PNODE = getNodeFromWindow(pWindow);
if (!PNODE)
return; // reject
if (!PNODE->pGroupParent)
if (!PNODE || !PNODE->isGroupMember())
return; // reject
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PNODE->workspaceID);
SDwindleNodeData* pNewNode;
if (forward)
PNODE->pGroupParent->groupMemberActive++;
pNewNode = PNODE->pNextGroupMember;
else
PNODE->pGroupParent->groupMemberActive--;
pNewNode = PNODE->pPreviousGroupMember;
if (PNODE->pGroupParent->groupMemberActive < 0)
PNODE->pGroupParent->groupMemberActive = PNODE->pGroupParent->groupMembers.size() - 1;
PNODE->setGroupFocusedNode(pNewNode);
if ((long unsigned int)PNODE->pGroupParent->groupMemberActive >= PNODE->pGroupParent->groupMembers.size())
PNODE->pGroupParent->groupMemberActive = 0;
pNewNode->position = PNODE->position;
pNewNode->size = PNODE->size;
bool restoreFullscreen = false;
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) {
fullscreenRequestForWindow(PNODE->pWindow, PWORKSPACE->m_efFullscreenMode, false);
restoreFullscreen = true;
}
PNODE->pWindow->m_bHidden = false;
g_pCompositor->setWindowFullscreen(PNODE->pWindow, false, PWORKSPACE->m_efFullscreenMode);
PNODE->pWindow->m_bHidden = true;
g_pCompositor->setWindowFullscreen(pNewNode->pWindow, true, PWORKSPACE->m_efFullscreenMode);
PNODE->pGroupParent->recalcSizePosRecursive();
for (auto& gm : PNODE->pGroupParent->groupMembers) {
for (auto& deco : gm->pWindow->m_dWindowDecorations) {
deco->updateWindow(gm->pWindow);
}
}
// focus
g_pCompositor->focusWindow(PNODE->pGroupParent->groupMembers[PNODE->pGroupParent->groupMemberActive]->pWindow);
if (restoreFullscreen) {
fullscreenRequestForWindow(PNODE->pGroupParent->groupMembers[PNODE->pGroupParent->groupMemberActive]->pWindow, PWORKSPACE->m_efFullscreenMode, true);
pNewNode->pWindow->m_vRealSize.warp();
pNewNode->pWindow->m_vRealPosition.warp();
}
}
@ -802,7 +892,7 @@ SWindowRenderLayoutHints CHyprDwindleLayout::requestRenderHints(CWindow* pWindow
if (!PNODE)
return hints; // left for the future, maybe floating funkiness
if (PNODE->pGroupParent) {
if (PNODE->isGroupMember()) {
hints.isBorderColor = true;
if (pWindow == g_pCompositor->m_pLastWindow)

View file

@ -18,10 +18,9 @@ struct SDwindleNodeData {
bool splitTop = false; // for preserve_split
bool isGroup = false;
int groupMemberActive = 0;
std::deque<SDwindleNodeData*> groupMembers;
SDwindleNodeData* pGroupParent = nullptr;
bool groupHead = false;
SDwindleNodeData* pNextGroupMember = nullptr;
SDwindleNodeData* pPreviousGroupMember = nullptr;
Vector2D position;
Vector2D size;
@ -39,6 +38,9 @@ struct SDwindleNodeData {
void recalcSizePosRecursive(bool force = false);
void getAllChildrenRecursive(std::deque<SDwindleNodeData*>*);
bool isGroupMember();
SDwindleNodeData* getGroupHead();
void setGroupFocusedNode(SDwindleNodeData*);
CHyprDwindleLayout* layout = nullptr;
};

View file

@ -260,6 +260,8 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
pWindow->m_sSpecialRenderData.rounding = true;
}
g_pCompositor->updateWindowAnimatedDecorationValues(pWindow);
pWindow->updateToplevel();
}