view: consolidate group flags and apply window rules (#13694)

* view: consolidate group flags and apply window rules

Replace individual boolean flags with a bitmask for group policies and ensure that window-specific group rules are correctly inherited when windows are initialized or added to a group.

* tests: add cases for locked groups and invade rule

Add tests to verify window grouping behavior, specifically checking that locked groups prevent merging by default and that the 'invade' group rule correctly overrides this lock policy.
This commit is contained in:
Kon 2026-03-17 14:10:53 +00:00 committed by Vaxry
parent b7285a301e
commit b6ada0c1dd
Signed by: vaxry
GPG key ID: 665806380871D640
3 changed files with 98 additions and 8 deletions

View file

@ -294,6 +294,89 @@ static bool test() {
Tests::killAllWindows();
EXPECT(Tests::windowCount(), 0);
// Tests for grouping/merging logic
NLog::log("{}Testing locked groups w/ invade", Colors::GREEN);
Tests::killAllWindows();
EXPECT(Tests::windowCount(), 0);
// Test normal, unlocked groups
{
auto winA = Tests::spawnKitty("unlocked");
if (!winA) {
NLog::log("{}Error: unlocked kitty did not spawn", Colors::RED);
return false;
}
OK(getFromSocket("/dispatch togglegroup"));
auto winB = Tests::spawnKitty("top");
if (!winB) {
NLog::log("{}Error: top kitty did not spawn", Colors::RED);
return false;
}
// Verify it DID merge into a group
{
auto str = getFromSocket("/clients");
EXPECT_COUNT_STRING(str, "at: 22,22", 2);
}
}
Tests::killAllWindows();
EXPECT(Tests::windowCount(), 0);
// Test locked groups
{
auto lockedWin = Tests::spawnKitty("locked");
if (!lockedWin) {
NLog::log("{}Error: locked kitty did not spawn", Colors::RED);
return false;
}
OK(getFromSocket("/dispatch togglegroup"));
OK(getFromSocket(std::format("/dispatch focuswindow pid:{}", lockedWin->pid())));
OK(getFromSocket("/dispatch lockactivegroup lock"));
auto winB = Tests::spawnKitty("top");
if (!winB) {
NLog::log("{}Error: top kitty did not spawn", Colors::RED);
return false;
}
// Verify it did NOT merge into the locked group
{
auto str = getFromSocket("/clients");
EXPECT_COUNT_STRING(str, "at: 22,22", 1);
}
}
Tests::killAllWindows();
EXPECT(Tests::windowCount(), 0);
// Test locked groups WITH invade rule
{
OK(getFromSocket("/keyword windowrule[locked-im]:match:class ^locked|invade$"));
OK(getFromSocket("/keyword windowrule[locked-im]:group set always lock invade"));
auto lockedWin = Tests::spawnKitty("locked");
if (!lockedWin) {
NLog::log("{}Error: locked kitty did not spawn", Colors::RED);
return false;
}
auto invadingWin = Tests::spawnKitty("invade");
if (!invadingWin) {
NLog::log("{}Error: invading kitty did not spawn", Colors::RED);
return false;
}
// Verify it DID merge into the locked group
auto str = getFromSocket("/clients");
EXPECT_COUNT_STRING(str, "at: 22,22", 2);
}
Tests::killAllWindows();
EXPECT(Tests::windowCount(), 0);
return !ret;
}

View file

@ -46,6 +46,7 @@ void CGroup::init() {
for (const auto& w : m_windows) {
RASSERT(!w->m_group, "CGroup: windows cannot contain grouped in init, this will explode");
w->m_group = m_self.lock();
m_groupPolicyFlags |= w->m_groupRules;
}
g_layoutManager->switchTargets(m_windows.at(0)->m_target, m_target);
@ -104,6 +105,7 @@ void CGroup::add(PHLWINDOW w) {
}
w->m_group = m_self.lock();
m_groupPolicyFlags |= w->m_groupRules;
w->m_target->setSpaceGhost(m_target->space());
w->m_target->setFloating(m_target->floating());
@ -296,19 +298,25 @@ size_t CGroup::size() const {
}
bool CGroup::locked() const {
return m_locked;
return m_groupPolicyFlags & GROUP_LOCK;
}
void CGroup::setLocked(bool x) {
m_locked = x;
if (x)
m_groupPolicyFlags |= GROUP_LOCK;
else
m_groupPolicyFlags &= ~GROUP_LOCK;
}
bool CGroup::denied() const {
return m_deny;
return m_groupPolicyFlags & GROUP_DENY;
}
void CGroup::setDenied(bool x) {
m_deny = x;
if (x)
m_groupPolicyFlags |= GROUP_DENY;
else
m_groupPolicyFlags &= ~GROUP_DENY;
}
void CGroup::updateWorkspace(PHLWORKSPACE ws) {

View file

@ -59,11 +59,10 @@ namespace Desktop::View {
std::vector<PHLWINDOWREF> m_windows;
bool m_locked = false;
bool m_deny = false;
size_t m_current = 0;
uint32_t m_groupPolicyFlags = 0;
};
std::vector<WP<CGroup>>& groups();
};
};