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
This commit is contained in:
memchr 2023-09-21 23:42:00 +00:00 committed by GitHub
parent 2e1842b5ff
commit 1357b66091
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 200 additions and 76 deletions

View file

@ -1674,6 +1674,8 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
// optimization // optimization
static auto* const ACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.active_border")->data.get(); 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 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 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 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(); 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 { else {
const bool GROUPLOCKED = pWindow->m_sGroupData.pNextWindow ? pWindow->getGroupHead()->m_sGroupData.locked : false; const bool GROUPLOCKED = pWindow->m_sGroupData.pNextWindow ? pWindow->getGroupHead()->m_sGroupData.locked : false;
if (pWindow == m_pLastWindow) { 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 ? setBorderColor(pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying() >= 0 ?
CGradientValueData(CColor(pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying())) : CGradientValueData(CColor(pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying())) :
*ACTIVECOLOR); *ACTIVECOLOR);
} else { } 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 ? setBorderColor(pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying() >= 0 ?
CGradientValueData(CColor(pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying())) : CGradientValueData(CColor(pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying())) :
*INACTIVECOLOR); *INACTIVECOLOR);

View file

@ -641,6 +641,69 @@ bool CWindow::hasPopupAt(const Vector2D& pos) {
return resultSurf; 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* CWindow::getGroupHead() {
CWindow* curr = this; CWindow* curr = this;
while (!curr->m_sGroupData.head) while (!curr->m_sGroupData.head)

View file

@ -18,6 +18,18 @@ enum eIdleInhibitMode {
IDLEINHIBIT_FOCUS 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> template <typename T>
class CWindowOverridableVar { class CWindowOverridableVar {
public: public:
@ -300,8 +312,10 @@ class CWindow {
struct SGroupData { struct SGroupData {
CWindow* pNextWindow = nullptr; // nullptr means no grouping. Self means single group. CWindow* pNextWindow = nullptr; // nullptr means no grouping. Self means single group.
bool head = false; 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; } m_sGroupData;
uint16_t m_eGroupRules = GROUP_NONE;
// For the list lookup // For the list lookup
bool operator==(const CWindow& rhs) { bool operator==(const CWindow& rhs) {
@ -342,6 +356,9 @@ class CWindow {
bool isInCurvedCorner(double x, double y); bool isInCurvedCorner(double x, double y);
bool hasPopupAt(const Vector2D& pos); bool hasPopupAt(const Vector2D& pos);
void applyGroupRules();
void createGroup();
void destroyGroup();
CWindow* getGroupHead(); CWindow* getGroupHead();
CWindow* getGroupTail(); CWindow* getGroupTail();
CWindow* getGroupCurrent(); CWindow* getGroupCurrent();

View file

@ -17,6 +17,8 @@ extern "C" char** environ;
CConfigManager::CConfigManager() { CConfigManager::CConfigManager() {
configValues["general:col.active_border"].data = std::make_shared<CGradientValueData>(0xffffffff); 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.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"].data = std::make_shared<CGradientValueData>(0x66777700);
configValues["general:col.group_border_active"].data = std::make_shared<CGradientValueData>(0x66ffff00); configValues["general:col.group_border_active"].data = std::make_shared<CGradientValueData>(0x66ffff00);
configValues["general:col.group_border_locked"].data = std::make_shared<CGradientValueData>(0x66775500); 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; configValues["general:gaps_out"].intValue = 20;
((CGradientValueData*)configValues["general:col.active_border"].data.get())->reset(0xffffffff); ((CGradientValueData*)configValues["general:col.active_border"].data.get())->reset(0xffffffff);
((CGradientValueData*)configValues["general:col.inactive_border"].data.get())->reset(0xff444444); ((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"].data.get())->reset(0x66777700);
((CGradientValueData*)configValues["general:col.group_border_active"].data.get())->reset(0x66ffff00); ((CGradientValueData*)configValues["general:col.group_border_active"].data.get())->reset(0x66ffff00);
((CGradientValueData*)configValues["general:col.group_border_locked"].data.get())->reset(0x66775500); ((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 != "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 != "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("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) { bool layerRuleValid(const std::string& RULE) {

View file

@ -198,6 +198,53 @@ void Events::listener_mapWindow(void* owner, void* data) {
overridingNoMaximize = true; overridingNoMaximize = true;
} else if (r.szRule == "stayfocused") { } else if (r.szRule == "stayfocused") {
PWINDOW->m_bStayFocused = true; 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) { } else if (r.szRule.find("idleinhibit") == 0) {
auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1); auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);

View file

@ -315,14 +315,21 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
applyNodeDataToWindow(PNODE); applyNodeDataToWindow(PNODE);
pWindow->applyGroupRules();
return; return;
} }
// if it's a group, add the window // if it's a group, add the window
if (OPENINGON->pWindow->m_sGroupData.pNextWindow && // target is group if (OPENINGON->pWindow->m_sGroupData.pNextWindow // target is group
!OPENINGON->pWindow->getGroupHead()->m_sGroupData.locked && // target unlocked && !g_pKeybindManager->m_bGroupsLocked // global group lock disengaged
!(pWindow->m_sGroupData.pNextWindow && pWindow->getGroupHead()->m_sGroupData.locked) && // source unlocked or isn't group && ((pWindow->m_eGroupRules & GROUP_INVADE && pWindow->m_bFirstMap) // window ignore local group locks, or
!g_pKeybindManager->m_bGroupsLocked && !m_vOverrideFocalPoint) { || (!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) if (!pWindow->m_sGroupData.pNextWindow)
pWindow->m_dWindowDecorations.emplace_back(std::make_unique<CHyprGroupBarDecoration>(pWindow)); 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); OPENINGON->pWindow->setGroupCurrent(pWindow);
pWindow->applyGroupRules();
pWindow->updateWindowDecos(); pWindow->updateWindowDecos();
recalculateWindow(pWindow); recalculateWindow(pWindow);
@ -475,6 +483,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
applyNodeDataToWindow(PNODE); applyNodeDataToWindow(PNODE);
applyNodeDataToWindow(OPENINGON); applyNodeDataToWindow(OPENINGON);
pWindow->applyGroupRules();
} }
void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) { void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) {

View file

@ -95,11 +95,15 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
// if it's a group, add the window // if it's a group, add the window
if (OPENINGON && OPENINGON != PNODE && OPENINGON->pWindow->m_sGroupData.pNextWindow && // target is group if (OPENINGON && OPENINGON != PNODE && OPENINGON->pWindow->m_sGroupData.pNextWindow // target is group
!OPENINGON->pWindow->getGroupHead()->m_sGroupData.locked && // target unlocked && !g_pKeybindManager->m_bGroupsLocked // global group lock disengaged
!(pWindow->m_sGroupData.pNextWindow && pWindow->getGroupHead()->m_sGroupData.locked) && // source unlocked or isn't group && ((pWindow->m_eGroupRules & GROUP_INVADE && pWindow->m_bFirstMap) // window ignore local group locks, or
!g_pKeybindManager->m_bGroupsLocked // global group lock disengaged || (!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) if (!pWindow->m_sGroupData.pNextWindow)
pWindow->m_dWindowDecorations.emplace_back(std::make_unique<CHyprGroupBarDecoration>(pWindow)); 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); OPENINGON->pWindow->setGroupCurrent(pWindow);
pWindow->applyGroupRules();
pWindow->updateWindowDecos(); pWindow->updateWindowDecos();
recalculateWindow(pWindow); recalculateWindow(pWindow);
return; return;
} }
pWindow->applyGroupRules();
if (*PNEWISMASTER || WINDOWSONWORKSPACE == 1 || (!pWindow->m_bFirstMap && OPENINGON->isMaster)) { if (*PNEWISMASTER || WINDOWSONWORKSPACE == 1 || (!pWindow->m_bFirstMap && OPENINGON->isMaster)) {
for (auto& nd : m_lMasterNodesData) { for (auto& nd : m_lMasterNodesData) {
if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) { if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) {

View file

@ -72,6 +72,7 @@ CKeybindManager::CKeybindManager() {
m_mDispatchers["moveoutofgroup"] = moveOutOfGroup; m_mDispatchers["moveoutofgroup"] = moveOutOfGroup;
m_mDispatchers["movewindoworgroup"] = moveWindowOrGroup; m_mDispatchers["movewindoworgroup"] = moveWindowOrGroup;
m_mDispatchers["setignoregrouplock"] = setIgnoreGroupLock; m_mDispatchers["setignoregrouplock"] = setIgnoreGroupLock;
m_mDispatchers["denywindowfromgroup"] = denyWindowFromGroup;
m_mDispatchers["global"] = global; m_mDispatchers["global"] = global;
m_tScrollTimer.reset(); m_tScrollTimer.reset();
@ -1151,46 +1152,10 @@ void CKeybindManager::toggleGroup(std::string args) {
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL);
if (!PWINDOW->m_sGroupData.pNextWindow) { if (!PWINDOW->m_sGroupData.pNextWindow)
PWINDOW->m_sGroupData.pNextWindow = PWINDOW; PWINDOW->createGroup();
PWINDOW->m_sGroupData.head = true; else
PWINDOW->m_sGroupData.locked = false; PWINDOW->destroyGroup();
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;
}
}
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
} }
@ -1978,6 +1943,9 @@ void CKeybindManager::lockActiveGroup(std::string args) {
} }
void CKeybindManager::moveWindowIntoGroup(CWindow* pWindow, CWindow* pWindowInDirection) { void CKeybindManager::moveWindowIntoGroup(CWindow* pWindow, CWindow* pWindowInDirection) {
if (pWindow->m_sGroupData.deny)
return;
if (!pWindow->m_sGroupData.pNextWindow) if (!pWindow->m_sGroupData.pNextWindow)
pWindow->m_dWindowDecorations.emplace_back(std::make_unique<CHyprGroupBarDecoration>(pWindow)); 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) { void CKeybindManager::moveWindowOutOfGroup(CWindow* pWindow, const std::string& dir) {
static auto* const BFOCUSREMOVEDWINDOW = &g_pConfigManager->getConfigValuePtr("misc:group_focus_removed_window")->intValue; static auto* const BFOCUSREMOVEDWINDOW = &g_pConfigManager->getConfigValuePtr("misc:group_focus_removed_window")->intValue;
const auto PWINDOWPREV = pWindow->getGroupPrevious(); const auto PWINDOWPREV = pWindow->getGroupPrevious();
eDirection direction; eDirection direction;
@ -2010,8 +1979,7 @@ void CKeybindManager::moveWindowOutOfGroup(CWindow* pWindow, const std::string&
} }
if (pWindow->m_sGroupData.pNextWindow == pWindow) { if (pWindow->m_sGroupData.pNextWindow == pWindow) {
pWindow->m_sGroupData.pNextWindow = nullptr; pWindow->destroyGroup();
pWindow->updateWindowDecos();
} else { } else {
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow); g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow);
@ -2044,7 +2012,7 @@ void CKeybindManager::moveIntoGroup(std::string args) {
const auto PWINDOW = g_pCompositor->m_pLastWindow; const auto PWINDOW = g_pCompositor->m_pLastWindow;
if (!PWINDOW || PWINDOW->m_bIsFloating) if (!PWINDOW || PWINDOW->m_bIsFloating || PWINDOW->m_sGroupData.deny)
return; return;
auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(PWINDOW, arg); auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(PWINDOW, arg);
@ -2071,7 +2039,7 @@ void CKeybindManager::moveOutOfGroup(std::string args) {
void CKeybindManager::moveWindowOrGroup(std::string args) { void CKeybindManager::moveWindowOrGroup(std::string args) {
char arg = args[0]; 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)) { if (!isDirection(args)) {
Debug::log(ERR, "Cannot move into group in direction %c, unsupported direction. Supported: l,r,u/t,d/b", arg); 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; const auto PWINDOW = g_pCompositor->m_pLastWindow;
if (!PWINDOW || PWINDOW->m_bIsFullscreen) if (!PWINDOW || PWINDOW->m_bIsFullscreen)
return; return;
const auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(PWINDOW, arg);
const auto ISWINDOWGROUP = PWINDOW->m_sGroupData.pNextWindow; const bool ISWINDOWGROUP = PWINDOW->m_sGroupData.pNextWindow;
const auto ISWINDOWGROUPLOCKED = ISWINDOWGROUP && PWINDOW->getGroupHead()->m_sGroupData.locked; const bool ISWINDOWGROUPLOCKED = ISWINDOWGROUP && PWINDOW->getGroupHead()->m_sGroupData.locked;
const bool ISWINDOWGROUPSINGLE = ISWINDOWGROUP && PWINDOW->m_sGroupData.pNextWindow == PWINDOW;
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;
// note: PWINDOWINDIR is not null implies !PWINDOW->m_bIsFloating // note: PWINDOWINDIR is not null implies !PWINDOW->m_bIsFloating
if (ISWINDOWINDIRGROUP && !ISWINDOWINDIRGROUPLOCKED) { if (PWINDOWINDIR && PWINDOWINDIR->m_sGroupData.pNextWindow) { // target is group
if (ISWINDOWGROUPLOCKED && !*BIGNOREGROUPLOCK) { if (!*PIGNOREGROUPLOCK && (PWINDOWINDIR->getGroupHead()->m_sGroupData.locked || ISWINDOWGROUPLOCKED || PWINDOW->m_sGroupData.deny)) {
g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args); g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args);
g_pCompositor->warpCursorTo(PWINDOW->middle()); g_pCompositor->warpCursorTo(PWINDOW->middle());
} else } else
moveWindowIntoGroup(PWINDOW, PWINDOWINDIR); moveWindowIntoGroup(PWINDOW, PWINDOWINDIR);
} else if (ISWINDOWINDIRGROUPLOCKED) { } else if (PWINDOWINDIR) { // target is regular window
if (!*BIGNOREGROUPLOCK) { if ((!*PIGNOREGROUPLOCK && ISWINDOWGROUPLOCKED) || !ISWINDOWGROUP || (ISWINDOWGROUPSINGLE && PWINDOW->m_eGroupRules & GROUP_SET_ALWAYS)) {
g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args); g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args);
g_pCompositor->warpCursorTo(PWINDOW->middle()); g_pCompositor->warpCursorTo(PWINDOW->middle());
} else } else
moveWindowIntoGroup(PWINDOW, PWINDOWINDIR);
} else if (PWINDOWINDIR) {
if (ISWINDOWGROUP && (*BIGNOREGROUPLOCK || !ISWINDOWGROUPLOCKED))
moveWindowOutOfGroup(PWINDOW, args); moveWindowOutOfGroup(PWINDOW, args);
else { } else if ((*PIGNOREGROUPLOCK || !ISWINDOWGROUPLOCKED) && ISWINDOWGROUP) // no target window
g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args);
g_pCompositor->warpCursorTo(PWINDOW->middle());
}
} else if (ISWINDOWGROUP && (*BIGNOREGROUPLOCK || !ISWINDOWGROUPLOCKED)) {
moveWindowOutOfGroup(PWINDOW, args); moveWindowOutOfGroup(PWINDOW, args);
}
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
} }
void CKeybindManager::setIgnoreGroupLock(std::string args) { 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)}); 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) { void CKeybindManager::global(std::string args) {
const auto APPID = args.substr(0, args.find_first_of(':')); const auto APPID = args.substr(0, args.find_first_of(':'));
const auto NAME = args.substr(args.find_first_of(':') + 1); const auto NAME = args.substr(args.find_first_of(':') + 1);

View file

@ -151,6 +151,7 @@ class CKeybindManager {
static void moveGroupWindow(std::string); static void moveGroupWindow(std::string);
static void moveWindowOrGroup(std::string); static void moveWindowOrGroup(std::string);
static void setIgnoreGroupLock(std::string); static void setIgnoreGroupLock(std::string);
static void denyWindowFromGroup(std::string);
static void global(std::string); static void global(std::string);
friend class CCompositor; friend class CCompositor;