Skip to content

Commit

Permalink
tag: consider tag rule on get matched rules
Browse files Browse the repository at this point in the history
  • Loading branch information
rtgiskard committed May 25, 2024
1 parent eb7223e commit f7f796a
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 98 deletions.
35 changes: 20 additions & 15 deletions src/config/ConfigManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1062,16 +1062,16 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo
bool hasFloating = pWindow->m_bIsFloating;
bool hasFullscreen = pWindow->m_bIsFullscreen;

// local tags for dynamic tag rule match
auto tags = pWindow->m_tags;

for (auto& rule : m_dWindowRules) {
// check if we have a matching rule
if (!rule.v2) {
try {
if (rule.szValue.starts_with("tag:")) {
const auto tag = rule.szValue.substr(4);

if (!pWindow->isTagged(tag))
continue;
} else if (rule.szValue.starts_with("title:")) {
if (rule.szValue.starts_with("tag:") && !tags.isTagged(rule.szValue.substr(4)))
continue;
else if (rule.szValue.starts_with("title:")) {
std::regex RULECHECK(rule.szValue.substr(6));

if (!std::regex_search(title, RULECHECK))
Expand All @@ -1088,10 +1088,8 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo
}
} else {
try {
if (!rule.szTag.empty()) {
if (!pWindow->isTagged(rule.szTag))
continue;
}
if (!rule.szTag.empty() && !tags.isTagged(rule.szTag))
continue;

if (!rule.szClass.empty()) {
std::regex RULECHECK(rule.szClass);
Expand Down Expand Up @@ -1183,6 +1181,13 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo

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]);
}

if (dynamic)
continue;

Expand Down Expand Up @@ -2044,19 +2049,19 @@ bool windowRuleValid(const std::string& RULE) {
"keepaspectratio", "maximize", "nearestneighbor", "noanim", "noblur", "noborder", "nodim", "nofocus",
"noinitialfocus", "nomaxsize", "noshadow", "opaque", "pin", "stayfocused", "tile", "windowdance",
};
static const auto rules_prefix = std::vector<std::string>{
static const auto rulesPrefix = std::vector<std::string>{
"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(rules_prefix.begin(), rules_prefix.end(), [&RULE](auto prefix) { return RULE.starts_with(prefix); });
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) {
static const auto rules = std::unordered_set<std::string>{"noanim", "blur", "blurpopups", "dimaround"};
static const auto rules_prefix = std::vector<std::string>{"ignorealpha", "ignorezero", "xray", "animation"};
static const auto rules = std::unordered_set<std::string>{"noanim", "blur", "blurpopups", "dimaround"};
static const auto rulesPrefix = std::vector<std::string>{"ignorealpha", "ignorezero", "xray", "animation"};

return rules.contains(RULE) || std::any_of(rules_prefix.begin(), rules_prefix.end(), [&RULE](auto prefix) { return RULE.starts_with(prefix); });
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) {
Expand Down
8 changes: 4 additions & 4 deletions src/debug/HyprCtl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,13 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
}

static std::string getTagsData(PHLWINDOW w, eHyprCtlOutputFormat format) {
const bool isJson = format == eHyprCtlOutputFormat::FORMAT_JSON;
const auto tags = w->m_tags.getTags();

if (isJson)
return std::accumulate(w->m_tags.begin(), w->m_tags.end(), std::string(),
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(w->m_tags.begin(), w->m_tags.end(), std::string(), [](const std::string& a, const std::string& b) { return a.empty() ? b : a + ", " + b; });
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) {
Expand Down
72 changes: 10 additions & 62 deletions src/desktop/Window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -615,9 +615,9 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
CVarList vars{r.szRule, 0, 's', true};

if (vars.size() == 2 && vars[0] == "tag")
applyTag(vars[1], true);
m_tags.applyTag(vars[1], true);
else
Debug::log(ERR, "Rule tag invalid: {}", r.szRule);
Debug::log(ERR, "Tag rule invalid: {}", r.szRule);
} else if (r.szRule.starts_with("rounding")) {
try {
m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
Expand Down Expand Up @@ -799,7 +799,7 @@ void CWindow::updateDynamicRules() {
m_sAdditionalConfigData.nearestNeighbor = false;
m_eIdleInhibitMode = IDLEINHIBIT_NONE;

std::erase_if(m_tags, [](const auto& tag) { return tag.ends_with("*"); });
m_tags.removeDynamicTags();

m_vMatchedRules = g_pConfigManager->getMatchingRules(m_pSelf.lock());
for (auto& r : m_vMatchedRules) {
Expand Down Expand Up @@ -851,59 +851,6 @@ bool CWindow::hasPopupAt(const Vector2D& pos) {
return popup && popup->m_sWLSurface.wlr();
}

bool CWindow::isTagged(const std::string& tag, bool strict) {
return m_tags.contains(tag) || (!strict && m_tags.contains(tag + "*"));
}

void CWindow::applyTag(const std::string& tag, bool dynamic) {

std::string tag_real = dynamic ? tag + "*" : tag;

bool changed = true;
bool setTag = true;

if (tag_real.starts_with("-")) { // unset
tag_real = tag_real.substr(1);
changed = isTagged(tag_real, true);
setTag = false;
} else if (tag_real.starts_with("+")) { // set
tag_real = tag_real.substr(1);
changed = !isTagged(tag_real, true);
} else // toggle if without prefix
setTag = !isTagged(tag_real, true);

if (!changed)
return;

if (setTag)
m_tags.emplace(tag_real);
else
m_tags.erase(tag_real);

// re run tag rules after update tag
queueScanForTagMatch();
}

void CWindow::queueScanForTagMatch() {
// TODO: assume single thread for window operation
if (!m_tagScanSource)
m_tagScanSource = wl_event_loop_add_idle(
g_pCompositor->m_sWLEventLoop,
[](void* data) {
auto w = static_cast<CWindow*>(data);

w->m_vMatchedRules = g_pConfigManager->getMatchingRules(w->m_pSelf.lock());
for (auto& r : w->m_vMatchedRules)
if ((r.v2 && !r.szTag.empty() && w->isTagged(r.szTag)) || (!r.v2 && r.szValue.starts_with("tag:") && w->isTagged(r.szValue.substr(4))))
w->applyDynamicRule(r);

// NOTE: if tag from tag, then the nested tag's rescan will be ignored
wl_event_source_remove(w->m_tagScanSource);
w->m_tagScanSource = nullptr;
},
this);
}

void CWindow::applyGroupRules() {
if ((m_eGroupRules & GROUP_SET && m_bFirstMap) || m_eGroupRules & GROUP_SET_ALWAYS)
createGroup();
Expand Down Expand Up @@ -1424,6 +1371,7 @@ void CWindow::onUpdateState() {

void CWindow::onUpdateMeta() {
const auto NEWTITLE = fetchTitle();
bool doUpdate = false;

if (m_szTitle != NEWTITLE) {
m_szTitle = NEWTITLE;
Expand All @@ -1436,11 +1384,8 @@ void CWindow::onUpdateMeta() {
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);
doUpdate = true;
}

const auto NEWCLASS = fetchClass();
Expand All @@ -1453,11 +1398,14 @@ void CWindow::onUpdateMeta() {
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();
g_pCompositor->updateWindowAnimatedDecorationValues(m_pSelf.lock());
updateToplevel();

Debug::log(LOG, "Window {:x} set class to {}", (uintptr_t)this, m_szClass);
}
}

Expand Down
9 changes: 2 additions & 7 deletions src/desktop/Window.hpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#pragma once

#include <deque>
#include <set>
#include <string>

#include "../config/ConfigDataValues.hpp"
#include "../defines.hpp"
#include "../helpers/AnimatedVariable.hpp"
#include "../helpers/Vector2D.hpp"
#include "../helpers/signal/Signal.hpp"
#include "../helpers/TagKeeper.hpp"
#include "../macros.hpp"
#include "../managers/XWaylandManager.hpp"
#include "../render/decorations/IHyprWindowDecoration.hpp"
Expand Down Expand Up @@ -394,8 +394,7 @@ class CWindow {
std::vector<SWindowRule> m_vMatchedRules;

// window tags
std::set<std::string> m_tags;
wl_event_source* m_tagScanSource = nullptr;
TagKeeper m_tags;

// For the list lookup
bool operator==(const CWindow& rhs) {
Expand Down Expand Up @@ -440,10 +439,6 @@ class CWindow {
void activate(bool force = false);
int surfacesCount();

bool isTagged(const std::string& tag, bool strict = false);
void applyTag(const std::string& tag, bool dynamic = false);
void queueScanForTagMatch();

int getRealBorderSize();
void updateSpecialRenderData();
void updateSpecialRenderData(const struct SWorkspaceRule&);
Expand Down
40 changes: 40 additions & 0 deletions src/helpers/TagKeeper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include "TagKeeper.hpp"

bool TagKeeper::isTagged(const std::string& tag, bool strict) {
return m_tags.contains(tag) || (!strict && m_tags.contains(tag + "*"));
}

bool TagKeeper::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 TagKeeper::removeDynamicTags() {
return std::erase_if(m_tags, [](const auto& tag) { return tag.ends_with("*"); });
}
18 changes: 18 additions & 0 deletions src/helpers/TagKeeper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once

#include <string>
#include <set>

class TagKeeper {
private:
std::set<std::string> m_tags;

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;
};
};
20 changes: 10 additions & 10 deletions src/managers/KeybindManager.cpp
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
#include "KeybindManager.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "debug/Log.hpp"
#include "helpers/VarList.hpp"
#include "../config/ConfigValue.hpp"
#include "TokenManager.hpp"
#include "../protocols/ShortcutsInhibit.hpp"
#include "../devices/IKeyboard.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 <regex>
#include <string>
#include <string_view>
#include <tuple>

#include <sys/ioctl.h>
#include <fcntl.h>
Expand Down Expand Up @@ -1941,8 +1939,10 @@ void CKeybindManager::tagWindow(std::string args) {
else
return;

if (PWINDOW)
PWINDOW->applyTag(vars[0]);
if (PWINDOW && PWINDOW->m_tags.applyTag(vars[0])) {
PWINDOW->updateDynamicRules();
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW->m_pSelf.lock());
}
}

void CKeybindManager::setSubmap(std::string submap) {
Expand Down

0 comments on commit f7f796a

Please sign in to comment.