| Index: ui/events/platform/x11/x11_event_source.cc
|
| diff --git a/ui/events/platform/x11/x11_event_source.cc b/ui/events/platform/x11/x11_event_source.cc
|
| index 1923e95fa14dbb8d97d401201129b4d8ad1dc355..afc77eb45f444cef61bc0dc99e7edda613ecbf94 100644
|
| --- a/ui/events/platform/x11/x11_event_source.cc
|
| +++ b/ui/events/platform/x11/x11_event_source.cc
|
| @@ -7,6 +7,8 @@
|
| #include <X11/Xatom.h>
|
| #include <X11/XKBlib.h>
|
| #include <X11/Xlib.h>
|
| +#include <X11/Xlib-xcb.h>
|
| +#include <xcb/xcbext.h>
|
|
|
| #include "base/logging.h"
|
| #include "base/metrics/histogram_macros.h"
|
| @@ -16,6 +18,8 @@
|
| #include "ui/events/platform/platform_event_dispatcher.h"
|
| #include "ui/events/platform/x11/x11_hotplug_event_handler.h"
|
|
|
| +#define XLIB_SEQUENCE_COMPARE(a, op, b) (((int64_t)(a) - (int64_t)(b)) op 0)
|
| +
|
| namespace ui {
|
|
|
| namespace {
|
| @@ -91,12 +95,18 @@ Bool IsPropertyNotifyForTimestamp(Display* display,
|
|
|
| X11EventSource* X11EventSource::instance_ = nullptr;
|
|
|
| +X11EventSource::Request::Request(uint32_t sequence) : sequence_(sequence) {}
|
| +X11EventSource::Request::~Request() {}
|
| +
|
| X11EventSource::X11EventSource(X11EventSourceDelegate* delegate,
|
| XDisplay* display)
|
| : delegate_(delegate),
|
| display_(display),
|
| + connection_(XGetXCBConnection(display_)),
|
| event_timestamp_(CurrentTime),
|
| dummy_initialized_(false),
|
| + next_reply_(nullptr),
|
| + next_error_(nullptr),
|
| continue_stream_(true) {
|
| DCHECK(!instance_);
|
| instance_ = this;
|
| @@ -109,6 +119,7 @@ X11EventSource::X11EventSource(X11EventSourceDelegate* delegate,
|
|
|
| X11EventSource::~X11EventSource() {
|
| DCHECK_EQ(this, instance_);
|
| + DCHECK(!next_reply_ && !next_error_);
|
| instance_ = nullptr;
|
| if (dummy_initialized_)
|
| XDestroyWindow(display_, dummy_window_);
|
| @@ -133,11 +144,22 @@ void X11EventSource::DispatchXEvents() {
|
| // It may be useful to eventually align this event dispatch with vsync, but
|
| // not yet.
|
| continue_stream_ = true;
|
| - while (XPending(display_) && continue_stream_) {
|
| - XEvent xevent;
|
| - XNextEvent(display_, &xevent);
|
| - ExtractCookieDataDispatchEvent(&xevent);
|
| +
|
| + // Read all available data.
|
| + XEventsQueued(display_, QueuedAfterReading);
|
| +
|
| + while (HasNextReply() && HasNextEvent() && continue_stream_) {
|
| + if (XLIB_SEQUENCE_COMPARE(NextReplySequence(), <=, NextEventSequence()))
|
| + ProcessNextReply();
|
| + else
|
| + ProcessNextEvent();
|
| }
|
| +
|
| + while (HasNextReply() && continue_stream_)
|
| + ProcessNextReply();
|
| +
|
| + while (HasNextEvent() && continue_stream_)
|
| + ProcessNextEvent();
|
| }
|
|
|
| void X11EventSource::DispatchXEventNow(XEvent* event) {
|
| @@ -189,6 +211,18 @@ Time X11EventSource::GetTimestamp() {
|
| return GetCurrentServerTime();
|
| }
|
|
|
| +void X11EventSource::EnqueueRequest(Request* request) {
|
| + DCHECK(request);
|
| + request_queue_.emplace_back(request);
|
| + request->it_ = --request_queue_.end();
|
| +}
|
| +
|
| +void X11EventSource::DiscardRequest(Request* request) {
|
| + DCHECK(connection_);
|
| + xcb_discard_reply(connection_, request->sequence());
|
| + request_queue_.erase(request->it_);
|
| +}
|
| +
|
| ////////////////////////////////////////////////////////////////////////////////
|
| // X11EventSource, protected
|
|
|
| @@ -252,6 +286,56 @@ void X11EventSource::BlockOnWindowStructureEvent(XID window, int type) {
|
| } while (event.type != type);
|
| }
|
|
|
| +bool X11EventSource::HasNextReply() {
|
| + if (request_queue_.empty() || xcb_connection_has_error(connection_))
|
| + return false;
|
| + if (next_reply_ || next_error_)
|
| + return true;
|
| +
|
| + return xcb_poll_for_reply(connection_, request_queue_.front()->sequence(),
|
| + &next_reply_, &next_error_);
|
| +}
|
| +
|
| +uint32_t X11EventSource::NextReplySequence() {
|
| + DCHECK(HasNextReply());
|
| + return request_queue_.front()->sequence();
|
| +}
|
| +
|
| +void X11EventSource::ProcessNextReply() {
|
| + DCHECK(HasNextReply());
|
| +
|
| + uint32_t sequence = request_queue_.front()->sequence();
|
| + request_queue_.front()->OnReply(
|
| + reinterpret_cast<xcb_generic_reply_t*>(next_reply_), next_error_);
|
| +
|
| + free(next_reply_);
|
| + free(next_error_);
|
| + next_reply_ = nullptr;
|
| + next_error_ = nullptr;
|
| +
|
| + // OnReply() may have already discarded this event.
|
| + if (!request_queue_.empty() && request_queue_.front()->sequence() == sequence)
|
| + request_queue_.pop_front();
|
| +}
|
| +
|
| +bool X11EventSource::HasNextEvent() {
|
| + return XEventsQueued(display_, QueuedAlready);
|
| +}
|
| +
|
| +uint32_t X11EventSource::NextEventSequence() {
|
| + DCHECK(HasNextEvent());
|
| + XEvent event;
|
| + XPeekEvent(display_, &event);
|
| + return event.xany.serial;
|
| +}
|
| +
|
| +void X11EventSource::ProcessNextEvent() {
|
| + DCHECK(HasNextEvent());
|
| + XEvent event;
|
| + XNextEvent(display_, &event);
|
| + ExtractCookieDataDispatchEvent(&event);
|
| +}
|
| +
|
| void X11EventSource::StopCurrentEventStream() {
|
| continue_stream_ = false;
|
| }
|
|
|