Replace wait_for_response with handle callback

The poll-loop could in theory swallow events which would not be seen by
the main eventloop
This commit is contained in:
patrick96 2022-11-30 15:05:34 +01:00
parent aadd4ce1c8
commit 65279883c3
No known key found for this signature in database
GPG Key ID: 521E5E03AEBCA1A7
3 changed files with 86 additions and 99 deletions

View File

@ -16,7 +16,7 @@ class logger;
class connection;
class signal_emitter;
class screen : public xpp::event::sink<evt::randr_screen_change_notify> {
class screen : public xpp::event::sink<evt::map_notify, evt::randr_screen_change_notify> {
public:
using make_type = unique_ptr<screen>;
static make_type make();
@ -25,6 +25,7 @@ class screen : public xpp::event::sink<evt::randr_screen_change_notify> {
~screen();
protected:
void handle(const evt::map_notify& evt) override;
void handle(const evt::randr_screen_change_notify& evt) override;
private:
@ -42,6 +43,12 @@ class screen : public xpp::event::sink<evt::randr_screen_change_notify> {
};
bool m_sigraised{false};
/**
* Original event mask on the root window.
* Used to restore event mask after the proxy window is mapped.
*/
uint32_t m_root_mask{0};
bool have_monitors_changed() const;
};

View File

@ -129,27 +129,6 @@ class connection : public detail::connection_base<connection&, XPP_EXTENSION_LIS
void dispatch_event(const shared_ptr<xcb_generic_event_t>& evt) const;
template <typename Event, unsigned int ResponseType>
void wait_for_response(function<bool(const Event*)> check_event) {
int fd = get_file_descriptor();
shared_ptr<xcb_generic_event_t> evt{};
while (!connection_has_error()) {
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
if (!select(fd + 1, &fds, nullptr, nullptr, nullptr)) {
continue;
} else if ((evt = shared_ptr<xcb_generic_event_t>(xcb_poll_for_event(*this), free)) == nullptr) {
continue;
} else if (evt->response_type != ResponseType) {
continue;
} else if (check_event(reinterpret_cast<const Event*>(&*evt))) {
break;
}
}
}
template <typename Sink>
void attach_sink(Sink&& sink, registry::priority prio = 0) {
m_registry.attach(prio, forward<Sink>(sink));

View File

@ -54,27 +54,19 @@ screen::screen(connection& conn, signal_emitter& emitter, const logger& logger,
// Update the root windows event mask
auto attributes = m_connection.get_window_attributes(m_root);
auto root_mask = attributes->your_event_mask;
m_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);
// Receive randr events
m_connection.randr().select_input(m_proxy, XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE);
// Attach the sink to process randr events
m_connection.attach_sink(this, SINK_PRIORITY_SCREEN);
// Create window used as event proxy
m_connection.map_window(m_proxy);
m_connection.flush();
// Wait until the proxy window has been mapped
// TODO replace wait with a `handle` method
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; });
// Restore the root windows event mask
m_connection.change_window_attributes(m_root, XCB_CW_EVENT_MASK, &root_mask);
// Finally attach the sink the process randr events
m_connection.attach_sink(this, SINK_PRIORITY_SCREEN);
}
/**
@ -88,6 +80,15 @@ screen::~screen() {
}
}
void screen::handle(const evt::map_notify& evt) {
if (evt->window != m_proxy) {
return;
}
// Once the proxy window has been mapped, restore the original root window event mask.
m_connection.change_window_attributes(m_root, XCB_CW_EVENT_MASK, &m_root_mask);
}
/**
* Handle XCB_RANDR_SCREEN_CHANGE_NOTIFY events
*