2021-09-13 14:54:00 -04:00
|
|
|
#include "components/screen.hpp"
|
|
|
|
|
2019-06-30 09:34:18 -04:00
|
|
|
#include <algorithm>
|
2021-09-13 14:54:00 -04:00
|
|
|
#include <csignal>
|
2016-11-26 18:46:41 -05:00
|
|
|
#include <thread>
|
|
|
|
|
|
|
|
#include "components/config.hpp"
|
|
|
|
#include "components/logger.hpp"
|
2016-12-03 22:11:47 -05:00
|
|
|
#include "components/types.hpp"
|
2016-12-05 14:41:00 -05:00
|
|
|
#include "events/signal.hpp"
|
|
|
|
#include "events/signal_emitter.hpp"
|
2016-11-26 18:46:41 -05:00
|
|
|
#include "x11/connection.hpp"
|
2016-12-26 04:27:30 -05:00
|
|
|
#include "x11/extensions/all.hpp"
|
|
|
|
#include "x11/registry.hpp"
|
|
|
|
#include "x11/types.hpp"
|
2016-11-26 18:46:41 -05:00
|
|
|
#include "x11/winspec.hpp"
|
|
|
|
|
|
|
|
POLYBAR_NS
|
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
using namespace signals::eventqueue;
|
2016-11-26 18:46:41 -05:00
|
|
|
|
2016-12-09 03:02:47 -05:00
|
|
|
/**
|
|
|
|
* Create instance
|
|
|
|
*/
|
2016-12-09 03:40:46 -05:00
|
|
|
screen::make_type screen::make() {
|
2021-09-21 15:15:49 -04:00
|
|
|
return std::make_unique<screen>(connection::make(), signal_emitter::make(), logger::make(), config::make());
|
2016-12-09 03:02:47 -05:00
|
|
|
}
|
|
|
|
|
2016-11-26 18:46:41 -05:00
|
|
|
/**
|
|
|
|
* Construct screen instance
|
|
|
|
*/
|
2016-12-05 14:41:00 -05:00
|
|
|
screen::screen(connection& conn, signal_emitter& emitter, const logger& logger, const config& conf)
|
2016-11-26 18:46:41 -05:00
|
|
|
: m_connection(conn)
|
2016-12-05 14:41:00 -05:00
|
|
|
, m_sig(emitter)
|
2016-11-26 18:46:41 -05:00
|
|
|
, m_log(logger)
|
|
|
|
, m_conf(conf)
|
|
|
|
, m_root(conn.root())
|
2019-06-30 09:34:18 -04:00
|
|
|
, m_monitors(randr_util::get_monitors(m_connection, m_root, true, false))
|
2016-11-26 18:46:41 -05:00
|
|
|
, m_size({conn.screen()->width_in_pixels, conn.screen()->height_in_pixels}) {
|
|
|
|
// Check if the reloading has been disabled by the user
|
2016-12-30 17:32:05 -05:00
|
|
|
if (!m_conf.get("settings", "screenchange-reload", false)) {
|
2016-11-26 18:46:41 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
m_proxy = winspec(m_connection)
|
|
|
|
<< cw_size(1U, 1U)
|
|
|
|
<< cw_pos(-1, -1)
|
|
|
|
<< cw_parent(m_root)
|
|
|
|
<< cw_params_override_redirect(true)
|
|
|
|
<< cw_params_event_mask(XCB_EVENT_MASK_PROPERTY_CHANGE)
|
|
|
|
<< cw_flush(true);
|
|
|
|
// clang-format on
|
|
|
|
|
2016-12-22 19:05:36 -05:00
|
|
|
// Update the root windows event mask
|
|
|
|
auto attributes = m_connection.get_window_attributes(m_root);
|
|
|
|
auto root_mask = attributes->your_event_mask;
|
|
|
|
attributes->your_event_mask = attributes->your_event_mask | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
|
|
|
|
m_connection.change_window_attributes(m_root, XCB_CW_EVENT_MASK, &attributes->your_event_mask);
|
|
|
|
|
2016-11-26 18:46:41 -05:00
|
|
|
// Receive randr events
|
|
|
|
m_connection.randr().select_input(m_proxy, XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE);
|
|
|
|
|
|
|
|
// Create window used as event proxy
|
|
|
|
m_connection.map_window(m_proxy);
|
|
|
|
m_connection.flush();
|
|
|
|
|
|
|
|
// Wait until the proxy window has been mapped
|
|
|
|
using evt = xcb_map_notify_event_t;
|
2016-12-21 17:22:02 -05:00
|
|
|
m_connection.wait_for_response<evt, XCB_MAP_NOTIFY>([&](const evt* evt) -> bool { return evt->window == m_proxy; });
|
2016-12-22 19:05:36 -05:00
|
|
|
|
|
|
|
// Restore the root windows event mask
|
|
|
|
m_connection.change_window_attributes(m_root, XCB_CW_EVENT_MASK, &root_mask);
|
2016-11-26 18:46:41 -05:00
|
|
|
|
|
|
|
// Finally attach the sink the process randr events
|
2016-12-03 07:00:40 -05:00
|
|
|
m_connection.attach_sink(this, SINK_PRIORITY_SCREEN);
|
2016-11-26 18:46:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Deconstruct screen instance
|
|
|
|
*/
|
|
|
|
screen::~screen() {
|
2016-12-03 07:00:40 -05:00
|
|
|
m_connection.detach_sink(this, SINK_PRIORITY_SCREEN);
|
2016-11-26 18:46:41 -05:00
|
|
|
|
2016-12-01 02:41:49 -05:00
|
|
|
if (m_proxy != XCB_NONE) {
|
2016-11-26 18:46:41 -05:00
|
|
|
m_connection.destroy_window(m_proxy);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle XCB_RANDR_SCREEN_CHANGE_NOTIFY events
|
|
|
|
*
|
2021-09-11 08:20:57 -04:00
|
|
|
* If any of the monitors have changed we trigger a reload
|
2016-11-26 18:46:41 -05:00
|
|
|
*/
|
|
|
|
void screen::handle(const evt::randr_screen_change_notify& evt) {
|
2016-12-03 10:44:31 -05:00
|
|
|
if (m_sigraised || evt->request_window != m_proxy) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto screen = m_connection.screen(true);
|
|
|
|
auto changed = false;
|
|
|
|
|
2019-06-30 09:34:18 -04:00
|
|
|
// We need to reload if the screen size changed as well
|
2016-12-03 10:44:31 -05:00
|
|
|
if (screen->width_in_pixels != m_size.w || screen->height_in_pixels != m_size.h) {
|
|
|
|
changed = true;
|
|
|
|
} else {
|
2019-06-30 09:34:18 -04:00
|
|
|
changed = have_monitors_changed();
|
2016-12-03 10:44:31 -05:00
|
|
|
}
|
|
|
|
|
2019-06-30 09:34:18 -04:00
|
|
|
if (changed) {
|
2020-04-21 18:14:02 -04:00
|
|
|
m_log.notice("randr_screen_change_notify (%ux%u)... reloading", evt->width, evt->height);
|
2019-06-30 09:34:18 -04:00
|
|
|
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);
|
|
|
|
|
2021-09-13 14:54:00 -04:00
|
|
|
if (monitors.size() != m_monitors.size()) {
|
2019-06-30 09:34:18 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto m : m_monitors) {
|
2021-09-13 14:54:00 -04:00
|
|
|
auto it =
|
|
|
|
std::find_if(monitors.begin(), monitors.end(), [m](auto& monitor) -> bool { return m->equals(*monitor); });
|
2019-06-30 09:34:18 -04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
2021-09-13 14:54:00 -04:00
|
|
|
if (it == monitors.end()) {
|
2019-06-30 09:34:18 -04:00
|
|
|
return true;
|
|
|
|
}
|
2016-11-26 18:46:41 -05:00
|
|
|
}
|
2016-12-03 16:54:58 -05:00
|
|
|
|
2019-06-30 09:34:18 -04:00
|
|
|
return false;
|
2016-11-26 18:46:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
POLYBAR_NS_END
|