mirror of
https://github.com/hyprwm/Hyprland
synced 2024-12-23 00:49:48 +01:00
Add "next on monitor or empty" workspace parameter (#2198)
* Add "next on monitor or empty" workspace parameter Implements the following workspace parameter: r+x/r-x (i.e. r+1): Behaves similar to the "m" parameter, but can also select empty workspaces and it doesn't wrap around * Improve code comments * Implementation V2 for 'r' workspace param * Rebase to upstream Should fix CI * Always set outName * Include named workspaces Currently only considers open/active named workspaces
This commit is contained in:
parent
a31dceb2c6
commit
826dc61e5c
3 changed files with 140 additions and 2 deletions
|
@ -2026,6 +2026,10 @@ std::string CConfigManager::getBoundMonitorStringForWS(const std::string& wsname
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::deque<SWorkspaceRule>& CConfigManager::getAllWorkspaceRules() {
|
||||||
|
return m_dWorkspaceRules;
|
||||||
|
}
|
||||||
|
|
||||||
void CConfigManager::addExecRule(const SExecRequestedRule& rule) {
|
void CConfigManager::addExecRule(const SExecRequestedRule& rule) {
|
||||||
execRequestedRules.push_back(rule);
|
execRequestedRules.push_back(rule);
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,6 +180,7 @@ class CConfigManager {
|
||||||
|
|
||||||
CMonitor* getBoundMonitorForWS(const std::string&);
|
CMonitor* getBoundMonitorForWS(const std::string&);
|
||||||
std::string getBoundMonitorStringForWS(const std::string&);
|
std::string getBoundMonitorStringForWS(const std::string&);
|
||||||
|
const std::deque<SWorkspaceRule>& getAllWorkspaceRules();
|
||||||
|
|
||||||
std::vector<SWindowRule> getMatchingRules(CWindow*);
|
std::vector<SWindowRule> getMatchingRules(CWindow*);
|
||||||
std::vector<SLayerRule> getMatchingRules(SLayerSurface*);
|
std::vector<SLayerRule> getMatchingRules(SLayerSurface*);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "../defines.hpp"
|
#include "../defines.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "../Compositor.hpp"
|
#include "../Compositor.hpp"
|
||||||
|
#include <set>
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
@ -305,7 +306,140 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||||
outName = PLASTWORKSPACE->m_szName;
|
outName = PLASTWORKSPACE->m_szName;
|
||||||
return PLASTWORKSPACE->m_iID;
|
return PLASTWORKSPACE->m_iID;
|
||||||
} else {
|
} else {
|
||||||
if ((in[0] == 'm' || in[0] == 'e') && (in[1] == '-' || in[1] == '+') && isNumber(in.substr(2))) {
|
if (in[0] == 'r' && (in[1] == '-' || in[1] == '+') && isNumber(in.substr(2))) {
|
||||||
|
if (!g_pCompositor->m_pLastMonitor) {
|
||||||
|
Debug::log(ERR, "Relative monitor workspace on monitor null!");
|
||||||
|
result = INT_MAX;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = (int)getPlusMinusKeywordResult(in.substr(1), 0);
|
||||||
|
|
||||||
|
int remains = (int)result;
|
||||||
|
|
||||||
|
std::set<int> invalidWSes;
|
||||||
|
|
||||||
|
// Collect all the workspaces we can't jump to.
|
||||||
|
for (auto& ws : g_pCompositor->m_vWorkspaces) {
|
||||||
|
if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID)) {
|
||||||
|
// Can't jump to this workspace
|
||||||
|
invalidWSes.insert(ws->m_iID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto& rule : g_pConfigManager->getAllWorkspaceRules()) {
|
||||||
|
const auto PMONITOR = g_pCompositor->getMonitorFromName(rule.monitor);
|
||||||
|
if (!PMONITOR || PMONITOR->ID == g_pCompositor->m_pLastMonitor->ID) {
|
||||||
|
// Can't be invalid
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// WS is bound to another monitor, can't jump to this
|
||||||
|
invalidWSes.insert(rule.workspaceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare all named workspaces in case when we need them
|
||||||
|
std::vector<int> namedWSes;
|
||||||
|
for (auto& ws : g_pCompositor->m_vWorkspaces) {
|
||||||
|
if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID) || ws->m_iID >= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
namedWSes.push_back(ws->m_iID);
|
||||||
|
}
|
||||||
|
std::sort(namedWSes.begin(), namedWSes.end());
|
||||||
|
|
||||||
|
// Just take a blind guess at where we'll probably end up
|
||||||
|
int predictedWSID = g_pCompositor->m_pLastMonitor->activeWorkspace + remains;
|
||||||
|
int remainingWSes = 0;
|
||||||
|
char walkDir = in[1];
|
||||||
|
|
||||||
|
// sanitize. 0 means invalid oob in -
|
||||||
|
predictedWSID = std::max(predictedWSID, 0);
|
||||||
|
|
||||||
|
// Count how many invalidWSes are in between (how bad the prediction was)
|
||||||
|
int beginID = in[1] == '+' ? g_pCompositor->m_pLastMonitor->activeWorkspace + 1 : predictedWSID;
|
||||||
|
int endID = in[1] == '+' ? predictedWSID : g_pCompositor->m_pLastMonitor->activeWorkspace;
|
||||||
|
auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >=
|
||||||
|
for (auto it = begin; *it <= endID && it != invalidWSes.end(); it++) {
|
||||||
|
remainingWSes++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle named workspaces. They are treated like always before other workspaces
|
||||||
|
if (g_pCompositor->m_pLastMonitor->activeWorkspace < 0) {
|
||||||
|
// Behaviour similar to 'm'
|
||||||
|
// Find current
|
||||||
|
int currentItem = -1;
|
||||||
|
for (size_t i = 0; i < namedWSes.size(); i++) {
|
||||||
|
if (namedWSes[i] == g_pCompositor->m_pLastMonitor->activeWorkspace) {
|
||||||
|
currentItem = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentItem += remains;
|
||||||
|
currentItem = std::max(currentItem, 0);
|
||||||
|
if (currentItem >= (int)namedWSes.size()) {
|
||||||
|
// At the seam between namedWSes and normal WSes. Behave like r+[diff] at imaginary ws 0
|
||||||
|
int diff = currentItem - (namedWSes.size() - 1);
|
||||||
|
predictedWSID = diff;
|
||||||
|
int beginID = 1;
|
||||||
|
int endID = predictedWSID;
|
||||||
|
auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >=
|
||||||
|
for (auto it = begin; *it <= endID && it != invalidWSes.end(); it++) {
|
||||||
|
remainingWSes++;
|
||||||
|
}
|
||||||
|
walkDir = '+';
|
||||||
|
} else {
|
||||||
|
// We found our final ws.
|
||||||
|
remainingWSes = 0;
|
||||||
|
predictedWSID = namedWSes[currentItem];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go in the search direction for remainingWSes
|
||||||
|
// The performance impact is directly proportional to the number of open and bound workspaces
|
||||||
|
int finalWSID = predictedWSID;
|
||||||
|
if (walkDir == '-') {
|
||||||
|
int beginID = finalWSID;
|
||||||
|
int curID = finalWSID;
|
||||||
|
while (--curID > 0 && remainingWSes > 0) {
|
||||||
|
if (invalidWSes.find(curID) == invalidWSes.end()) {
|
||||||
|
remainingWSes--;
|
||||||
|
}
|
||||||
|
finalWSID = curID;
|
||||||
|
}
|
||||||
|
if (finalWSID <= 0 || invalidWSes.find(finalWSID) != invalidWSes.end()) {
|
||||||
|
if (namedWSes.size()) {
|
||||||
|
// Go to the named workspaces
|
||||||
|
// Need remainingWSes more
|
||||||
|
int namedWSIdx = namedWSes.size() - remainingWSes;
|
||||||
|
// Sanitze
|
||||||
|
namedWSIdx = std::clamp(namedWSIdx, 0, (int)namedWSes.size() - 1);
|
||||||
|
finalWSID = namedWSes[namedWSIdx];
|
||||||
|
} else {
|
||||||
|
// Couldn't find valid workspace in negative direction, search last first one back up positive direction
|
||||||
|
walkDir = '+';
|
||||||
|
// We know, that everything less than beginID is invalid, so don't bother with that
|
||||||
|
finalWSID = beginID;
|
||||||
|
remainingWSes = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (walkDir == '+') {
|
||||||
|
int curID = finalWSID;
|
||||||
|
while (++curID < INT32_MAX && remainingWSes > 0) {
|
||||||
|
if (invalidWSes.find(curID) == invalidWSes.end()) {
|
||||||
|
remainingWSes--;
|
||||||
|
}
|
||||||
|
finalWSID = curID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = finalWSID;
|
||||||
|
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(result);
|
||||||
|
if (PWORKSPACE)
|
||||||
|
outName = g_pCompositor->getWorkspaceByID(result)->m_szName;
|
||||||
|
else
|
||||||
|
outName = std::to_string(finalWSID);
|
||||||
|
|
||||||
|
} else if ((in[0] == 'm' || in[0] == 'e') && (in[1] == '-' || in[1] == '+') && isNumber(in.substr(2))) {
|
||||||
bool onAllMonitors = in[0] == 'e';
|
bool onAllMonitors = in[0] == 'e';
|
||||||
|
|
||||||
if (!g_pCompositor->m_pLastMonitor) {
|
if (!g_pCompositor->m_pLastMonitor) {
|
||||||
|
@ -354,7 +488,6 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||||
|
|
||||||
result = validWSes[currentItem];
|
result = validWSes[currentItem];
|
||||||
outName = g_pCompositor->getWorkspaceByID(validWSes[currentItem])->m_szName;
|
outName = g_pCompositor->getWorkspaceByID(validWSes[currentItem])->m_szName;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (in[0] == '+' || in[0] == '-') {
|
if (in[0] == '+' || in[0] == '-') {
|
||||||
if (g_pCompositor->m_pLastMonitor)
|
if (g_pCompositor->m_pLastMonitor)
|
||||||
|
|
Loading…
Reference in a new issue