feat: Reload on XCB_RANDR_SCREEN_CHANGE_NOTIFY
This commit is contained in:
parent
340add5c40
commit
4852f2817c
@ -14,13 +14,14 @@
|
|||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
// fwd
|
// fwd
|
||||||
|
class screen;
|
||||||
class tray_manager;
|
class tray_manager;
|
||||||
class logger;
|
class logger;
|
||||||
class renderer;
|
class renderer;
|
||||||
|
|
||||||
class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::property_notify> {
|
class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::property_notify> {
|
||||||
public:
|
public:
|
||||||
explicit bar(connection& conn, const config& config, const logger& logger, unique_ptr<tray_manager> tray_manager);
|
explicit bar(connection& conn, const config& config, const logger& logger, unique_ptr<screen> screen, unique_ptr<tray_manager> tray_manager);
|
||||||
~bar();
|
~bar();
|
||||||
|
|
||||||
void bootstrap(bool nodraw = false);
|
void bootstrap(bool nodraw = false);
|
||||||
@ -45,12 +46,11 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
|
|||||||
connection& m_connection;
|
connection& m_connection;
|
||||||
const config& m_conf;
|
const config& m_conf;
|
||||||
const logger& m_log;
|
const logger& m_log;
|
||||||
|
unique_ptr<screen> m_screen;
|
||||||
unique_ptr<tray_manager> m_tray;
|
unique_ptr<tray_manager> m_tray;
|
||||||
unique_ptr<renderer> m_renderer;
|
unique_ptr<renderer> m_renderer;
|
||||||
|
|
||||||
xcb_screen_t* m_screen;
|
|
||||||
xcb_window_t m_window;
|
xcb_window_t m_window;
|
||||||
|
|
||||||
bar_settings m_opts;
|
bar_settings m_opts;
|
||||||
|
|
||||||
alignment m_trayalign{alignment::NONE};
|
alignment m_trayalign{alignment::NONE};
|
||||||
|
45
include/components/screen.hpp
Normal file
45
include/components/screen.hpp
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
#include "components/types.hpp"
|
||||||
|
#include "x11/events.hpp"
|
||||||
|
#include "x11/window.hpp"
|
||||||
|
|
||||||
|
POLYBAR_NS
|
||||||
|
|
||||||
|
// fwd
|
||||||
|
class config;
|
||||||
|
class logger;
|
||||||
|
class connection;
|
||||||
|
|
||||||
|
class screen : public xpp::event::sink<evt::randr_screen_change_notify> {
|
||||||
|
public:
|
||||||
|
explicit screen(connection& conn, const logger& logger, const config& conf);
|
||||||
|
~screen();
|
||||||
|
|
||||||
|
struct size size() const {
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
xcb_window_t root() const {
|
||||||
|
return m_root;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void handle(const evt::randr_screen_change_notify& evt);
|
||||||
|
|
||||||
|
private:
|
||||||
|
connection& m_connection;
|
||||||
|
const logger& m_log;
|
||||||
|
const config& m_conf;
|
||||||
|
|
||||||
|
xcb_window_t m_root;
|
||||||
|
xcb_window_t m_proxy;
|
||||||
|
|
||||||
|
struct size m_size{0U, 0U};
|
||||||
|
bool m_sigraised{false};
|
||||||
|
};
|
||||||
|
|
||||||
|
di::injector<unique_ptr<screen>> configure_screen();
|
||||||
|
|
||||||
|
POLYBAR_NS_END
|
@ -69,6 +69,30 @@ class connection : public xpp_connection {
|
|||||||
|
|
||||||
virtual ~connection() {}
|
virtual ~connection() {}
|
||||||
|
|
||||||
|
template <typename Event, uint32_t ResponseType>
|
||||||
|
void wait_for_response(function<bool(const Event&)> check_event) {
|
||||||
|
auto fd = get_file_descriptor();
|
||||||
|
fd_set fds;
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(fd, &fds);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (select(fd + 1, &fds, nullptr, nullptr, nullptr) > 0) {
|
||||||
|
shared_ptr<xcb_generic_event_t> evt;
|
||||||
|
|
||||||
|
if ((evt = poll_for_event()) && evt->response_type == ResponseType) {
|
||||||
|
if (check_event(reinterpret_cast<const xcb_map_notify_event_t&>(*(evt.get())))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connection_has_error()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void preload_atoms();
|
void preload_atoms();
|
||||||
|
|
||||||
void query_extensions();
|
void query_extensions();
|
||||||
@ -77,6 +101,9 @@ class connection : public xpp_connection {
|
|||||||
|
|
||||||
xcb_screen_t* screen();
|
xcb_screen_t* screen();
|
||||||
|
|
||||||
|
void ensure_event_mask(xcb_window_t win, uint32_t event);
|
||||||
|
void clear_event_mask(xcb_window_t win);
|
||||||
|
|
||||||
shared_ptr<xcb_client_message_event_t> make_client_message(xcb_atom_t type, xcb_window_t target) const;
|
shared_ptr<xcb_client_message_event_t> make_client_message(xcb_atom_t type, xcb_window_t target) const;
|
||||||
|
|
||||||
void send_client_message(const shared_ptr<xcb_client_message_event_t>& message, xcb_window_t target,
|
void send_client_message(const shared_ptr<xcb_client_message_event_t>& message, xcb_window_t target,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xcb_aux.h>
|
#include <xcb/xcb_aux.h>
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "components/bar.hpp"
|
#include "components/bar.hpp"
|
||||||
#include "components/parser.hpp"
|
#include "components/parser.hpp"
|
||||||
#include "components/renderer.hpp"
|
#include "components/renderer.hpp"
|
||||||
|
#include "components/screen.hpp"
|
||||||
#include "components/signals.hpp"
|
#include "components/signals.hpp"
|
||||||
#include "utils/bspwm.hpp"
|
#include "utils/bspwm.hpp"
|
||||||
#include "utils/color.hpp"
|
#include "utils/color.hpp"
|
||||||
@ -34,6 +35,7 @@ di::injector<unique_ptr<bar>> configure_bar() {
|
|||||||
configure_connection(),
|
configure_connection(),
|
||||||
configure_config(),
|
configure_config(),
|
||||||
configure_logger(),
|
configure_logger(),
|
||||||
|
configure_screen(),
|
||||||
configure_tray_manager());
|
configure_tray_manager());
|
||||||
// clang-format on
|
// clang-format on
|
||||||
}
|
}
|
||||||
@ -41,12 +43,9 @@ di::injector<unique_ptr<bar>> configure_bar() {
|
|||||||
/**
|
/**
|
||||||
* Construct bar instance
|
* Construct bar instance
|
||||||
*/
|
*/
|
||||||
bar::bar(connection& conn, const config& config, const logger& logger, unique_ptr<tray_manager> tray_manager)
|
bar::bar(connection& conn, const config& config, const logger& logger, unique_ptr<screen> screen,
|
||||||
: m_connection(conn)
|
unique_ptr<tray_manager> tray_manager)
|
||||||
, m_conf(config)
|
: m_connection(conn), m_conf(config), m_log(logger), m_screen(move(screen)), m_tray(move(tray_manager)) {}
|
||||||
, m_log(logger)
|
|
||||||
, m_tray(forward<decltype(tray_manager)>(tray_manager))
|
|
||||||
, m_screen(conn.screen()) {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleanup signal handlers and destroy the bar window
|
* Cleanup signal handlers and destroy the bar window
|
||||||
@ -465,7 +464,7 @@ void bar::setup_monitor() {
|
|||||||
m_log.trace("bar: Create monitor from matching X RandR output");
|
m_log.trace("bar: Create monitor from matching X RandR output");
|
||||||
|
|
||||||
auto strict = m_conf.get<bool>(m_conf.bar_section(), "monitor-strict", false);
|
auto strict = m_conf.get<bool>(m_conf.bar_section(), "monitor-strict", false);
|
||||||
auto monitors = randr_util::get_monitors(m_connection, m_screen->root, strict);
|
auto monitors = randr_util::get_monitors(m_connection, m_screen->root(), strict);
|
||||||
|
|
||||||
if (monitors.empty()) {
|
if (monitors.empty()) {
|
||||||
throw application_error("No monitors found");
|
throw application_error("No monitors found");
|
||||||
@ -534,7 +533,7 @@ void bar::restack_window() {
|
|||||||
* and moving it to the correct position
|
* and moving it to the correct position
|
||||||
*/
|
*/
|
||||||
void bar::reconfigure_window() {
|
void bar::reconfigure_window() {
|
||||||
auto geom = m_connection.get_geometry(m_screen->root);
|
auto geom = m_connection.get_geometry(m_screen->root());
|
||||||
auto w = m_opts.size.w + m_opts.offset.x;
|
auto w = m_opts.size.w + m_opts.offset.x;
|
||||||
auto h = m_opts.size.h + m_opts.offset.y;
|
auto h = m_opts.size.h + m_opts.offset.y;
|
||||||
auto x = m_opts.pos.x;
|
auto x = m_opts.pos.x;
|
||||||
|
86
src/components/screen.cpp
Normal file
86
src/components/screen.cpp
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
#include <csignal>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "components/config.hpp"
|
||||||
|
#include "components/logger.hpp"
|
||||||
|
#include "components/screen.hpp"
|
||||||
|
#include "components/types.hpp"
|
||||||
|
#include "x11/connection.hpp"
|
||||||
|
#include "x11/randr.hpp"
|
||||||
|
#include "x11/winspec.hpp"
|
||||||
|
|
||||||
|
POLYBAR_NS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure injection module
|
||||||
|
*/
|
||||||
|
di::injector<unique_ptr<screen>> configure_screen() {
|
||||||
|
return di::make_injector(configure_connection(), configure_logger(), configure_config());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct screen instance
|
||||||
|
*/
|
||||||
|
screen::screen(connection& conn, const logger& logger, const config& conf)
|
||||||
|
: m_connection(conn)
|
||||||
|
, m_log(logger)
|
||||||
|
, m_conf(conf)
|
||||||
|
, m_root(conn.root())
|
||||||
|
, 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<bool>("settings", "screenchange-reload", false)) {
|
||||||
|
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
|
||||||
|
|
||||||
|
// Receive randr events
|
||||||
|
m_connection.randr().select_input(m_proxy, XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE);
|
||||||
|
m_connection.ensure_event_mask(m_root, XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
m_connection.wait_for_response<evt, XCB_MAP_NOTIFY>([&](const evt& evt) -> bool { return evt.window == m_proxy; });
|
||||||
|
m_connection.clear_event_mask(m_root);
|
||||||
|
|
||||||
|
// Finally attach the sink the process randr events
|
||||||
|
m_connection.attach_sink(this, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deconstruct screen instance
|
||||||
|
*/
|
||||||
|
screen::~screen() {
|
||||||
|
m_connection.detach_sink(this, 1);
|
||||||
|
|
||||||
|
if (m_proxy) {
|
||||||
|
m_connection.destroy_window(m_proxy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle XCB_RANDR_SCREEN_CHANGE_NOTIFY events
|
||||||
|
*
|
||||||
|
* If the screen dimensions 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) {
|
||||||
|
m_log.warn("randr_screen_change_notify (%ux%u)... reloading", evt->width, evt->height);
|
||||||
|
m_sigraised = true;
|
||||||
|
kill(getpid(), SIGUSR1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
POLYBAR_NS_END
|
@ -101,6 +101,26 @@ xcb_screen_t* connection::screen() {
|
|||||||
return m_screen;
|
return m_screen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add given event to the event mask unless already added
|
||||||
|
*/
|
||||||
|
void connection::ensure_event_mask(xcb_window_t win, uint32_t event) {
|
||||||
|
auto attributes = get_window_attributes(win);
|
||||||
|
uint32_t mask{attributes->your_event_mask | event};
|
||||||
|
|
||||||
|
if (!(attributes->your_event_mask & event)) {
|
||||||
|
change_window_attributes(win, XCB_CW_EVENT_MASK, &mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear event mask for the given window
|
||||||
|
*/
|
||||||
|
void connection::clear_event_mask(xcb_window_t win) {
|
||||||
|
uint32_t mask{XCB_EVENT_MASK_NO_EVENT};
|
||||||
|
change_window_attributes(win, XCB_CW_EVENT_MASK, &mask);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an instance of shared_ptr<xcb_client_message_event_t>
|
* Creates an instance of shared_ptr<xcb_client_message_event_t>
|
||||||
*/
|
*/
|
||||||
|
@ -41,12 +41,7 @@ window window::change_event_mask(uint32_t mask) {
|
|||||||
* Add given event to the event mask unless already added
|
* Add given event to the event mask unless already added
|
||||||
*/
|
*/
|
||||||
window window::ensure_event_mask(uint32_t event) {
|
window window::ensure_event_mask(uint32_t event) {
|
||||||
auto attributes = get_attributes();
|
connection().ensure_event_mask(*this, event);
|
||||||
|
|
||||||
if ((attributes->your_event_mask & event) != event) {
|
|
||||||
change_event_mask(attributes->your_event_mask | event);
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user