mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-22 16:25:59 +01:00
config: add tag dispacther and window rule (#6211)
This commit is contained in:
parent
73b133d015
commit
ebf258788e
9 changed files with 190 additions and 51 deletions
|
@ -117,6 +117,7 @@ hyprctl [<OPTIONS>]... <ARGUMENTS>
|
||||||
| (movewindowpixel) "Move a selected window"
|
| (movewindowpixel) "Move a selected window"
|
||||||
| (cyclenext) "Focus the next window on a workspace"
|
| (cyclenext) "Focus the next window on a workspace"
|
||||||
| (swapnext) "Swap the focused window with the next window"
|
| (swapnext) "Swap the focused window with the next window"
|
||||||
|
| (tagwindow) "Apply a tag to the window"
|
||||||
| (focuswindow) "Focus the first window matching"
|
| (focuswindow) "Focus the first window matching"
|
||||||
| (focusmonitor) "Focus a monitor"
|
| (focusmonitor) "Focus a monitor"
|
||||||
| (splitratio) "Change the split ratio"
|
| (splitratio) "Change the split ratio"
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
#include <unordered_set>
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
|
||||||
extern "C" char** environ;
|
extern "C" char** environ;
|
||||||
|
@ -994,7 +995,7 @@ SMonitorRule CConfigManager::getMonitorRuleFor(const CMonitor& PMONITOR) {
|
||||||
Debug::log(WARN, "No rule found for {}, trying to use the first.", PMONITOR.szName);
|
Debug::log(WARN, "No rule found for {}, trying to use the first.", PMONITOR.szName);
|
||||||
|
|
||||||
for (auto& r : m_dMonitorRules) {
|
for (auto& r : m_dMonitorRules) {
|
||||||
if (r.name == "") {
|
if (r.name.empty()) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1080,12 +1081,17 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo
|
||||||
bool hasFloating = pWindow->m_bIsFloating;
|
bool hasFloating = pWindow->m_bIsFloating;
|
||||||
bool hasFullscreen = pWindow->m_bIsFullscreen;
|
bool hasFullscreen = pWindow->m_bIsFullscreen;
|
||||||
|
|
||||||
|
// local tags for dynamic tag rule match
|
||||||
|
auto tags = pWindow->m_tags;
|
||||||
|
|
||||||
for (auto& rule : m_dWindowRules) {
|
for (auto& rule : m_dWindowRules) {
|
||||||
// check if we have a matching rule
|
// check if we have a matching rule
|
||||||
if (!rule.v2) {
|
if (!rule.v2) {
|
||||||
try {
|
try {
|
||||||
|
if (rule.szValue.starts_with("tag:") && !tags.isTagged(rule.szValue.substr(4)))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (rule.szValue.starts_with("title:")) {
|
if (rule.szValue.starts_with("title:")) {
|
||||||
// we have a title rule.
|
|
||||||
std::regex RULECHECK(rule.szValue.substr(6));
|
std::regex RULECHECK(rule.szValue.substr(6));
|
||||||
|
|
||||||
if (!std::regex_search(title, RULECHECK))
|
if (!std::regex_search(title, RULECHECK))
|
||||||
|
@ -1102,28 +1108,31 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
if (rule.szClass != "") {
|
if (!rule.szTag.empty() && !tags.isTagged(rule.szTag))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!rule.szClass.empty()) {
|
||||||
std::regex RULECHECK(rule.szClass);
|
std::regex RULECHECK(rule.szClass);
|
||||||
|
|
||||||
if (!std::regex_search(appidclass, RULECHECK))
|
if (!std::regex_search(appidclass, RULECHECK))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rule.szTitle != "") {
|
if (!rule.szTitle.empty()) {
|
||||||
std::regex RULECHECK(rule.szTitle);
|
std::regex RULECHECK(rule.szTitle);
|
||||||
|
|
||||||
if (!std::regex_search(title, RULECHECK))
|
if (!std::regex_search(title, RULECHECK))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rule.szInitialTitle != "") {
|
if (!rule.szInitialTitle.empty()) {
|
||||||
std::regex RULECHECK(rule.szInitialTitle);
|
std::regex RULECHECK(rule.szInitialTitle);
|
||||||
|
|
||||||
if (!std::regex_search(pWindow->m_szInitialTitle, RULECHECK))
|
if (!std::regex_search(pWindow->m_szInitialTitle, RULECHECK))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rule.szInitialClass != "") {
|
if (!rule.szInitialClass.empty()) {
|
||||||
std::regex RULECHECK(rule.szInitialClass);
|
std::regex RULECHECK(rule.szInitialClass);
|
||||||
|
|
||||||
if (!std::regex_search(pWindow->m_szInitialClass, RULECHECK))
|
if (!std::regex_search(pWindow->m_szInitialClass, RULECHECK))
|
||||||
|
@ -1192,6 +1201,13 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo
|
||||||
|
|
||||||
returns.push_back(rule);
|
returns.push_back(rule);
|
||||||
|
|
||||||
|
// apply tag with local tags
|
||||||
|
if (rule.szRule.starts_with("tag")) {
|
||||||
|
CVarList vars{rule.szRule, 0, 's', true};
|
||||||
|
if (vars.size() == 2 && vars[0] == "tag")
|
||||||
|
tags.applyTag(vars[1], true);
|
||||||
|
}
|
||||||
|
|
||||||
if (dynamic)
|
if (dynamic)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -1696,7 +1712,7 @@ std::optional<std::string> CConfigManager::handleMonitor(const std::string& comm
|
||||||
newrule.resolution = Vector2D(-1, -2);
|
newrule.resolution = Vector2D(-1, -2);
|
||||||
} else if (parseModeLine(ARGS[1], newrule.drmMode)) {
|
} else if (parseModeLine(ARGS[1], newrule.drmMode)) {
|
||||||
newrule.resolution = Vector2D(newrule.drmMode.hdisplay, newrule.drmMode.vdisplay);
|
newrule.resolution = Vector2D(newrule.drmMode.hdisplay, newrule.drmMode.vdisplay);
|
||||||
newrule.refreshRate = newrule.drmMode.vrefresh / 1000;
|
newrule.refreshRate = float(newrule.drmMode.vrefresh) / 1000;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (!ARGS[1].contains("x")) {
|
if (!ARGS[1].contains("x")) {
|
||||||
|
@ -2023,7 +2039,7 @@ std::optional<std::string> CConfigManager::handleBind(const std::string& command
|
||||||
if ((KEY != "") || multiKey) {
|
if ((KEY != "") || multiKey) {
|
||||||
SParsedKey parsedKey = parseKey(KEY);
|
SParsedKey parsedKey = parseKey(KEY);
|
||||||
|
|
||||||
if (parsedKey.catchAll && m_szCurrentSubmap == "") {
|
if (parsedKey.catchAll && m_szCurrentSubmap.empty()) {
|
||||||
Debug::log(ERR, "Catchall not allowed outside of submap!");
|
Debug::log(ERR, "Catchall not allowed outside of submap!");
|
||||||
return "Invalid catchall, catchall keybinds are only allowed in submaps.";
|
return "Invalid catchall, catchall keybinds are only allowed in submaps.";
|
||||||
}
|
}
|
||||||
|
@ -2048,18 +2064,24 @@ std::optional<std::string> CConfigManager::handleUnbind(const std::string& comma
|
||||||
}
|
}
|
||||||
|
|
||||||
bool windowRuleValid(const std::string& RULE) {
|
bool windowRuleValid(const std::string& RULE) {
|
||||||
return RULE == "float" || RULE == "tile" || RULE.starts_with("opacity") || RULE.starts_with("move") || RULE.starts_with("size") || RULE.starts_with("minsize") ||
|
static const auto rules = std::unordered_set<std::string>{
|
||||||
RULE.starts_with("maxsize") || RULE.starts_with("pseudo") || RULE.starts_with("monitor") || RULE.starts_with("idleinhibit") || RULE == "nofocus" || RULE == "noblur" ||
|
"dimaround", "fakefullscreen", "float", "focusonactivate", "forceinput", "forcergbx", "fullscreen", "immediate",
|
||||||
RULE == "noshadow" || RULE == "nodim" || RULE == "noborder" || RULE == "opaque" || RULE == "forceinput" || RULE == "fullscreen" || RULE == "fakefullscreen" ||
|
"keepaspectratio", "maximize", "nearestneighbor", "noanim", "noblur", "noborder", "nodim", "nofocus",
|
||||||
RULE == "nomaxsize" || RULE == "pin" || RULE == "noanim" || RULE == "dimaround" || RULE == "windowdance" || RULE == "maximize" || RULE == "keepaspectratio" ||
|
"noinitialfocus", "nomaxsize", "noshadow", "opaque", "pin", "stayfocused", "tile", "windowdance",
|
||||||
RULE == "focusonactivate" || RULE.starts_with("animation") || RULE.starts_with("rounding") || RULE.starts_with("workspace") || RULE.starts_with("bordercolor") ||
|
};
|
||||||
RULE == "forcergbx" || RULE == "noinitialfocus" || RULE == "stayfocused" || RULE.starts_with("bordersize") || RULE.starts_with("xray") || RULE.starts_with("center") ||
|
static const auto rulesPrefix = std::vector<std::string>{
|
||||||
RULE.starts_with("group") || RULE == "immediate" || RULE == "nearestneighbor" || RULE.starts_with("suppressevent") || RULE.starts_with("plugin:");
|
"animation", "bordercolor", "bordersize", "center", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move",
|
||||||
|
"opacity", "plugin:", "pseudo", "rounding", "size", "suppressevent", "tag", "workspace", "xray",
|
||||||
|
};
|
||||||
|
|
||||||
|
return rules.contains(RULE) || std::any_of(rulesPrefix.begin(), rulesPrefix.end(), [&RULE](auto prefix) { return RULE.starts_with(prefix); });
|
||||||
}
|
}
|
||||||
|
|
||||||
bool layerRuleValid(const std::string& RULE) {
|
bool layerRuleValid(const std::string& RULE) {
|
||||||
return RULE == "noanim" || RULE == "blur" || RULE == "blurpopups" || RULE.starts_with("ignorealpha") || RULE.starts_with("ignorezero") || RULE == "dimaround" ||
|
static const auto rules = std::unordered_set<std::string>{"noanim", "blur", "blurpopups", "dimaround"};
|
||||||
RULE.starts_with("xray") || RULE.starts_with("animation");
|
static const auto rulesPrefix = std::vector<std::string>{"ignorealpha", "ignorezero", "xray", "animation"};
|
||||||
|
|
||||||
|
return rules.contains(RULE) || std::any_of(rulesPrefix.begin(), rulesPrefix.end(), [&RULE](auto prefix) { return RULE.starts_with(prefix); });
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> CConfigManager::handleWindowRule(const std::string& command, const std::string& value) {
|
std::optional<std::string> CConfigManager::handleWindowRule(const std::string& command, const std::string& value) {
|
||||||
|
@ -2067,7 +2089,7 @@ std::optional<std::string> CConfigManager::handleWindowRule(const std::string& c
|
||||||
const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1));
|
const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1));
|
||||||
|
|
||||||
// check rule and value
|
// check rule and value
|
||||||
if (RULE == "" || VALUE == "")
|
if (RULE.empty() || VALUE.empty())
|
||||||
return "empty rule?";
|
return "empty rule?";
|
||||||
|
|
||||||
if (RULE == "unset") {
|
if (RULE == "unset") {
|
||||||
|
@ -2094,7 +2116,7 @@ std::optional<std::string> CConfigManager::handleLayerRule(const std::string& co
|
||||||
const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1));
|
const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1));
|
||||||
|
|
||||||
// check rule and value
|
// check rule and value
|
||||||
if (RULE == "" || VALUE == "")
|
if (RULE.empty() || VALUE.empty())
|
||||||
return "empty rule?";
|
return "empty rule?";
|
||||||
|
|
||||||
if (RULE == "unset") {
|
if (RULE == "unset") {
|
||||||
|
@ -2132,6 +2154,7 @@ std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string&
|
||||||
rule.szRule = RULE;
|
rule.szRule = RULE;
|
||||||
rule.szValue = VALUE;
|
rule.szValue = VALUE;
|
||||||
|
|
||||||
|
const auto TAGPOS = VALUE.find("tag:");
|
||||||
const auto TITLEPOS = VALUE.find("title:");
|
const auto TITLEPOS = VALUE.find("title:");
|
||||||
const auto CLASSPOS = VALUE.find("class:");
|
const auto CLASSPOS = VALUE.find("class:");
|
||||||
const auto INITIALTITLEPOS = VALUE.find("initialTitle:");
|
const auto INITIALTITLEPOS = VALUE.find("initialTitle:");
|
||||||
|
@ -2154,9 +2177,10 @@ std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string&
|
||||||
currentPos = VALUE.find("workspace:", currentPos + 1);
|
currentPos = VALUE.find("workspace:", currentPos + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TITLEPOS == std::string::npos && CLASSPOS == std::string::npos && INITIALTITLEPOS == std::string::npos && INITIALCLASSPOS == std::string::npos &&
|
const auto checkPos = std::unordered_set{
|
||||||
X11POS == std::string::npos && FLOATPOS == std::string::npos && FULLSCREENPOS == std::string::npos && PINNEDPOS == std::string::npos && WORKSPACEPOS == std::string::npos &&
|
TAGPOS, TITLEPOS, CLASSPOS, INITIALTITLEPOS, INITIALCLASSPOS, X11POS, FLOATPOS, FULLSCREENPOS, PINNEDPOS, WORKSPACEPOS, FOCUSPOS, ONWORKSPACEPOS,
|
||||||
FOCUSPOS == std::string::npos && ONWORKSPACEPOS == std::string::npos) {
|
};
|
||||||
|
if (checkPos.size() == 1 && checkPos.contains(std::string::npos)) {
|
||||||
Debug::log(ERR, "Invalid rulev2 syntax: {}", VALUE);
|
Debug::log(ERR, "Invalid rulev2 syntax: {}", VALUE);
|
||||||
return "Invalid rulev2 syntax: " + VALUE;
|
return "Invalid rulev2 syntax: " + VALUE;
|
||||||
}
|
}
|
||||||
|
@ -2166,6 +2190,8 @@ std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string&
|
||||||
result = VALUE.substr(pos);
|
result = VALUE.substr(pos);
|
||||||
|
|
||||||
size_t min = 999999;
|
size_t min = 999999;
|
||||||
|
if (TAGPOS > pos && TAGPOS < min)
|
||||||
|
min = TAGPOS;
|
||||||
if (TITLEPOS > pos && TITLEPOS < min)
|
if (TITLEPOS > pos && TITLEPOS < min)
|
||||||
min = TITLEPOS;
|
min = TITLEPOS;
|
||||||
if (CLASSPOS > pos && CLASSPOS < min)
|
if (CLASSPOS > pos && CLASSPOS < min)
|
||||||
|
@ -2199,6 +2225,9 @@ std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string&
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (TAGPOS != std::string::npos)
|
||||||
|
rule.szTag = extract(TAGPOS + 4);
|
||||||
|
|
||||||
if (CLASSPOS != std::string::npos)
|
if (CLASSPOS != std::string::npos)
|
||||||
rule.szClass = extract(CLASSPOS + 6);
|
rule.szClass = extract(CLASSPOS + 6);
|
||||||
|
|
||||||
|
@ -2237,6 +2266,9 @@ std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string&
|
||||||
if (!other.v2) {
|
if (!other.v2) {
|
||||||
return other.szClass == rule.szClass && !rule.szClass.empty();
|
return other.szClass == rule.szClass && !rule.szClass.empty();
|
||||||
} else {
|
} else {
|
||||||
|
if (!rule.szTag.empty() && rule.szTag != other.szTag)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!rule.szClass.empty() && rule.szClass != other.szClass)
|
if (!rule.szClass.empty() && rule.szClass != other.szClass)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <typeindex>
|
#include <typeindex>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
#include "../config/ConfigDataValues.hpp"
|
#include "../config/ConfigDataValues.hpp"
|
||||||
#include "../config/ConfigValue.hpp"
|
#include "../config/ConfigValue.hpp"
|
||||||
|
@ -131,10 +132,9 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
result += std::format(
|
result += std::format(
|
||||||
"Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\tspecial "
|
"Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t"
|
||||||
"workspace: {} ({})\n\treserved: {} "
|
"special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t"
|
||||||
"{} {} {}\n\tscale: {:.2f}\n\ttransform: "
|
"dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n",
|
||||||
"{}\n\tfocused: {}\n\tdpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n",
|
|
||||||
m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription,
|
m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription,
|
||||||
(m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), m->activeWorkspaceID(),
|
(m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), m->activeWorkspaceID(),
|
||||||
(!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""),
|
(!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""),
|
||||||
|
@ -147,6 +147,16 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string getTagsData(PHLWINDOW w, eHyprCtlOutputFormat format) {
|
||||||
|
const auto tags = w->m_tags.getTags();
|
||||||
|
|
||||||
|
if (format == eHyprCtlOutputFormat::FORMAT_JSON)
|
||||||
|
return std::accumulate(tags.begin(), tags.end(), std::string(),
|
||||||
|
[](const std::string& a, const std::string& b) { return a.empty() ? std::format("\"{}\"", b) : std::format("{}, \"{}\"", a, b); });
|
||||||
|
else
|
||||||
|
return std::accumulate(tags.begin(), tags.end(), std::string(), [](const std::string& a, const std::string& b) { return a.empty() ? b : a + ", " + b; });
|
||||||
|
}
|
||||||
|
|
||||||
static std::string getGroupedData(PHLWINDOW w, eHyprCtlOutputFormat format) {
|
static std::string getGroupedData(PHLWINDOW w, eHyprCtlOutputFormat format) {
|
||||||
const bool isJson = format == eHyprCtlOutputFormat::FORMAT_JSON;
|
const bool isJson = format == eHyprCtlOutputFormat::FORMAT_JSON;
|
||||||
if (w->m_sGroupData.pNextWindow.expired())
|
if (w->m_sGroupData.pNextWindow.expired())
|
||||||
|
@ -205,6 +215,7 @@ static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) {
|
||||||
"fullscreenMode": {},
|
"fullscreenMode": {},
|
||||||
"fakeFullscreen": {},
|
"fakeFullscreen": {},
|
||||||
"grouped": [{}],
|
"grouped": [{}],
|
||||||
|
"tags": [{}],
|
||||||
"swallowing": "0x{:x}",
|
"swallowing": "0x{:x}",
|
||||||
"focusHistoryID": {}
|
"focusHistoryID": {}
|
||||||
}},)#",
|
}},)#",
|
||||||
|
@ -214,18 +225,18 @@ static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) {
|
||||||
escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass), escapeJSONStrings(w->m_szInitialTitle), w->getPID(),
|
escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass), escapeJSONStrings(w->m_szInitialTitle), w->getPID(),
|
||||||
((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), (w->m_bIsFullscreen ? "true" : "false"),
|
((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), (w->m_bIsFullscreen ? "true" : "false"),
|
||||||
(w->m_bIsFullscreen ? (w->m_pWorkspace ? (int)w->m_pWorkspace->m_efFullscreenMode : 0) : 0), w->m_bFakeFullscreenState ? "true" : "false", getGroupedData(w, format),
|
(w->m_bIsFullscreen ? (w->m_pWorkspace ? (int)w->m_pWorkspace->m_efFullscreenMode : 0) : 0), w->m_bFakeFullscreenState ? "true" : "false", getGroupedData(w, format),
|
||||||
(uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w));
|
getTagsData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w));
|
||||||
} else {
|
} else {
|
||||||
return std::format("Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: "
|
return std::format("Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: "
|
||||||
"{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: "
|
"{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: "
|
||||||
"{}\n\txwayland: {}\n\tpinned: "
|
"{}\n\txwayland: {}\n\tpinned: "
|
||||||
"{}\n\tfullscreen: {}\n\tfullscreenmode: {}\n\tfakefullscreen: {}\n\tgrouped: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n",
|
"{}\n\tfullscreen: {}\n\tfullscreenmode: {}\n\tfakefullscreen: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n",
|
||||||
(uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y,
|
(uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y,
|
||||||
(int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID,
|
(int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID,
|
||||||
(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), (int)w->m_bIsFloating, (int64_t)w->m_iMonitorID, w->m_szClass, w->m_szTitle, w->m_szInitialClass,
|
(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), (int)w->m_bIsFloating, (int64_t)w->m_iMonitorID, w->m_szClass, w->m_szTitle, w->m_szInitialClass,
|
||||||
w->m_szInitialTitle, w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen,
|
w->m_szInitialTitle, w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen,
|
||||||
(w->m_bIsFullscreen ? (w->m_pWorkspace ? w->m_pWorkspace->m_efFullscreenMode : 0) : 0), (int)w->m_bFakeFullscreenState, getGroupedData(w, format),
|
(w->m_bIsFullscreen ? (w->m_pWorkspace ? w->m_pWorkspace->m_efFullscreenMode : 0) : 0), (int)w->m_bFakeFullscreenState, getGroupedData(w, format),
|
||||||
(uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w));
|
getTagsData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
|
#include <any>
|
||||||
|
#include <string_view>
|
||||||
|
#include <algorithm>
|
||||||
#include "Window.hpp"
|
#include "Window.hpp"
|
||||||
#include "../Compositor.hpp"
|
#include "../Compositor.hpp"
|
||||||
#include "../render/decorations/CHyprDropShadowDecoration.hpp"
|
#include "../render/decorations/CHyprDropShadowDecoration.hpp"
|
||||||
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
|
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
|
||||||
#include "../render/decorations/CHyprBorderDecoration.hpp"
|
#include "../render/decorations/CHyprBorderDecoration.hpp"
|
||||||
#include "../config/ConfigValue.hpp"
|
#include "../config/ConfigValue.hpp"
|
||||||
#include <any>
|
|
||||||
#include "../managers/TokenManager.hpp"
|
#include "../managers/TokenManager.hpp"
|
||||||
#include "../protocols/XDGShell.hpp"
|
#include "../protocols/XDGShell.hpp"
|
||||||
#include "../xwayland/XWayland.hpp"
|
#include "../xwayland/XWayland.hpp"
|
||||||
|
@ -619,6 +621,13 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
|
||||||
m_sAdditionalConfigData.forceTearing = true;
|
m_sAdditionalConfigData.forceTearing = true;
|
||||||
} else if (r.szRule == "nearestneighbor") {
|
} else if (r.szRule == "nearestneighbor") {
|
||||||
m_sAdditionalConfigData.nearestNeighbor = true;
|
m_sAdditionalConfigData.nearestNeighbor = true;
|
||||||
|
} else if (r.szRule.starts_with("tag")) {
|
||||||
|
CVarList vars{r.szRule, 0, 's', true};
|
||||||
|
|
||||||
|
if (vars.size() == 2 && vars[0] == "tag")
|
||||||
|
m_tags.applyTag(vars[1], true);
|
||||||
|
else
|
||||||
|
Debug::log(ERR, "Tag rule invalid: {}", r.szRule);
|
||||||
} else if (r.szRule.starts_with("rounding")) {
|
} else if (r.szRule.starts_with("rounding")) {
|
||||||
try {
|
try {
|
||||||
m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
|
m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
|
||||||
|
@ -800,6 +809,8 @@ void CWindow::updateDynamicRules() {
|
||||||
m_sAdditionalConfigData.nearestNeighbor = false;
|
m_sAdditionalConfigData.nearestNeighbor = false;
|
||||||
m_eIdleInhibitMode = IDLEINHIBIT_NONE;
|
m_eIdleInhibitMode = IDLEINHIBIT_NONE;
|
||||||
|
|
||||||
|
m_tags.removeDynamicTags();
|
||||||
|
|
||||||
m_vMatchedRules = g_pConfigManager->getMatchingRules(m_pSelf.lock());
|
m_vMatchedRules = g_pConfigManager->getMatchingRules(m_pSelf.lock());
|
||||||
for (auto& r : m_vMatchedRules) {
|
for (auto& r : m_vMatchedRules) {
|
||||||
applyDynamicRule(r);
|
applyDynamicRule(r);
|
||||||
|
@ -1370,6 +1381,7 @@ void CWindow::onUpdateState() {
|
||||||
|
|
||||||
void CWindow::onUpdateMeta() {
|
void CWindow::onUpdateMeta() {
|
||||||
const auto NEWTITLE = fetchTitle();
|
const auto NEWTITLE = fetchTitle();
|
||||||
|
bool doUpdate = false;
|
||||||
|
|
||||||
if (m_szTitle != NEWTITLE) {
|
if (m_szTitle != NEWTITLE) {
|
||||||
m_szTitle = NEWTITLE;
|
m_szTitle = NEWTITLE;
|
||||||
|
@ -1382,11 +1394,8 @@ void CWindow::onUpdateMeta() {
|
||||||
EMIT_HOOK_EVENT("activeWindow", m_pSelf.lock());
|
EMIT_HOOK_EVENT("activeWindow", m_pSelf.lock());
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDynamicRules();
|
|
||||||
g_pCompositor->updateWindowAnimatedDecorationValues(m_pSelf.lock());
|
|
||||||
updateToplevel();
|
|
||||||
|
|
||||||
Debug::log(LOG, "Window {:x} set title to {}", (uintptr_t)this, m_szTitle);
|
Debug::log(LOG, "Window {:x} set title to {}", (uintptr_t)this, m_szTitle);
|
||||||
|
doUpdate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto NEWCLASS = fetchClass();
|
const auto NEWCLASS = fetchClass();
|
||||||
|
@ -1399,11 +1408,14 @@ void CWindow::onUpdateMeta() {
|
||||||
EMIT_HOOK_EVENT("activeWindow", m_pSelf.lock());
|
EMIT_HOOK_EVENT("activeWindow", m_pSelf.lock());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Debug::log(LOG, "Window {:x} set class to {}", (uintptr_t)this, m_szClass);
|
||||||
|
doUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doUpdate) {
|
||||||
updateDynamicRules();
|
updateDynamicRules();
|
||||||
g_pCompositor->updateWindowAnimatedDecorationValues(m_pSelf.lock());
|
g_pCompositor->updateWindowAnimatedDecorationValues(m_pSelf.lock());
|
||||||
updateToplevel();
|
updateToplevel();
|
||||||
|
|
||||||
Debug::log(LOG, "Window {:x} set class to {}", (uintptr_t)this, m_szClass);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,21 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../defines.hpp"
|
|
||||||
#include "Subsurface.hpp"
|
|
||||||
#include "../helpers/AnimatedVariable.hpp"
|
|
||||||
#include "../render/decorations/IHyprWindowDecoration.hpp"
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "../config/ConfigDataValues.hpp"
|
#include "../config/ConfigDataValues.hpp"
|
||||||
|
#include "../defines.hpp"
|
||||||
|
#include "../helpers/AnimatedVariable.hpp"
|
||||||
#include "../helpers/Vector2D.hpp"
|
#include "../helpers/Vector2D.hpp"
|
||||||
#include "WLSurface.hpp"
|
#include "../helpers/signal/Signal.hpp"
|
||||||
#include "Popup.hpp"
|
#include "../helpers/TagKeeper.hpp"
|
||||||
#include "../macros.hpp"
|
#include "../macros.hpp"
|
||||||
#include "../managers/XWaylandManager.hpp"
|
#include "../managers/XWaylandManager.hpp"
|
||||||
|
#include "../render/decorations/IHyprWindowDecoration.hpp"
|
||||||
#include "DesktopTypes.hpp"
|
#include "DesktopTypes.hpp"
|
||||||
#include "../helpers/signal/Signal.hpp"
|
#include "Popup.hpp"
|
||||||
|
#include "Subsurface.hpp"
|
||||||
|
#include "WLSurface.hpp"
|
||||||
|
|
||||||
class CXDGSurfaceResource;
|
class CXDGSurfaceResource;
|
||||||
class CXWaylandSurface;
|
class CXWaylandSurface;
|
||||||
|
@ -183,6 +186,7 @@ struct SWindowRule {
|
||||||
std::string szClass;
|
std::string szClass;
|
||||||
std::string szInitialTitle;
|
std::string szInitialTitle;
|
||||||
std::string szInitialClass;
|
std::string szInitialClass;
|
||||||
|
std::string szTag;
|
||||||
int bX11 = -1; // -1 means "ANY"
|
int bX11 = -1; // -1 means "ANY"
|
||||||
int bFloating = -1;
|
int bFloating = -1;
|
||||||
int bFullscreen = -1;
|
int bFullscreen = -1;
|
||||||
|
@ -365,6 +369,9 @@ class CWindow {
|
||||||
// stores the currently matched window rules
|
// stores the currently matched window rules
|
||||||
std::vector<SWindowRule> m_vMatchedRules;
|
std::vector<SWindowRule> m_vMatchedRules;
|
||||||
|
|
||||||
|
// window tags
|
||||||
|
CTagKeeper m_tags;
|
||||||
|
|
||||||
// For the list lookup
|
// For the list lookup
|
||||||
bool operator==(const CWindow& rhs) {
|
bool operator==(const CWindow& rhs) {
|
||||||
return m_pXDGSurface == rhs.m_pXDGSurface && m_pXWaylandSurface == rhs.m_pXWaylandSurface && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize &&
|
return m_pXDGSurface == rhs.m_pXDGSurface && m_pXWaylandSurface == rhs.m_pXWaylandSurface && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize &&
|
||||||
|
|
40
src/helpers/TagKeeper.cpp
Normal file
40
src/helpers/TagKeeper.cpp
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#include "TagKeeper.hpp"
|
||||||
|
|
||||||
|
bool CTagKeeper::isTagged(const std::string& tag, bool strict) {
|
||||||
|
return m_tags.contains(tag) || (!strict && m_tags.contains(tag + "*"));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CTagKeeper::applyTag(const std::string& tag, bool dynamic) {
|
||||||
|
|
||||||
|
std::string tagReal = tag;
|
||||||
|
|
||||||
|
if (dynamic && !tag.ends_with("*"))
|
||||||
|
tagReal += "*";
|
||||||
|
|
||||||
|
bool changed = true;
|
||||||
|
bool setTag = true;
|
||||||
|
|
||||||
|
if (tagReal.starts_with("-")) { // unset
|
||||||
|
tagReal = tagReal.substr(1);
|
||||||
|
changed = isTagged(tagReal, true);
|
||||||
|
setTag = false;
|
||||||
|
} else if (tagReal.starts_with("+")) { // set
|
||||||
|
tagReal = tagReal.substr(1);
|
||||||
|
changed = !isTagged(tagReal, true);
|
||||||
|
} else // toggle if without prefix
|
||||||
|
setTag = !isTagged(tagReal, true);
|
||||||
|
|
||||||
|
if (!changed)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (setTag)
|
||||||
|
m_tags.emplace(tagReal);
|
||||||
|
else
|
||||||
|
m_tags.erase(tagReal);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CTagKeeper::removeDynamicTags() {
|
||||||
|
return std::erase_if(m_tags, [](const auto& tag) { return tag.ends_with("*"); });
|
||||||
|
}
|
18
src/helpers/TagKeeper.hpp
Normal file
18
src/helpers/TagKeeper.hpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
class CTagKeeper {
|
||||||
|
public:
|
||||||
|
bool isTagged(const std::string& tag, bool strict = false);
|
||||||
|
bool applyTag(const std::string& tag, bool dynamic = false);
|
||||||
|
bool removeDynamicTags();
|
||||||
|
|
||||||
|
inline const auto& getTags() {
|
||||||
|
return m_tags;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::set<std::string> m_tags;
|
||||||
|
};
|
|
@ -1,17 +1,16 @@
|
||||||
#include "KeybindManager.hpp"
|
|
||||||
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
|
|
||||||
#include "debug/Log.hpp"
|
|
||||||
#include "helpers/VarList.hpp"
|
|
||||||
#include "../config/ConfigValue.hpp"
|
#include "../config/ConfigValue.hpp"
|
||||||
#include "TokenManager.hpp"
|
|
||||||
#include "../protocols/ShortcutsInhibit.hpp"
|
|
||||||
#include "../devices/IKeyboard.hpp"
|
#include "../devices/IKeyboard.hpp"
|
||||||
#include "../managers/SeatManager.hpp"
|
#include "../managers/SeatManager.hpp"
|
||||||
|
#include "../protocols/ShortcutsInhibit.hpp"
|
||||||
|
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
|
||||||
|
#include "KeybindManager.hpp"
|
||||||
|
#include "TokenManager.hpp"
|
||||||
|
#include "debug/Log.hpp"
|
||||||
|
#include "helpers/VarList.hpp"
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <regex>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
#include <string_view>
|
||||||
|
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
@ -87,6 +86,7 @@ CKeybindManager::CKeybindManager() {
|
||||||
m_mDispatchers["cyclenext"] = circleNext;
|
m_mDispatchers["cyclenext"] = circleNext;
|
||||||
m_mDispatchers["focuswindowbyclass"] = focusWindow;
|
m_mDispatchers["focuswindowbyclass"] = focusWindow;
|
||||||
m_mDispatchers["focuswindow"] = focusWindow;
|
m_mDispatchers["focuswindow"] = focusWindow;
|
||||||
|
m_mDispatchers["tagwindow"] = tagWindow;
|
||||||
m_mDispatchers["submap"] = setSubmap;
|
m_mDispatchers["submap"] = setSubmap;
|
||||||
m_mDispatchers["pass"] = pass;
|
m_mDispatchers["pass"] = pass;
|
||||||
m_mDispatchers["sendshortcut"] = sendshortcut;
|
m_mDispatchers["sendshortcut"] = sendshortcut;
|
||||||
|
@ -1928,6 +1928,23 @@ void CKeybindManager::focusWindow(std::string regexp) {
|
||||||
g_pCompositor->warpCursorTo(PWINDOW->middle());
|
g_pCompositor->warpCursorTo(PWINDOW->middle());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CKeybindManager::tagWindow(std::string args) {
|
||||||
|
PHLWINDOW PWINDOW = nullptr;
|
||||||
|
CVarList vars{args, 0, 's', true};
|
||||||
|
|
||||||
|
if (vars.size() == 1)
|
||||||
|
PWINDOW = g_pCompositor->m_pLastWindow.lock();
|
||||||
|
else if (vars.size() == 2)
|
||||||
|
PWINDOW = g_pCompositor->getWindowByRegex(vars[1]);
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (PWINDOW && PWINDOW->m_tags.applyTag(vars[0])) {
|
||||||
|
PWINDOW->updateDynamicRules();
|
||||||
|
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW->m_pSelf.lock());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CKeybindManager::setSubmap(std::string submap) {
|
void CKeybindManager::setSubmap(std::string submap) {
|
||||||
if (submap == "reset" || submap == "") {
|
if (submap == "reset" || submap == "") {
|
||||||
m_szCurrentSelectedSubmap = "";
|
m_szCurrentSelectedSubmap = "";
|
||||||
|
|
|
@ -181,6 +181,7 @@ class CKeybindManager {
|
||||||
static void resizeWindow(std::string);
|
static void resizeWindow(std::string);
|
||||||
static void circleNext(std::string);
|
static void circleNext(std::string);
|
||||||
static void focusWindow(std::string);
|
static void focusWindow(std::string);
|
||||||
|
static void tagWindow(std::string);
|
||||||
static void setSubmap(std::string);
|
static void setSubmap(std::string);
|
||||||
static void pass(std::string);
|
static void pass(std::string);
|
||||||
static void sendshortcut(std::string);
|
static void sendshortcut(std::string);
|
||||||
|
|
Loading…
Reference in a new issue