kranewm

An ICCCM & EWMH compliant X11 reparenting, dynamic window manager, written in C++
git clone git clone git://git.deurzen.net/kranewm.git
Log | Files | Refs | LICENSE

commit d5b624e931bbbe4c30fa61eb2deb3ba5809aa80b
parent f083ef490d046f3cbb6c000f1f6e2a25743fed22
Author: deurzen <m.deurzen@tum.de>
Date:   Sat,  4 Sep 2021 11:19:08 +0200

implements default rules config handling

Diffstat:
Msrc/core/config.cc | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/core/config.hh | 3+++
Msrc/core/model.cc | 22++++++++++++++++++++--
Msrc/core/rules.hh | 59++++++++++++++++++++++++++++++++++++++++++++++-------------
4 files changed, 145 insertions(+), 15 deletions(-)

diff --git a/src/core/config.cc b/src/core/config.cc @@ -87,6 +87,82 @@ Config::Config() } } } + + { // produce vector of default spawn rules + std::ifstream in(directory + std::string("defaultrules")); + + if (in.good()) { + std::string line; + + while (std::getline(in, line)) { + std::string::size_type pos = line.find('#'); + + if (pos != std::string::npos) + line = line.substr(0, pos); + + if (line.length() < 5) + continue; + + line.erase(4, line.find_first_not_of(" \t\n\r\f\v")); + line.erase(line.find_last_not_of(" \t\n\r\f\v") + 1); + + if (line.length() < 5) + continue; + + pos = line.find(':'); + std::string rules = line.substr(0, pos); + + if (pos == std::string::npos || rules.empty() || pos >= (line.size() - 1)) + continue; + + line = line.substr(pos + 1); + + if (line.length() < 5) + continue; + + SearchSelector::SelectionCriterium criterium; + + switch (line[1]) { + case 'N': + { + switch (line[0]) { + case '=': criterium = SearchSelector::SelectionCriterium::ByNameEquals; break; + case '~': criterium = SearchSelector::SelectionCriterium::ByNameContains; break; + default: continue; + } + + break; + } + case 'C': + { + switch (line[0]) { + case '=': criterium = SearchSelector::SelectionCriterium::ByClassEquals; break; + case '~': criterium = SearchSelector::SelectionCriterium::ByClassContains; break; + default: continue; + } + + break; + } + case 'I': + { + switch (line[0]) { + case '=': criterium = SearchSelector::SelectionCriterium::ByInstanceEquals; break; + case '~': criterium = SearchSelector::SelectionCriterium::ByInstanceContains; break; + default: continue; + } + + break; + } + default: continue; + } + + default_rules.push_back({ + new SearchSelector{criterium, line.substr(3)}, + Rules::parse_rules(rules, true) + }); + } + } + } } Config::~Config() diff --git a/src/core/config.hh b/src/core/config.hh @@ -2,6 +2,7 @@ #define __CONFIG_H_GUARD__ #include "search.hh" +#include "rules.hh" #include <string> #include <vector> @@ -35,6 +36,8 @@ struct Config std::vector<SearchSelector_ptr> ignored_producers; std::vector<SearchSelector_ptr> ignored_consumers; + std::vector<std::tuple<SearchSelector_ptr, Rules>> default_rules; + }; #endif//__CONFIG_H_GUARD__ diff --git a/src/core/model.cc b/src/core/model.cc @@ -428,7 +428,7 @@ Model::Model(Connection& conn) CALL(activate_next_workspace(Direction::Backward)) }, { { Key::One, { Main } }, - CALL(activate_workspace(Util::Change<Index> { 0 })) + CALL(activate_workspace(Util::Change<Index>{ 0 })) }, { { Key::Two, { Main } }, CALL(activate_workspace(1)) @@ -1516,6 +1516,8 @@ Model::render_decoration(Client_ptr client) void Model::manage(const Window window, const bool ignore, const bool may_map) { + static std::unordered_map<std::string, Rules> default_rules_memoized = {}; + std::optional<Region> window_geometry = m_conn.get_window_geometry(window); if (ignore || !window_geometry) { @@ -1547,6 +1549,10 @@ Model::manage(const Window window, const bool ignore, const bool may_map) std::string class_ = m_conn.get_icccm_window_class(window); std::string instance = m_conn.get_icccm_window_instance(window); + std::string client_handle = name + + ":" + class_ + + ":" + instance; + std::unordered_set<WindowType> types = m_conn.get_window_types(window); std::unordered_set<WindowState> states = m_conn.get_window_states(window); @@ -1625,7 +1631,19 @@ Model::manage(const Window window, const bool ignore, const bool may_map) client->leader = leader; } - Rules rules = Rules::parse_rules(client); + std::optional<Rules> default_rules + = Util::retrieve(default_rules_memoized, client_handle); + + if (!default_rules) + for (auto& [selector,default_rules_] : m_config.default_rules) + if (client_matches_search(client, *selector)) { + default_rules_memoized[client_handle] = default_rules_; + default_rules = default_rules_; + } + + Rules rules = default_rules + ? Rules::merge_rules(*default_rules, Rules::parse_rules(client->instance)) + : Rules::parse_rules(client->instance); if (center || (rules.do_center && *rules.do_center)) { const Region screen_region = active_screen().placeable_region(); diff --git a/src/core/rules.hh b/src/core/rules.hh @@ -7,6 +7,7 @@ #include <optional> #include <vector> +#include <iostream> struct Rules { @@ -33,31 +34,31 @@ struct Rules std::optional<std::vector<winsys::Edge>> snap_edges; static Rules - parse_rules(Client_ptr client) + parse_rules(std::string_view rule, bool ignore_prefix = false) { static std::string prefix = WM_NAME + ":"; static auto snapedge_list_handler = [](Rules& rules, auto iter) { switch (*iter) { - case 'l': rules.snap_edges->push_back(winsys::Edge::Left); return; - case 't': rules.snap_edges->push_back(winsys::Edge::Top); return; - case 'r': rules.snap_edges->push_back(winsys::Edge::Right); return; - case 'b': rules.snap_edges->push_back(winsys::Edge::Bottom); return; - default: return; + case 'l': rules.snap_edges->push_back(winsys::Edge::Left); return; + case 't': rules.snap_edges->push_back(winsys::Edge::Top); return; + case 'r': rules.snap_edges->push_back(winsys::Edge::Right); return; + case 'b': rules.snap_edges->push_back(winsys::Edge::Bottom); return; + default: return; } }; Rules rules = {}; - if (client->instance.size() <= prefix.size()) + if (!ignore_prefix && rule.size() <= prefix.size()) return rules; auto res = std::mismatch( - prefix.begin(), - prefix.end(), - client->instance.begin() - ); + prefix.begin(), + prefix.end(), + rule.begin() + ); - if (res.first == prefix.end()) { + if (ignore_prefix || res.first == prefix.end()) { bool invert = false; bool next_partition = false; bool next_context = false; @@ -65,7 +66,7 @@ struct Rules std::optional<decltype(snapedge_list_handler)> list_handler = std::nullopt; - for (auto iter = res.second; iter != client->instance.end(); ++iter) { + for (auto iter = res.second; iter != rule.end(); ++iter) { if (*iter == '.') { list_handler = std::nullopt; continue; @@ -135,6 +136,38 @@ struct Rules return rules; } + + static Rules + merge_rules(Rules const& base, Rules const& merger) + { + Rules rules = base; + + if (merger.do_focus) + rules.do_focus = merger.do_focus; + + if (merger.do_float) + rules.do_float = merger.do_float; + + if (merger.do_center) + rules.do_center = merger.do_center; + + if (merger.do_fullscreen) + rules.do_fullscreen = merger.do_fullscreen; + + if (merger.to_partition) + rules.to_partition = merger.to_partition; + + if (merger.to_context) + rules.to_context = merger.to_context; + + if (merger.to_workspace) + rules.to_workspace = merger.to_workspace; + + if (merger.snap_edges) + rules.snap_edges = merger.snap_edges; + + return rules; + } }; #endif//__RULES_H_GUARD__