From e7930820086374403077bdbc1b089e795f4283d9 Mon Sep 17 00:00:00 2001
From: patrick96
Date: Mon, 3 Dec 2018 01:21:20 +0100
Subject: [PATCH] randr: Add separate key for exact monitor matching
This adds `monitor-exact = true` in the bar section
This also properly does best-match instead of first-match if multiple
matches exists. For example if there are two monitors HDMI2 and HDMI-2
and we try to match HDMI-2 with monitor-exact = false, until now HDMI2
would be matched. Now exact matches are always preferred.
Fixes #1532
---
include/components/types.hpp | 1 +
include/x11/extensions/randr.hpp | 3 ++-
src/components/bar.cpp | 18 ++++----------
src/modules/xbacklight.cpp | 12 +++------
src/x11/extensions/randr.cpp | 42 +++++++++++++++++++++++++++-----
5 files changed, 48 insertions(+), 28 deletions(-)
diff --git a/include/components/types.hpp b/include/components/types.hpp
index 1a1299ed..b24e58d0 100644
--- a/include/components/types.hpp
+++ b/include/components/types.hpp
@@ -123,6 +123,7 @@ struct bar_settings {
xcb_window_t window{XCB_NONE};
monitor_t monitor{};
+ bool monitor_exact{true};
edge origin{edge::TOP};
struct size size {
1U, 1U
diff --git a/include/x11/extensions/randr.hpp b/include/x11/extensions/randr.hpp
index 8c9ea967..515a059e 100644
--- a/include/x11/extensions/randr.hpp
+++ b/include/x11/extensions/randr.hpp
@@ -37,7 +37,7 @@ struct randr_output {
xcb_randr_output_t output;
backlight_values backlight;
- bool match(const string& o, bool strict = false) const;
+ bool match(const string& o, bool exact = true) const;
bool match(const position& p) const;
};
@@ -50,6 +50,7 @@ namespace randr_util {
monitor_t make_monitor(xcb_randr_output_t randr, string name, unsigned short int w, unsigned short int h, short int x, short int y);
vector get_monitors(connection& conn, xcb_window_t root, bool connected_only = false, bool realloc = false);
+ monitor_t match_monitor(vector monitors, const string& name, bool exact_match);
void get_backlight_range(connection& conn, const monitor_t& mon, backlight_values& dst);
void get_backlight_value(connection& conn, const monitor_t& mon, backlight_values& dst);
diff --git a/src/components/bar.cpp b/src/components/bar.cpp
index d9bb3087..1bdb7640 100644
--- a/src/components/bar.cpp
+++ b/src/components/bar.cpp
@@ -73,6 +73,7 @@ bar::bar(connection& conn, signal_emitter& emitter, const config& config, const
auto monitor_name = m_conf.get(bs, "monitor", ""s);
auto monitor_name_fallback = m_conf.get(bs, "monitor-fallback", ""s);
auto monitor_strictmode = m_conf.get(bs, "monitor-strict", false);
+ m_opts.monitor_exact = m_conf.get(bs, "monitor-exact", m_opts.monitor_exact);
auto monitors = randr_util::get_monitors(m_connection, m_connection.screen()->root, monitor_strictmode);
if (monitors.empty()) {
@@ -92,26 +93,17 @@ bar::bar(connection& conn, signal_emitter& emitter, const config& config, const
m_log.warn("No monitor specified, using \"%s\"", monitor_name);
}
- bool name_found{false};
- bool fallback_found{monitor_name_fallback.empty()};
+ m_opts.monitor = randr_util::match_monitor(monitors, monitor_name, m_opts.monitor_exact);
monitor_t fallback{};
- for (auto&& monitor : monitors) {
- if (!name_found && (name_found = monitor->match(monitor_name, monitor_strictmode))) {
- m_opts.monitor = move(monitor);
- } else if (!fallback_found && (fallback_found = monitor->match(monitor_name_fallback, monitor_strictmode))) {
- fallback = move(monitor);
- }
-
- if (name_found && fallback_found) {
- break;
- }
+ if(!monitor_name_fallback.empty()) {
+ fallback = randr_util::match_monitor(monitors, monitor_name_fallback, m_opts.monitor_exact);
}
if (!m_opts.monitor) {
if (fallback) {
m_opts.monitor = move(fallback);
- m_log.warn("Monitor \"%s\" not found, reverting to fallback \"%s\"", monitor_name, monitor_name_fallback);
+ m_log.warn("Monitor \"%s\" not found, reverting to fallback \"%s\"", monitor_name, m_opts.monitor->name);
} else {
throw application_error("Monitor \"" + monitor_name + "\" not found or disconnected");
}
diff --git a/src/modules/xbacklight.cpp b/src/modules/xbacklight.cpp
index 5debbe45..0364dfc1 100644
--- a/src/modules/xbacklight.cpp
+++ b/src/modules/xbacklight.cpp
@@ -21,13 +21,9 @@ namespace modules {
auto output = m_conf.get(name(), "output", m_bar.monitor->name);
auto strict = m_conf.get(name(), "monitor-strict", false);
- // Grab a list of all outputs and try to find the one defined in the config
- for (auto&& mon : randr_util::get_monitors(m_connection, m_connection.root(), strict)) {
- if (mon->match(output, strict)) {
- m_output.swap(mon);
- break;
- }
- }
+ auto monitors = randr_util::get_monitors(m_connection, m_connection.root(), strict);
+
+ m_output = randr_util::match_monitor(monitors, output, bar.monitor_exact);
// If we didn't get a match we stop the module
if (!m_output) {
@@ -44,7 +40,7 @@ namespace modules {
randr_util::get_backlight_value(m_connection, m_output, backlight);
} catch (const exception& err) {
m_log.err("%s: Could not get data (err: %s)", name(), err.what());
- throw module_error("Not supported for \"" + output + "\"");
+ throw module_error("Not supported for \"" + m_output->name + "\"");
}
// Create window that will proxy all RandR notify events
diff --git a/src/x11/extensions/randr.cpp b/src/x11/extensions/randr.cpp
index dab74473..bd11806d 100644
--- a/src/x11/extensions/randr.cpp
+++ b/src/x11/extensions/randr.cpp
@@ -12,15 +12,17 @@
POLYBAR_NS
/**
- * Workaround for the inconsistent naming
- * of outputs between my intel and nvidia
+ * Workaround for the inconsistent naming of outputs between intel and nvidia
* drivers (xf86-video-intel drops the dash)
+ *
+ * If exact == false, dashes will be ignored while matching
*/
-bool randr_output::match(const string& o, bool strict) const {
- if (strict && name != o) {
- return false;
+bool randr_output::match(const string& o, bool exact) const {
+ if (exact) {
+ return name == o;
+ } else {
+ return string_util::replace(name, "-", "") == string_util::replace(o, "-", "");
}
- return name == o || name == string_util::replace(o, "-", "");
}
/**
@@ -172,6 +174,34 @@ namespace randr_util {
return monitors;
}
+ /**
+ * Searches for a monitor with name in monitors
+ *
+ * Does best-fit matching (if exact_match == true, this is also first-fit)
+ */
+ monitor_t match_monitor(vector monitors, const string& name, bool exact_match) {
+ monitor_t result{};
+ for(auto&& monitor : monitors) {
+ // If we can do an exact match, we have found our result
+ if(monitor->match(name, true)) {
+ result = move(monitor);
+ break;
+ }
+
+ /*
+ * Non-exact matches are moved into the result but we continue searching
+ * through the list, maybe we can find an exact match
+ * Note: If exact_match == true, we don't need to run this because it
+ * would be the exact same check as above
+ */
+ if(!exact_match && monitor->match(name, false)) {
+ result = move(monitor);
+ }
+ }
+
+ return result;
+ }
+
/**
* Get backlight value range for given output
*/