aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authormemchr <[email protected]>2023-09-21 23:42:00 +0000
committerGitHub <[email protected]>2023-09-22 00:42:00 +0100
commit1357b66091ecd73f097d19d527a23a9ae72a4ff1 (patch)
treee629bedcce584757ebd1afae0dcc12ea25f15c95
parent2e1842b5ff140bc81a604c663482221d86c30cff (diff)
downloadHyprland-1357b66091ecd73f097d19d527a23a9ae72a4ff1.tar.gz
Hyprland-1357b66091ecd73f097d19d527a23a9ae72a4ff1.zip
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
-rw-r--r--src/Compositor.cpp8
-rw-r--r--src/Window.cpp63
-rw-r--r--src/Window.hpp19
-rw-r--r--src/config/ConfigManager.cpp6
-rw-r--r--src/events/Windows.cpp47
-rw-r--r--src/layout/DwindleLayout.cpp17
-rw-r--r--src/layout/MasterLayout.cpp15
-rw-r--r--src/managers/KeybindManager.cpp100
-rw-r--r--src/managers/KeybindManager.hpp1
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<CHyprGroupBarDecoration>(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<CWindow*> 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 <typename T>
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<CGradientValueData>(0xffffffff);
configValues["general:col.inactive_border"].data = std::make_shared<CGradientValueData>(0xff444444);
+ configValues["general:col.nogroup_border"].data = std::make_shared<CGradientValueData>(0xffffaaff);
+ configValues["general:col.nogroup_border_active"].data = std::make_shared<CGradientValueData>(0xffff00ff);
configValues["general:col.group_border"].data = std::make_shared<CGradientValueData>(0x66777700);
configValues["general:col.group_border_active"].data = std::make_shared<CGradientValueData>(0x66ffff00);
configValues["general:col.group_border_locked"].data = std::make_shared<CGradientValueData>(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<CHyprGroupBarDecoration>(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<CHyprGroupBarDecoration>(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<CHyprGroupBarDecoration>(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<CWindow*> 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<CHyprGroupBarDecoration>(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;