mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-26 07:05:58 +01:00
config/workspace: added workspace selectors
This commit is contained in:
parent
c32b2331d1
commit
05cd6d3df1
7 changed files with 239 additions and 39 deletions
|
@ -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++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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&);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue