diff --git a/include/components/screen.hpp b/include/components/screen.hpp index 04ae97f5..bdcf30a2 100644 --- a/include/components/screen.hpp +++ b/include/components/screen.hpp @@ -47,6 +47,8 @@ class screen : public xpp::event::sink { vector m_monitors; struct size m_size {0U, 0U}; bool m_sigraised{false}; + + bool have_monitors_changed() const; }; POLYBAR_NS_END diff --git a/include/x11/extensions/randr.hpp b/include/x11/extensions/randr.hpp index b53f395e..9d9822f3 100644 --- a/include/x11/extensions/randr.hpp +++ b/include/x11/extensions/randr.hpp @@ -42,6 +42,8 @@ struct randr_output { bool match(const position& p) const; bool contains(const randr_output& output) const; + + bool equals(const randr_output& output) const; }; using monitor_t = shared_ptr; diff --git a/src/components/screen.cpp b/src/components/screen.cpp index a206b539..b52be580 100644 --- a/src/components/screen.cpp +++ b/src/components/screen.cpp @@ -1,4 +1,5 @@ #include +#include #include #include "components/config.hpp" @@ -33,7 +34,7 @@ screen::screen(connection& conn, signal_emitter& emitter, const logger& logger, , m_log(logger) , m_conf(conf) , m_root(conn.root()) - , m_monitors(randr_util::get_monitors(m_connection, m_root, true)) + , m_monitors(randr_util::get_monitors(m_connection, m_root, true, false)) , m_size({conn.screen()->width_in_pixels, conn.screen()->height_in_pixels}) { // Check if the reloading has been disabled by the user if (!m_conf.get("settings", "screenchange-reload", false)) { @@ -88,7 +89,7 @@ screen::~screen() { /** * Handle XCB_RANDR_SCREEN_CHANGE_NOTIFY events * - * If the screen dimensions have changed we raise USR1 to trigger a reload + * If any of the monitors have changed we raise USR1 to trigger a reload */ void screen::handle(const evt::randr_screen_change_notify& evt) { if (m_sigraised || evt->request_window != m_proxy) { @@ -98,24 +99,49 @@ void screen::handle(const evt::randr_screen_change_notify& evt) { auto screen = m_connection.screen(true); auto changed = false; + // We need to reload if the screen size changed as well if (screen->width_in_pixels != m_size.w || screen->height_in_pixels != m_size.h) { changed = true; } else { - auto monitors = randr_util::get_monitors(m_connection, m_root, true, false); - for (size_t n = 0; n < monitors.size(); n++) { - if (n < m_monitors.size() && monitors[n]->output != m_monitors[n]->output) { - changed = true; - } + changed = have_monitors_changed(); + } + + if (changed) { + m_log.warn("randr_screen_change_notify (%ux%u)... reloading", evt->width, evt->height); + m_sig.emit(exit_reload{}); + m_sigraised = true; + } +} + +/** + * Checks if the stored monitor list is different from a newly fetched one + * + * Fetches the monitor list and compares it with the one stored + */ +bool screen::have_monitors_changed() const { + auto monitors = randr_util::get_monitors(m_connection, m_root, true, false); + + if(monitors.size() != m_monitors.size()) { + return true; + } + + for (auto m : m_monitors) { + auto it = std::find_if(monitors.begin(), monitors.end(), + [m] (auto& monitor) -> bool { + return m->equals(*monitor); + }); + + /* + * Every monitor in the stored list should also exist in the newly fetched + * list. If this holds then the two lists are equivalent since they have + * the same size + */ + if(it == monitors.end()) { + return true; } } - if (!changed) { - return; - } - - m_log.warn("randr_screen_change_notify (%ux%u)... reloading", evt->width, evt->height); - m_sig.emit(exit_reload{}); - m_sigraised = true; + return false; } POLYBAR_NS_END diff --git a/src/x11/extensions/randr.cpp b/src/x11/extensions/randr.cpp index ac4333c1..74a01122 100644 --- a/src/x11/extensions/randr.cpp +++ b/src/x11/extensions/randr.cpp @@ -42,6 +42,16 @@ bool randr_output::contains(const randr_output& inner) const { && inner.y >= y && inner.y + inner.h <= y + h; } +/** + * Checks if the given output is the same as this + * + * Looks at xcb_randr_output_t, position, dimension, name and 'primary' + */ +bool randr_output::equals(const randr_output& o) const { + return o.output == output && o.x == x && o.y == y && o.w == w && o.h == h && + o.primary == primary && o.name == name; +} + namespace randr_util { /** * XRandR version