mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-23 01:46:00 +01:00
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:
parent
2e1842b5ff
commit
1357b66091
9 changed files with 200 additions and 76 deletions
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue