config/workspace: added workspace selectors

This commit is contained in:
Vaxry 2024-03-19 20:56:20 +00:00
parent c32b2331d1
commit 05cd6d3df1
7 changed files with 239 additions and 39 deletions

View file

@ -1290,10 +1290,10 @@ void CCompositor::sanityCheckWorkspaces() {
} }
} }
int CCompositor::getWindowsOnWorkspace(const int& id) { int CCompositor::getWindowsOnWorkspace(const int& id, std::optional<bool> onlyTiled) {
int no = 0; int no = 0;
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID == id && w->m_bIsMapped) if (w->m_iWorkspaceID == id && w->m_bIsMapped && !(onlyTiled.has_value() && !w->m_bIsFloating != onlyTiled.value()))
no++; no++;
} }

View file

@ -149,7 +149,7 @@ class CCompositor {
CWorkspace* getWorkspaceByString(const std::string&); CWorkspace* getWorkspaceByString(const std::string&);
void sanityCheckWorkspaces(); void sanityCheckWorkspaces();
void updateWorkspaceWindowDecos(const int&); void updateWorkspaceWindowDecos(const int&);
int getWindowsOnWorkspace(const int&); int getWindowsOnWorkspace(const int& id, std::optional<bool> onlyTiled = {});
CWindow* getUrgentWindow(); CWindow* getUrgentWindow();
bool hasUrgentWindowOnWorkspace(const int&); bool hasUrgentWindowOnWorkspace(const int&);
CWindow* getFirstWindowOnWorkspace(const int&); CWindow* getFirstWindowOnWorkspace(const int&);

View file

@ -175,13 +175,13 @@ struct SWindowRule {
std::string szClass; std::string szClass;
std::string szInitialTitle; std::string szInitialTitle;
std::string szInitialClass; std::string szInitialClass;
int bX11 = -1; // -1 means "ANY" int bX11 = -1; // -1 means "ANY"
int bFloating = -1; int bFloating = -1;
int bFullscreen = -1; int bFullscreen = -1;
int bPinned = -1; int bPinned = -1;
int bFocus = -1; int bFocus = -1;
int iOnWorkspace = -1; std::string szOnWorkspace = ""; // empty means any
std::string szWorkspace = ""; // empty means any std::string szWorkspace = ""; // empty means any
}; };
class CWindow { class CWindow {

View file

@ -937,13 +937,7 @@ SMonitorRule CConfigManager::getMonitorRuleFor(const CMonitor& PMONITOR) {
} }
SWorkspaceRule CConfigManager::getWorkspaceRuleFor(CWorkspace* pWorkspace) { SWorkspaceRule CConfigManager::getWorkspaceRuleFor(CWorkspace* pWorkspace) {
const auto WORKSPACEIDSTR = std::to_string(pWorkspace->m_iID); const auto IT = std::find_if(m_dWorkspaceRules.begin(), m_dWorkspaceRules.end(), [&](const auto& other) { return pWorkspace->matchesStaticSelector(other.workspaceString); });
const auto IT = std::find_if(m_dWorkspaceRules.begin(), m_dWorkspaceRules.end(), [&](const auto& other) {
return other.workspaceName == pWorkspace->m_szName /* name matches */
|| (pWorkspace->m_bIsSpecialWorkspace && other.workspaceName.starts_with("special:") &&
other.workspaceName.substr(8) == pWorkspace->m_szName) /* special and special:name */
|| (pWorkspace->m_iID > 0 && WORKSPACEIDSTR == other.workspaceName); /* id matches and workspace is numerical */
});
if (IT == m_dWorkspaceRules.end()) if (IT == m_dWorkspaceRules.end())
return SWorkspaceRule{}; return SWorkspaceRule{};
return *IT; return *IT;
@ -1039,8 +1033,9 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow, bool
continue; continue;
} }
if (rule.iOnWorkspace != -1) { if (!rule.szOnWorkspace.empty()) {
if (rule.iOnWorkspace != g_pCompositor->getWindowsOnWorkspace(pWindow->m_iWorkspaceID)) const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
if (!PWORKSPACE || !PWORKSPACE->matchesStaticSelector(rule.szOnWorkspace))
continue; continue;
} }
@ -1327,9 +1322,8 @@ std::string CConfigManager::getBoundMonitorStringForWS(const std::string& wsname
for (auto& wr : m_dWorkspaceRules) { for (auto& wr : m_dWorkspaceRules) {
const auto WSNAME = wr.workspaceName.starts_with("name:") ? wr.workspaceName.substr(5) : wr.workspaceName; const auto WSNAME = wr.workspaceName.starts_with("name:") ? wr.workspaceName.substr(5) : wr.workspaceName;
if (WSNAME == wsname) { if (WSNAME == wsname)
return wr.monitor; return wr.monitor;
}
} }
return ""; return "";
@ -2065,7 +2059,7 @@ std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string&
rule.bFocus = extract(FOCUSPOS + 6) == "1" ? 1 : 0; rule.bFocus = extract(FOCUSPOS + 6) == "1" ? 1 : 0;
if (ONWORKSPACEPOS != std::string::npos) if (ONWORKSPACEPOS != std::string::npos)
rule.iOnWorkspace = configStringToInt(extract(ONWORKSPACEPOS + 12)); rule.szOnWorkspace = extract(ONWORKSPACEPOS + 12);
if (RULE == "unset") { if (RULE == "unset") {
std::erase_if(m_dWindowRules, [&](const SWindowRule& other) { std::erase_if(m_dWindowRules, [&](const SWindowRule& other) {
@ -2102,7 +2096,7 @@ std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string&
if (rule.bFocus != -1 && rule.bFocus != other.bFocus) if (rule.bFocus != -1 && rule.bFocus != other.bFocus)
return false; return false;
if (rule.iOnWorkspace != -1 && rule.iOnWorkspace != other.iOnWorkspace) if (!rule.szOnWorkspace.empty() && rule.szOnWorkspace != other.szOnWorkspace)
return false; return false;
return true; return true;
@ -2165,21 +2159,21 @@ std::optional<std::string> CConfigManager::handleWorkspaceRules(const std::strin
auto rules = value.substr(FIRST_DELIM + 1); auto rules = value.substr(FIRST_DELIM + 1);
SWorkspaceRule wsRule; SWorkspaceRule wsRule;
wsRule.workspaceString = first_ident; wsRule.workspaceString = first_ident;
if (id == WORKSPACE_INVALID) { // if (id == WORKSPACE_INVALID) {
// it could be the monitor. If so, second value MUST be // // it could be the monitor. If so, second value MUST be
// the workspace. // // the workspace.
const auto WORKSPACE_DELIM = value.find_first_of(',', FIRST_DELIM + 1); // const auto WORKSPACE_DELIM = value.find_first_of(',', FIRST_DELIM + 1);
auto wsIdent = removeBeginEndSpacesTabs(value.substr(FIRST_DELIM + 1, (WORKSPACE_DELIM - FIRST_DELIM - 1))); // auto wsIdent = removeBeginEndSpacesTabs(value.substr(FIRST_DELIM + 1, (WORKSPACE_DELIM - FIRST_DELIM - 1)));
id = getWorkspaceIDFromString(wsIdent, name); // id = getWorkspaceIDFromString(wsIdent, name);
if (id == WORKSPACE_INVALID) { // if (id == WORKSPACE_INVALID) {
Debug::log(ERR, "Invalid workspace identifier found: {}", wsIdent); // Debug::log(ERR, "Invalid workspace identifier found: {}", wsIdent);
return "Invalid workspace identifier found: " + wsIdent; // return "Invalid workspace identifier found: " + wsIdent;
} // }
wsRule.monitor = first_ident; // wsRule.monitor = first_ident;
wsRule.workspaceString = wsIdent; // wsRule.workspaceString = wsIdent;
wsRule.isDefault = true; // backwards compat // wsRule.isDefault = true; // backwards compat
rules = value.substr(WORKSPACE_DELIM + 1); // rules = value.substr(WORKSPACE_DELIM + 1);
} // }
const static std::string ruleOnCreatedEmtpy = "on-created-empty:"; const static std::string ruleOnCreatedEmtpy = "on-created-empty:";
const static int ruleOnCreatedEmtpyLen = ruleOnCreatedEmtpy.length(); const static int ruleOnCreatedEmtpyLen = ruleOnCreatedEmtpy.length();

View file

@ -182,3 +182,205 @@ std::string CWorkspace::getConfigName() {
return "name:" + m_szName; return "name:" + m_szName;
} }
bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
auto selector = removeBeginEndSpacesTabs(selector_);
if (selector.empty())
return true;
if (isNumber(selector)) {
std::string wsname = "";
int wsid = getWorkspaceIDFromString(selector, wsname);
if (wsid == WORKSPACE_INVALID)
return false;
return wsid == m_iID;
} else if (selector.starts_with("name:")) {
return m_szName == selector.substr(5);
} else {
// parse selector
for (size_t i = 0; i < selector.length(); ++i) {
const char& cur = selector[i];
if (std::isspace(cur))
continue;
// Allowed selectors:
// r - range: r[1-5]
// s - special: s[true]
// n - named: n[true] or n[s:string] or n[e:string]
// m - monitor: m[monitor_selector]
// w - windowCount: w[0-4] or w[1], optional flag t or f for tiled or floating, e.g. w[t0-1]
const auto NEXTSPACE = selector.find_first_of(' ', i);
std::string prop = selector.substr(i, NEXTSPACE == std::string::npos ? std::string::npos : NEXTSPACE - i);
i = NEXTSPACE;
if (cur == 'r') {
int from = 0, to = 0;
if (!prop.starts_with("r[") || !prop.ends_with("]")) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
prop = prop.substr(2, prop.length() - 3);
if (!prop.contains("-")) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
const auto DASHPOS = prop.find("-");
const auto LHS = prop.substr(0, DASHPOS), RHS = prop.substr(DASHPOS + 1);
if (!isNumber(LHS) || !isNumber(RHS)) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
try {
from = std::stoll(LHS);
to = std::stoll(RHS);
} catch (std::exception& e) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
if (to < from || to < 1 || from < 1) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
if (std::clamp(m_iID, from, to) != m_iID)
return false;
continue;
}
if (cur == 's') {
if (!prop.starts_with("s[") || !prop.ends_with("]")) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
prop = prop.substr(2, prop.length() - 3);
const auto SHOULDBESPECIAL = configStringToInt(prop);
if ((bool)SHOULDBESPECIAL != m_bIsSpecialWorkspace)
return false;
continue;
}
if (cur == 'm') {
if (!prop.starts_with("m[") || !prop.ends_with("]")) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
prop = prop.substr(2, prop.length() - 3);
const auto PMONITOR = g_pCompositor->getMonitorFromString(prop);
if (!(PMONITOR ? PMONITOR->ID == m_iMonitorID : false))
return false;
continue;
}
if (cur == 'n') {
if (!prop.starts_with("n[") || !prop.ends_with("]")) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
prop = prop.substr(2, prop.length() - 3);
if (prop.starts_with("s:"))
return m_szName.starts_with(prop.substr(2));
if (prop.starts_with("e:"))
return m_szName.ends_with(prop.substr(2));
const auto WANTSNAMED = configStringToInt(prop);
if (WANTSNAMED != (m_iID <= -1337))
return false;
continue;
}
if (cur == 'w') {
int from = 0, to = 0;
if (!prop.starts_with("w[") || !prop.ends_with("]")) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
prop = prop.substr(2, prop.length() - 3);
int wantsOnlyTiled = -1;
if (prop.starts_with("t")) {
wantsOnlyTiled = 1;
prop = prop.substr(1);
} else if (prop.starts_with("f")) {
wantsOnlyTiled = 0;
prop = prop.substr(1);
}
if (!prop.contains("-")) {
// try single
if (!isNumber(prop)) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
try {
from = std::stoll(prop);
} catch (std::exception& e) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
return g_pCompositor->getWindowsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled)) == from;
}
const auto DASHPOS = prop.find("-");
const auto LHS = prop.substr(0, DASHPOS), RHS = prop.substr(DASHPOS + 1);
if (!isNumber(LHS) || !isNumber(RHS)) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
try {
from = std::stoll(LHS);
to = std::stoll(RHS);
} catch (std::exception& e) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
if (to < from || to < 1 || from < 1) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
const auto WINDOWSONWORKSPACE = g_pCompositor->getWindowsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled));
if (std::clamp(WINDOWSONWORKSPACE, from, to) != WINDOWSONWORKSPACE)
return false;
continue;
}
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
return true;
}
UNREACHABLE();
return false;
}

View file

@ -64,4 +64,6 @@ class CWorkspace {
void rememberPrevWorkspace(const CWorkspace* prevWorkspace); void rememberPrevWorkspace(const CWorkspace* prevWorkspace);
std::string getConfigName(); std::string getConfigName();
bool matchesStaticSelector(const std::string& selector);
}; };

View file

@ -871,10 +871,12 @@ void toggleActiveFloatingCore(std::string args, std::optional<bool> floatState)
curr->updateSpecialRenderData(); curr->updateSpecialRenderData();
curr = curr->m_sGroupData.pNextWindow; curr = curr->m_sGroupData.pNextWindow;
} }
g_pCompositor->updateWorkspaceWindows(PWINDOW->m_iWorkspaceID);
} else { } else {
PWINDOW->m_bIsFloating = !PWINDOW->m_bIsFloating; PWINDOW->m_bIsFloating = !PWINDOW->m_bIsFloating;
PWINDOW->updateDynamicRules(); g_pCompositor->updateWorkspaceWindows(PWINDOW->m_iWorkspaceID);
g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(PWINDOW); g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(PWINDOW);
} }