mirror of
https://github.com/hyprwm/Hyprland
synced 2024-12-23 05:49:48 +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;
|
||||
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++;
|
||||
}
|
||||
|
||||
|
|
|
@ -149,7 +149,7 @@ class CCompositor {
|
|||
CWorkspace* getWorkspaceByString(const std::string&);
|
||||
void sanityCheckWorkspaces();
|
||||
void updateWorkspaceWindowDecos(const int&);
|
||||
int getWindowsOnWorkspace(const int&);
|
||||
int getWindowsOnWorkspace(const int& id, std::optional<bool> onlyTiled = {});
|
||||
CWindow* getUrgentWindow();
|
||||
bool hasUrgentWindowOnWorkspace(const int&);
|
||||
CWindow* getFirstWindowOnWorkspace(const int&);
|
||||
|
|
|
@ -175,13 +175,13 @@ struct SWindowRule {
|
|||
std::string szClass;
|
||||
std::string szInitialTitle;
|
||||
std::string szInitialClass;
|
||||
int bX11 = -1; // -1 means "ANY"
|
||||
int bFloating = -1;
|
||||
int bFullscreen = -1;
|
||||
int bPinned = -1;
|
||||
int bFocus = -1;
|
||||
int iOnWorkspace = -1;
|
||||
std::string szWorkspace = ""; // empty means any
|
||||
int bX11 = -1; // -1 means "ANY"
|
||||
int bFloating = -1;
|
||||
int bFullscreen = -1;
|
||||
int bPinned = -1;
|
||||
int bFocus = -1;
|
||||
std::string szOnWorkspace = ""; // empty means any
|
||||
std::string szWorkspace = ""; // empty means any
|
||||
};
|
||||
|
||||
class CWindow {
|
||||
|
|
|
@ -937,13 +937,7 @@ SMonitorRule CConfigManager::getMonitorRuleFor(const CMonitor& PMONITOR) {
|
|||
}
|
||||
|
||||
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 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 */
|
||||
});
|
||||
const auto IT = std::find_if(m_dWorkspaceRules.begin(), m_dWorkspaceRules.end(), [&](const auto& other) { return pWorkspace->matchesStaticSelector(other.workspaceString); });
|
||||
if (IT == m_dWorkspaceRules.end())
|
||||
return SWorkspaceRule{};
|
||||
return *IT;
|
||||
|
@ -1039,8 +1033,9 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow, bool
|
|||
continue;
|
||||
}
|
||||
|
||||
if (rule.iOnWorkspace != -1) {
|
||||
if (rule.iOnWorkspace != g_pCompositor->getWindowsOnWorkspace(pWindow->m_iWorkspaceID))
|
||||
if (!rule.szOnWorkspace.empty()) {
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
|
||||
if (!PWORKSPACE || !PWORKSPACE->matchesStaticSelector(rule.szOnWorkspace))
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1327,9 +1322,8 @@ std::string CConfigManager::getBoundMonitorStringForWS(const std::string& wsname
|
|||
for (auto& wr : m_dWorkspaceRules) {
|
||||
const auto WSNAME = wr.workspaceName.starts_with("name:") ? wr.workspaceName.substr(5) : wr.workspaceName;
|
||||
|
||||
if (WSNAME == wsname) {
|
||||
if (WSNAME == wsname)
|
||||
return wr.monitor;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
|
@ -2065,7 +2059,7 @@ std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string&
|
|||
rule.bFocus = extract(FOCUSPOS + 6) == "1" ? 1 : 0;
|
||||
|
||||
if (ONWORKSPACEPOS != std::string::npos)
|
||||
rule.iOnWorkspace = configStringToInt(extract(ONWORKSPACEPOS + 12));
|
||||
rule.szOnWorkspace = extract(ONWORKSPACEPOS + 12);
|
||||
|
||||
if (RULE == "unset") {
|
||||
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)
|
||||
return false;
|
||||
|
||||
if (rule.iOnWorkspace != -1 && rule.iOnWorkspace != other.iOnWorkspace)
|
||||
if (!rule.szOnWorkspace.empty() && rule.szOnWorkspace != other.szOnWorkspace)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -2165,21 +2159,21 @@ std::optional<std::string> CConfigManager::handleWorkspaceRules(const std::strin
|
|||
auto rules = value.substr(FIRST_DELIM + 1);
|
||||
SWorkspaceRule wsRule;
|
||||
wsRule.workspaceString = first_ident;
|
||||
if (id == WORKSPACE_INVALID) {
|
||||
// it could be the monitor. If so, second value MUST be
|
||||
// the workspace.
|
||||
const auto WORKSPACE_DELIM = value.find_first_of(',', FIRST_DELIM + 1);
|
||||
auto wsIdent = removeBeginEndSpacesTabs(value.substr(FIRST_DELIM + 1, (WORKSPACE_DELIM - FIRST_DELIM - 1)));
|
||||
id = getWorkspaceIDFromString(wsIdent, name);
|
||||
if (id == WORKSPACE_INVALID) {
|
||||
Debug::log(ERR, "Invalid workspace identifier found: {}", wsIdent);
|
||||
return "Invalid workspace identifier found: " + wsIdent;
|
||||
}
|
||||
wsRule.monitor = first_ident;
|
||||
wsRule.workspaceString = wsIdent;
|
||||
wsRule.isDefault = true; // backwards compat
|
||||
rules = value.substr(WORKSPACE_DELIM + 1);
|
||||
}
|
||||
// if (id == WORKSPACE_INVALID) {
|
||||
// // it could be the monitor. If so, second value MUST be
|
||||
// // the workspace.
|
||||
// const auto WORKSPACE_DELIM = value.find_first_of(',', FIRST_DELIM + 1);
|
||||
// auto wsIdent = removeBeginEndSpacesTabs(value.substr(FIRST_DELIM + 1, (WORKSPACE_DELIM - FIRST_DELIM - 1)));
|
||||
// id = getWorkspaceIDFromString(wsIdent, name);
|
||||
// if (id == WORKSPACE_INVALID) {
|
||||
// Debug::log(ERR, "Invalid workspace identifier found: {}", wsIdent);
|
||||
// return "Invalid workspace identifier found: " + wsIdent;
|
||||
// }
|
||||
// wsRule.monitor = first_ident;
|
||||
// wsRule.workspaceString = wsIdent;
|
||||
// wsRule.isDefault = true; // backwards compat
|
||||
// rules = value.substr(WORKSPACE_DELIM + 1);
|
||||
// }
|
||||
|
||||
const static std::string ruleOnCreatedEmtpy = "on-created-empty:";
|
||||
const static int ruleOnCreatedEmtpyLen = ruleOnCreatedEmtpy.length();
|
||||
|
|
|
@ -182,3 +182,205 @@ std::string CWorkspace::getConfigName() {
|
|||
|
||||
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);
|
||||
|
||||
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 = curr->m_sGroupData.pNextWindow;
|
||||
}
|
||||
|
||||
g_pCompositor->updateWorkspaceWindows(PWINDOW->m_iWorkspaceID);
|
||||
} else {
|
||||
PWINDOW->m_bIsFloating = !PWINDOW->m_bIsFloating;
|
||||
|
||||
PWINDOW->updateDynamicRules();
|
||||
g_pCompositor->updateWorkspaceWindows(PWINDOW->m_iWorkspaceID);
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(PWINDOW);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue