From 1357b66091ecd73f097d19d527a23a9ae72a4ff1 Mon Sep 17 00:00:00 2001 From: memchr <118117622+memchr@users.noreply.github.com> Date: Thu, 21 Sep 2023 23:42:00 +0000 Subject: [PATCH] windowrules: add rule `group` to map windows grouped (#3279) * windows: add rule group to map windows grouped * group rule: use `invade` to force open a window in a locked group --- src/Compositor.cpp | 8 ++- src/Window.cpp | 63 ++++++++++++++++++++ src/Window.hpp | 19 +++++- src/config/ConfigManager.cpp | 6 +- src/events/Windows.cpp | 47 +++++++++++++++ src/layout/DwindleLayout.cpp | 17 ++++-- src/layout/MasterLayout.cpp | 15 +++-- src/managers/KeybindManager.cpp | 100 ++++++++++++-------------------- src/managers/KeybindManager.hpp | 1 + 9 files changed, 200 insertions(+), 76 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 7e5a6c26..2960fc2c 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1674,6 +1674,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 NOGROUPACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.nogroup_border_active")->data.get(); + static auto* const NOGROUPINACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.nogroup_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 GROUPACTIVELOCKEDCOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.group_border_locked_active")->data.get(); @@ -1703,12 +1705,14 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) { else { const bool GROUPLOCKED = pWindow->m_sGroupData.pNextWindow ? pWindow->getGroupHead()->m_sGroupData.locked : false; if (pWindow == m_pLastWindow) { - const auto* const ACTIVECOLOR = !pWindow->m_sGroupData.pNextWindow ? ACTIVECOL : (GROUPLOCKED ? GROUPACTIVELOCKEDCOL : GROUPACTIVECOL); + const auto* const ACTIVECOLOR = + !pWindow->m_sGroupData.pNextWindow ? (!pWindow->m_sGroupData.deny ? ACTIVECOL : NOGROUPACTIVECOL) : (GROUPLOCKED ? GROUPACTIVELOCKEDCOL : 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 : (GROUPLOCKED ? GROUPINACTIVELOCKEDCOL : GROUPINACTIVECOL); + const auto* const INACTIVECOLOR = + !pWindow->m_sGroupData.pNextWindow ? (!pWindow->m_sGroupData.deny ? INACTIVECOL : NOGROUPINACTIVECOL) : (GROUPLOCKED ? GROUPINACTIVELOCKEDCOL : GROUPINACTIVECOL); setBorderColor(pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying() >= 0 ? CGradientValueData(CColor(pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying())) : *INACTIVECOLOR); diff --git a/src/Window.cpp b/src/Window.cpp index 3df30123..4ee40dff 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -641,6 +641,69 @@ bool CWindow::hasPopupAt(const Vector2D& pos) { return resultSurf; } +void CWindow::applyGroupRules() { + if ((m_eGroupRules & GROUP_SET && m_bFirstMap) || m_eGroupRules & GROUP_SET_ALWAYS) + createGroup(); + + if (m_sGroupData.pNextWindow && ((m_eGroupRules & GROUP_LOCK && m_bFirstMap) || m_eGroupRules & GROUP_LOCK_ALWAYS)) + getGroupHead()->m_sGroupData.locked = true; +} + +void CWindow::createGroup() { + if (m_sGroupData.deny) { + Debug::log(LOG, "createGroup: window:{:x},title:{} is denied as a group, ignored", (uintptr_t)this, this->m_szTitle); + return; + } + if (!m_sGroupData.pNextWindow) { + m_sGroupData.pNextWindow = this; + m_sGroupData.head = true; + m_sGroupData.locked = false; + m_sGroupData.deny = false; + + m_dWindowDecorations.emplace_back(std::make_unique(this)); + updateWindowDecos(); + + g_pLayoutManager->getCurrentLayout()->recalculateWindow(this); + g_pCompositor->updateAllWindowsAnimatedDecorationValues(); + } +} + +void CWindow::destroyGroup() { + if (m_sGroupData.pNextWindow == this) { + if (m_eGroupRules & GROUP_SET_ALWAYS) { + Debug::log(LOG, "destoryGroup: window:{:x},title:{} has rule [group set always], ignored", (uintptr_t)this, this->m_szTitle); + return; + } + m_sGroupData.pNextWindow = nullptr; + updateWindowDecos(); + return; + } + + CWindow* curr = this; + 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 != this); + + for (auto& w : members) { + if (w->m_sGroupData.head) + g_pLayoutManager->getCurrentLayout()->onWindowRemoved(curr); + w->m_sGroupData.head = false; + } + + const bool GROUPSLOCKEDPREV = g_pKeybindManager->m_bGroupsLocked; + g_pKeybindManager->m_bGroupsLocked = true; + for (auto& w : members) { + g_pLayoutManager->getCurrentLayout()->onWindowCreated(w); + w->updateWindowDecos(); + } + g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV; +} + CWindow* CWindow::getGroupHead() { CWindow* curr = this; while (!curr->m_sGroupData.head) diff --git a/src/Window.hpp b/src/Window.hpp index 7e4c73b8..81b6156f 100644 --- a/src/Window.hpp +++ b/src/Window.hpp @@ -18,6 +18,18 @@ enum eIdleInhibitMode { IDLEINHIBIT_FOCUS }; +enum eGroupRules { + // effective only during first map, except for _ALWAYS variant + GROUP_NONE = 0, + GROUP_SET = 1 << 0, // Open as new group or add to focused group + GROUP_SET_ALWAYS = 1 << 1, + GROUP_BARRED = 1 << 2, // Don't insert to focused group. + GROUP_LOCK = 1 << 3, // Lock m_sGroupData.lock + GROUP_LOCK_ALWAYS = 1 << 4, + GROUP_INVADE = 1 << 5, // Force enter a group, event if lock is engaged + GROUP_OVERRIDE = 1 << 6, // Override other rules +}; + template class CWindowOverridableVar { public: @@ -300,8 +312,10 @@ class CWindow { struct SGroupData { CWindow* pNextWindow = nullptr; // nullptr means no grouping. Self means single group. bool head = false; - bool locked = false; + bool locked = false; // per group lock + bool deny = false; // deny window from enter a group or made a group } m_sGroupData; + uint16_t m_eGroupRules = GROUP_NONE; // For the list lookup bool operator==(const CWindow& rhs) { @@ -342,6 +356,9 @@ class CWindow { bool isInCurvedCorner(double x, double y); bool hasPopupAt(const Vector2D& pos); + void applyGroupRules(); + void createGroup(); + void destroyGroup(); CWindow* getGroupHead(); CWindow* getGroupTail(); CWindow* getGroupCurrent(); diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 636582fc..1e7d8177 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -17,6 +17,8 @@ extern "C" char** environ; CConfigManager::CConfigManager() { configValues["general:col.active_border"].data = std::make_shared(0xffffffff); configValues["general:col.inactive_border"].data = std::make_shared(0xff444444); + configValues["general:col.nogroup_border"].data = std::make_shared(0xffffaaff); + configValues["general:col.nogroup_border_active"].data = std::make_shared(0xffff00ff); configValues["general:col.group_border"].data = std::make_shared(0x66777700); configValues["general:col.group_border_active"].data = std::make_shared(0x66ffff00); configValues["general:col.group_border_locked"].data = std::make_shared(0x66775500); @@ -72,6 +74,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.nogroup_border"].data.get())->reset(0xff444444); + ((CGradientValueData*)configValues["general:col.nogroup_border_active"].data.get())->reset(0xffff00ff); ((CGradientValueData*)configValues["general:col.group_border"].data.get())->reset(0x66777700); ((CGradientValueData*)configValues["general:col.group_border_active"].data.get())->reset(0x66ffff00); ((CGradientValueData*)configValues["general:col.group_border_locked"].data.get())->reset(0x66775500); @@ -904,7 +908,7 @@ bool windowRuleValid(const std::string& RULE) { RULE != "nomaximizerequest" && RULE != "fakefullscreen" && RULE != "nomaxsize" && RULE != "pin" && RULE != "noanim" && RULE != "dimaround" && RULE != "windowdance" && RULE != "maximize" && RULE != "keepaspectratio" && RULE.find("animation") != 0 && RULE.find("rounding") != 0 && RULE.find("workspace") != 0 && RULE.find("bordercolor") != 0 && RULE != "forcergbx" && RULE != "noinitialfocus" && RULE != "stayfocused" && RULE.find("bordersize") != 0 && RULE.find("xray") != 0 && - RULE.find("center") != 0); + RULE.find("center") != 0 && RULE.find("group") != 0); } bool layerRuleValid(const std::string& RULE) { diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 41c19ab4..d0ae4ae8 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -198,6 +198,53 @@ void Events::listener_mapWindow(void* owner, void* data) { overridingNoMaximize = true; } else if (r.szRule == "stayfocused") { PWINDOW->m_bStayFocused = true; + } else if (r.szRule.find("group") == 0) { + if (PWINDOW->m_eGroupRules & GROUP_OVERRIDE) + continue; + + // `group` is a shorthand of `group set` + if (removeBeginEndSpacesTabs(r.szRule) == "group") { + PWINDOW->m_eGroupRules |= GROUP_SET; + continue; + } + + CVarList vars(r.szRule, 0, 's'); + std::string vPrev = ""; + + for (auto const& v : vars) { + if (v == "group") + continue; + + if (v == "set") { + PWINDOW->m_eGroupRules |= GROUP_SET; + } else if (v == "new") { + // shorthand for `group barred set` + PWINDOW->m_eGroupRules |= (GROUP_SET | GROUP_BARRED); + } else if (v == "lock") { + PWINDOW->m_eGroupRules |= GROUP_LOCK; + } else if (v == "invade") { + PWINDOW->m_eGroupRules |= GROUP_INVADE; + } else if (v == "barred") { + PWINDOW->m_eGroupRules |= GROUP_BARRED; + } else if (v == "deny") { + PWINDOW->m_sGroupData.deny = true; + } else if (v == "override") { + // Clear existing rules + PWINDOW->m_eGroupRules = GROUP_OVERRIDE; + } else if (v == "unset") { + // Clear existing rules and stop processing + PWINDOW->m_eGroupRules = GROUP_OVERRIDE; + break; + } else if (v == "always") { + if (vPrev == "set" || vPrev == "group") + PWINDOW->m_eGroupRules |= GROUP_SET_ALWAYS; + else if (vPrev == "lock") + PWINDOW->m_eGroupRules |= GROUP_LOCK_ALWAYS; + else + Debug::log(ERR, "windowrule `group` does not support `{} always`", vPrev); + } + vPrev = v; + } } else if (r.szRule.find("idleinhibit") == 0) { auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1); diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 1688b417..fae4af52 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -315,14 +315,21 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire applyNodeDataToWindow(PNODE); + pWindow->applyGroupRules(); + return; } // if it's a group, add the window - if (OPENINGON->pWindow->m_sGroupData.pNextWindow && // target is group - !OPENINGON->pWindow->getGroupHead()->m_sGroupData.locked && // target unlocked - !(pWindow->m_sGroupData.pNextWindow && pWindow->getGroupHead()->m_sGroupData.locked) && // source unlocked or isn't group - !g_pKeybindManager->m_bGroupsLocked && !m_vOverrideFocalPoint) { + if (OPENINGON->pWindow->m_sGroupData.pNextWindow // target is group + && !g_pKeybindManager->m_bGroupsLocked // global group lock disengaged + && ((pWindow->m_eGroupRules & GROUP_INVADE && pWindow->m_bFirstMap) // window ignore local group locks, or + || (!OPENINGON->pWindow->getGroupHead()->m_sGroupData.locked // target unlocked + && !(pWindow->m_sGroupData.pNextWindow && pWindow->getGroupHead()->m_sGroupData.locked))) // source unlocked or isn't group + && !pWindow->m_sGroupData.deny // source is not denied entry + && !(pWindow->m_eGroupRules & GROUP_BARRED && pWindow->m_bFirstMap) // group rule doesn't prevent adding window + && !m_vOverrideFocalPoint // we are not moving window + ) { if (!pWindow->m_sGroupData.pNextWindow) pWindow->m_dWindowDecorations.emplace_back(std::make_unique(pWindow)); @@ -342,6 +349,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire } OPENINGON->pWindow->setGroupCurrent(pWindow); + pWindow->applyGroupRules(); pWindow->updateWindowDecos(); recalculateWindow(pWindow); @@ -475,6 +483,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire applyNodeDataToWindow(PNODE); applyNodeDataToWindow(OPENINGON); + pWindow->applyGroupRules(); } void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) { diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 5b5d0122..c1dd37dc 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -95,11 +95,15 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); // if it's a group, add the window - if (OPENINGON && OPENINGON != PNODE && OPENINGON->pWindow->m_sGroupData.pNextWindow && // target is group - !OPENINGON->pWindow->getGroupHead()->m_sGroupData.locked && // target unlocked - !(pWindow->m_sGroupData.pNextWindow && pWindow->getGroupHead()->m_sGroupData.locked) && // source unlocked or isn't group - !g_pKeybindManager->m_bGroupsLocked // global group lock disengaged + if (OPENINGON && OPENINGON != PNODE && OPENINGON->pWindow->m_sGroupData.pNextWindow // target is group + && !g_pKeybindManager->m_bGroupsLocked // global group lock disengaged + && ((pWindow->m_eGroupRules & GROUP_INVADE && pWindow->m_bFirstMap) // window ignore local group locks, or + || (!OPENINGON->pWindow->getGroupHead()->m_sGroupData.locked // target unlocked + && !(pWindow->m_sGroupData.pNextWindow && pWindow->getGroupHead()->m_sGroupData.locked))) // source unlocked or isn't group + && !pWindow->m_sGroupData.deny // source is not denied entry + && !(pWindow->m_eGroupRules & GROUP_BARRED) // group rule doesn't prevent adding window ) { + if (!pWindow->m_sGroupData.pNextWindow) pWindow->m_dWindowDecorations.emplace_back(std::make_unique(pWindow)); @@ -119,12 +123,15 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc } OPENINGON->pWindow->setGroupCurrent(pWindow); + pWindow->applyGroupRules(); pWindow->updateWindowDecos(); recalculateWindow(pWindow); return; } + pWindow->applyGroupRules(); + if (*PNEWISMASTER || WINDOWSONWORKSPACE == 1 || (!pWindow->m_bFirstMap && OPENINGON->isMaster)) { for (auto& nd : m_lMasterNodesData) { if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) { diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 0703ba2e..0e4d47b9 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -72,6 +72,7 @@ CKeybindManager::CKeybindManager() { m_mDispatchers["moveoutofgroup"] = moveOutOfGroup; m_mDispatchers["movewindoworgroup"] = moveWindowOrGroup; m_mDispatchers["setignoregrouplock"] = setIgnoreGroupLock; + m_mDispatchers["denywindowfromgroup"] = denyWindowFromGroup; m_mDispatchers["global"] = global; m_tScrollTimer.reset(); @@ -1151,46 +1152,10 @@ void CKeybindManager::toggleGroup(std::string args) { g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL); - if (!PWINDOW->m_sGroupData.pNextWindow) { - PWINDOW->m_sGroupData.pNextWindow = PWINDOW; - PWINDOW->m_sGroupData.head = true; - PWINDOW->m_sGroupData.locked = false; - - PWINDOW->m_dWindowDecorations.emplace_back(std::make_unique(PWINDOW)); - - PWINDOW->updateWindowDecos(); - g_pLayoutManager->getCurrentLayout()->recalculateWindow(PWINDOW); - } 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; - } - - const bool GROUPSLOCKEDPREV = g_pKeybindManager->m_bGroupsLocked; - g_pKeybindManager->m_bGroupsLocked = true; - for (auto& w : members) { - g_pLayoutManager->getCurrentLayout()->onWindowCreated(w); - w->updateWindowDecos(); - } - g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV; - } - } + if (!PWINDOW->m_sGroupData.pNextWindow) + PWINDOW->createGroup(); + else + PWINDOW->destroyGroup(); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); } @@ -1978,6 +1943,9 @@ void CKeybindManager::lockActiveGroup(std::string args) { } void CKeybindManager::moveWindowIntoGroup(CWindow* pWindow, CWindow* pWindowInDirection) { + if (pWindow->m_sGroupData.deny) + return; + if (!pWindow->m_sGroupData.pNextWindow) pWindow->m_dWindowDecorations.emplace_back(std::make_unique(pWindow)); @@ -1995,6 +1963,7 @@ void CKeybindManager::moveWindowIntoGroup(CWindow* pWindow, CWindow* pWindowInDi } void CKeybindManager::moveWindowOutOfGroup(CWindow* pWindow, const std::string& dir) { + static auto* const BFOCUSREMOVEDWINDOW = &g_pConfigManager->getConfigValuePtr("misc:group_focus_removed_window")->intValue; const auto PWINDOWPREV = pWindow->getGroupPrevious(); eDirection direction; @@ -2010,8 +1979,7 @@ void CKeybindManager::moveWindowOutOfGroup(CWindow* pWindow, const std::string& } if (pWindow->m_sGroupData.pNextWindow == pWindow) { - pWindow->m_sGroupData.pNextWindow = nullptr; - pWindow->updateWindowDecos(); + pWindow->destroyGroup(); } else { g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow); @@ -2044,7 +2012,7 @@ void CKeybindManager::moveIntoGroup(std::string args) { const auto PWINDOW = g_pCompositor->m_pLastWindow; - if (!PWINDOW || PWINDOW->m_bIsFloating) + if (!PWINDOW || PWINDOW->m_bIsFloating || PWINDOW->m_sGroupData.deny) return; auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(PWINDOW, arg); @@ -2071,7 +2039,7 @@ void CKeybindManager::moveOutOfGroup(std::string args) { void CKeybindManager::moveWindowOrGroup(std::string args) { char arg = args[0]; - static auto* const BIGNOREGROUPLOCK = &g_pConfigManager->getConfigValuePtr("binds:ignore_group_lock")->intValue; + static auto* const PIGNOREGROUPLOCK = &g_pConfigManager->getConfigValuePtr("binds:ignore_group_lock")->intValue; if (!isDirection(args)) { Debug::log(ERR, "Cannot move into group in direction %c, unsupported direction. Supported: l,r,u/t,d/b", arg); @@ -2079,40 +2047,31 @@ void CKeybindManager::moveWindowOrGroup(std::string args) { } const auto PWINDOW = g_pCompositor->m_pLastWindow; - if (!PWINDOW || PWINDOW->m_bIsFullscreen) return; + const auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(PWINDOW, arg); - const auto ISWINDOWGROUP = PWINDOW->m_sGroupData.pNextWindow; - const auto ISWINDOWGROUPLOCKED = ISWINDOWGROUP && PWINDOW->getGroupHead()->m_sGroupData.locked; - - const auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(PWINDOW, arg); - const auto ISWINDOWINDIRGROUP = PWINDOWINDIR && PWINDOWINDIR->m_sGroupData.pNextWindow; - const auto ISWINDOWINDIRGROUPLOCKED = ISWINDOWINDIRGROUP && PWINDOWINDIR->getGroupHead()->m_sGroupData.locked; + const bool ISWINDOWGROUP = PWINDOW->m_sGroupData.pNextWindow; + const bool ISWINDOWGROUPLOCKED = ISWINDOWGROUP && PWINDOW->getGroupHead()->m_sGroupData.locked; + const bool ISWINDOWGROUPSINGLE = ISWINDOWGROUP && PWINDOW->m_sGroupData.pNextWindow == PWINDOW; // note: PWINDOWINDIR is not null implies !PWINDOW->m_bIsFloating - if (ISWINDOWINDIRGROUP && !ISWINDOWINDIRGROUPLOCKED) { - if (ISWINDOWGROUPLOCKED && !*BIGNOREGROUPLOCK) { + if (PWINDOWINDIR && PWINDOWINDIR->m_sGroupData.pNextWindow) { // target is group + if (!*PIGNOREGROUPLOCK && (PWINDOWINDIR->getGroupHead()->m_sGroupData.locked || ISWINDOWGROUPLOCKED || PWINDOW->m_sGroupData.deny)) { g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args); g_pCompositor->warpCursorTo(PWINDOW->middle()); } else moveWindowIntoGroup(PWINDOW, PWINDOWINDIR); - } else if (ISWINDOWINDIRGROUPLOCKED) { - if (!*BIGNOREGROUPLOCK) { + } else if (PWINDOWINDIR) { // target is regular window + if ((!*PIGNOREGROUPLOCK && ISWINDOWGROUPLOCKED) || !ISWINDOWGROUP || (ISWINDOWGROUPSINGLE && PWINDOW->m_eGroupRules & GROUP_SET_ALWAYS)) { g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args); g_pCompositor->warpCursorTo(PWINDOW->middle()); } else - moveWindowIntoGroup(PWINDOW, PWINDOWINDIR); - } else if (PWINDOWINDIR) { - if (ISWINDOWGROUP && (*BIGNOREGROUPLOCK || !ISWINDOWGROUPLOCKED)) moveWindowOutOfGroup(PWINDOW, args); - else { - g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args); - g_pCompositor->warpCursorTo(PWINDOW->middle()); - } - } else if (ISWINDOWGROUP && (*BIGNOREGROUPLOCK || !ISWINDOWGROUPLOCKED)) { + } else if ((*PIGNOREGROUPLOCK || !ISWINDOWGROUPLOCKED) && ISWINDOWGROUP) // no target window moveWindowOutOfGroup(PWINDOW, args); - } + + g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW); } void CKeybindManager::setIgnoreGroupLock(std::string args) { @@ -2126,6 +2085,19 @@ void CKeybindManager::setIgnoreGroupLock(std::string args) { g_pEventManager->postEvent(SHyprIPCEvent{"ignoregrouplock", std::to_string(*BIGNOREGROUPLOCK)}); } +void CKeybindManager::denyWindowFromGroup(std::string args) { + const auto PWINDOW = g_pCompositor->m_pLastWindow; + if (!PWINDOW || (PWINDOW && PWINDOW->m_sGroupData.pNextWindow)) + return; + + if (args == "toggle") + PWINDOW->m_sGroupData.deny = !PWINDOW->m_sGroupData.deny; + else + PWINDOW->m_sGroupData.deny = args == "on"; + + g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW); +} + void CKeybindManager::global(std::string args) { const auto APPID = args.substr(0, args.find_first_of(':')); const auto NAME = args.substr(args.find_first_of(':') + 1); diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 4a4ebeab..9c63249e 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -151,6 +151,7 @@ class CKeybindManager { static void moveGroupWindow(std::string); static void moveWindowOrGroup(std::string); static void setIgnoreGroupLock(std::string); + static void denyWindowFromGroup(std::string); static void global(std::string); friend class CCompositor;