fix: Handle X events before polling for IO (#2820)

* Use m_connection.poll_for_event

* fix: Handle X events before polling for IO

Polling the XCB file descriptor for X events doesn't detect events that
are already in XCB's event queue but not yet handled.

If this happens, the eventloop polls for IO and the queued events wait
until another event arrives, causing some desyncs in the bar.

This can easily happen if something (e.g. a click event) triggers some
xcb calls, which as a consequence buffer some incoming events.

We "fix" this by adding a libuv prepare handle (which runs right before
polling for IO) that processes pending X events.
This commit is contained in:
Patrick Ziegler
2022-09-13 14:21:36 +02:00
committed by GitHub
parent 053a7eb2d8
commit 1d4e30c4be
4 changed files with 50 additions and 7 deletions

View File

@ -171,7 +171,7 @@ void controller::conn_cb() {
}
shared_ptr<xcb_generic_event_t> evt{};
while ((evt = shared_ptr<xcb_generic_event_t>(xcb_poll_for_event(m_connection), free)) != nullptr) {
while ((evt = m_connection.poll_for_event()) != nullptr) {
try {
m_connection.dispatch_event(evt);
} catch (xpp::connection_error& err) {
@ -247,14 +247,25 @@ void controller::read_events(bool confwatch) {
m_log.info("Entering event loop (thread-id=%lu)", this_thread::get_id());
try {
auto& poll_handle = m_loop.handle<PollHandle>(m_connection.get_file_descriptor());
poll_handle.start(
auto& x_poll_handle = m_loop.handle<PollHandle>(m_connection.get_file_descriptor());
x_poll_handle.start(
UV_READABLE, [this](const auto&) { conn_cb(); },
[this](const auto& e) {
m_log.err("libuv error while polling X connection: "s + uv_strerror(e.status));
stop(false);
});
auto& x_prepare_handle = m_loop.handle<PrepareHandle>();
x_prepare_handle.start([this]() {
/*
* We have to also handle events in the prepare handle (which runs right
* before polling for IO) to process any already queued X events which
* wouldn't trigger the uv_poll handle.
*/
conn_cb();
m_connection.flush();
});
for (auto s : {SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGALRM}) {
auto& signal_handle = m_loop.handle<SignalHandle>();
signal_handle.start(s, [this](const auto& e) { signal_handler(e.signum); });