| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/events/platform/x11/x11_event_source.h" | 5 #include "ui/events/platform/x11/x11_event_source.h" |
| 6 | 6 |
| 7 #include <X11/Xatom.h> | 7 #include <X11/Xatom.h> |
| 8 #include <X11/XKBlib.h> | 8 #include <X11/XKBlib.h> |
| 9 #include <X11/Xlib.h> | 9 #include <X11/Xlib.h> |
| 10 #include <X11/Xlib-xcb.h> |
| 11 #include <xcb/xcbext.h> |
| 10 | 12 |
| 11 #include "base/logging.h" | 13 #include "base/logging.h" |
| 12 #include "base/metrics/histogram_macros.h" | 14 #include "base/metrics/histogram_macros.h" |
| 13 #include "ui/base/x/x11_window_event_manager.h" | 15 #include "ui/base/x/x11_window_event_manager.h" |
| 14 #include "ui/events/devices/x11/device_data_manager_x11.h" | 16 #include "ui/events/devices/x11/device_data_manager_x11.h" |
| 15 #include "ui/events/devices/x11/touch_factory_x11.h" | 17 #include "ui/events/devices/x11/touch_factory_x11.h" |
| 16 #include "ui/events/event_utils.h" | 18 #include "ui/events/event_utils.h" |
| 17 #include "ui/events/platform/platform_event_dispatcher.h" | 19 #include "ui/events/platform/platform_event_dispatcher.h" |
| 18 #include "ui/events/platform/x11/x11_hotplug_event_handler.h" | 20 #include "ui/events/platform/x11/x11_hotplug_event_handler.h" |
| 19 | 21 |
| 22 #define XLIB_SEQUENCE_COMPARE(a, op, b) (((int64_t)(a) - (int64_t)(b)) op 0) |
| 23 |
| 20 namespace ui { | 24 namespace ui { |
| 21 | 25 |
| 22 namespace { | 26 namespace { |
| 23 | 27 |
| 24 bool InitializeXkb(XDisplay* display) { | 28 bool InitializeXkb(XDisplay* display) { |
| 25 if (!display) | 29 if (!display) |
| 26 return false; | 30 return false; |
| 27 | 31 |
| 28 int opcode, event, error; | 32 int opcode, event, error; |
| 29 int major = XkbMajorVersion; | 33 int major = XkbMajorVersion; |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 85 XEvent* event, | 89 XEvent* event, |
| 86 XPointer arg) { | 90 XPointer arg) { |
| 87 return event->type == PropertyNotify && | 91 return event->type == PropertyNotify && |
| 88 event->xproperty.window == *reinterpret_cast<Window*>(arg); | 92 event->xproperty.window == *reinterpret_cast<Window*>(arg); |
| 89 } | 93 } |
| 90 | 94 |
| 91 } // namespace | 95 } // namespace |
| 92 | 96 |
| 93 X11EventSource* X11EventSource::instance_ = nullptr; | 97 X11EventSource* X11EventSource::instance_ = nullptr; |
| 94 | 98 |
| 99 X11EventSource::Request::Request(uint32_t sequence) |
| 100 : sequence_(sequence), weak_factory_(this) {} |
| 101 X11EventSource::Request::~Request() {} |
| 102 |
| 103 base::WeakPtr<X11EventSource::Request> X11EventSource::Request::GetWeakPtr() { |
| 104 return weak_factory_.GetWeakPtr(); |
| 105 } |
| 106 |
| 95 X11EventSource::X11EventSource(X11EventSourceDelegate* delegate, | 107 X11EventSource::X11EventSource(X11EventSourceDelegate* delegate, |
| 96 XDisplay* display) | 108 XDisplay* display) |
| 97 : delegate_(delegate), | 109 : delegate_(delegate), |
| 98 display_(display), | 110 display_(display), |
| 111 connection_(XGetXCBConnection(display_)), |
| 99 dummy_initialized_(false), | 112 dummy_initialized_(false), |
| 113 next_reply_(nullptr), |
| 114 next_error_(nullptr), |
| 100 continue_stream_(true) { | 115 continue_stream_(true) { |
| 101 DCHECK(!instance_); | 116 DCHECK(!instance_); |
| 102 instance_ = this; | 117 instance_ = this; |
| 103 | 118 |
| 104 DCHECK(delegate_); | 119 DCHECK(delegate_); |
| 105 DCHECK(display_); | 120 DCHECK(display_); |
| 106 DeviceDataManagerX11::CreateInstance(); | 121 DeviceDataManagerX11::CreateInstance(); |
| 107 InitializeXkb(display_); | 122 InitializeXkb(display_); |
| 108 } | 123 } |
| 109 | 124 |
| 110 X11EventSource::~X11EventSource() { | 125 X11EventSource::~X11EventSource() { |
| 111 DCHECK_EQ(this, instance_); | 126 DCHECK_EQ(this, instance_); |
| 127 DCHECK(!next_reply_ && !next_error_); |
| 112 instance_ = nullptr; | 128 instance_ = nullptr; |
| 113 if (dummy_initialized_) | 129 if (dummy_initialized_) |
| 114 XDestroyWindow(display_, dummy_window_); | 130 XDestroyWindow(display_, dummy_window_); |
| 115 } | 131 } |
| 116 | 132 |
| 117 bool X11EventSource::HasInstance() { | 133 bool X11EventSource::HasInstance() { |
| 118 return instance_; | 134 return instance_; |
| 119 } | 135 } |
| 120 | 136 |
| 121 // static | 137 // static |
| 122 X11EventSource* X11EventSource::GetInstance() { | 138 X11EventSource* X11EventSource::GetInstance() { |
| 123 DCHECK(instance_); | 139 DCHECK(instance_); |
| 124 return instance_; | 140 return instance_; |
| 125 } | 141 } |
| 126 | 142 |
| 127 //////////////////////////////////////////////////////////////////////////////// | 143 //////////////////////////////////////////////////////////////////////////////// |
| 128 // X11EventSource, public | 144 // X11EventSource, public |
| 129 | 145 |
| 130 void X11EventSource::DispatchXEvents() { | 146 void X11EventSource::DispatchXEvents() { |
| 131 DCHECK(display_); | 147 DCHECK(display_); |
| 132 // Handle all pending events. | 148 // Handle all pending events. |
| 133 // It may be useful to eventually align this event dispatch with vsync, but | 149 // It may be useful to eventually align this event dispatch with vsync, but |
| 134 // not yet. | 150 // not yet. |
| 135 continue_stream_ = true; | 151 continue_stream_ = true; |
| 136 while (XPending(display_) && continue_stream_) { | 152 |
| 137 XEvent xevent; | 153 // Read all available data. |
| 138 XNextEvent(display_, &xevent); | 154 XEventsQueued(display_, QueuedAfterReading); |
| 139 ExtractCookieDataDispatchEvent(&xevent); | 155 |
| 156 while (HasNextReply() && HasNextEvent() && continue_stream_) { |
| 157 if (XLIB_SEQUENCE_COMPARE(NextReplySequence(), <=, NextEventSequence())) |
| 158 ProcessNextReply(); |
| 159 else |
| 160 ProcessNextEvent(); |
| 140 } | 161 } |
| 162 |
| 163 while (HasNextReply() && continue_stream_) |
| 164 ProcessNextReply(); |
| 165 |
| 166 while (HasNextEvent() && continue_stream_) |
| 167 ProcessNextEvent(); |
| 141 } | 168 } |
| 142 | 169 |
| 143 void X11EventSource::DispatchXEventNow(XEvent* event) { | 170 void X11EventSource::DispatchXEventNow(XEvent* event) { |
| 144 ExtractCookieDataDispatchEvent(event); | 171 ExtractCookieDataDispatchEvent(event); |
| 145 } | 172 } |
| 146 | 173 |
| 147 void X11EventSource::BlockUntilWindowMapped(XID window) { | 174 void X11EventSource::BlockUntilWindowMapped(XID window) { |
| 148 BlockOnWindowStructureEvent(window, MapNotify); | 175 BlockOnWindowStructureEvent(window, MapNotify); |
| 149 } | 176 } |
| 150 | 177 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 if (!ui::TouchFactory::GetInstance()->ShouldProcessXI2Event(event)) | 240 if (!ui::TouchFactory::GetInstance()->ShouldProcessXI2Event(event)) |
| 214 break; | 241 break; |
| 215 is_valid_event = true; | 242 is_valid_event = true; |
| 216 } | 243 } |
| 217 | 244 |
| 218 if (is_valid_event) | 245 if (is_valid_event) |
| 219 return ui::EventSystemLocationFromNative(event); | 246 return ui::EventSystemLocationFromNative(event); |
| 220 return base::nullopt; | 247 return base::nullopt; |
| 221 } | 248 } |
| 222 | 249 |
| 250 void X11EventSource::EnqueueRequest(Request* request) { |
| 251 DCHECK(request); |
| 252 request_queue_.emplace_back(request); |
| 253 request->it_ = --request_queue_.end(); |
| 254 } |
| 255 |
| 256 void X11EventSource::DiscardRequest(Request* request) { |
| 257 DCHECK(connection_); |
| 258 if ((next_reply_ || next_error_) && request == request_queue_.front().get()) { |
| 259 free(next_reply_); |
| 260 free(next_error_); |
| 261 next_reply_ = nullptr; |
| 262 next_error_ = nullptr; |
| 263 } else { |
| 264 xcb_discard_reply(connection_, request->sequence()); |
| 265 } |
| 266 request_queue_.erase(request->it_); |
| 267 } |
| 268 |
| 269 bool X11EventSource::DispatchRequestNow(Request* request) { |
| 270 DCHECK(connection_); |
| 271 |
| 272 bool success = false; |
| 273 if ((next_reply_ || next_error_) && request == request_queue_.front().get()) { |
| 274 success = !next_error_; |
| 275 ProcessNextReply(); |
| 276 } else { |
| 277 xcb_generic_error_t* error = nullptr; |
| 278 void* reply = xcb_wait_for_reply(connection_, request->sequence(), &error); |
| 279 success = !error; |
| 280 ProcessRequest(request, reinterpret_cast<xcb_generic_reply_t*>(reply), |
| 281 error); |
| 282 free(reply); |
| 283 free(error); |
| 284 } |
| 285 return success; |
| 286 } |
| 287 |
| 223 //////////////////////////////////////////////////////////////////////////////// | 288 //////////////////////////////////////////////////////////////////////////////// |
| 224 // X11EventSource, protected | 289 // X11EventSource, protected |
| 225 | 290 |
| 226 void X11EventSource::ExtractCookieDataDispatchEvent(XEvent* xevent) { | 291 void X11EventSource::ExtractCookieDataDispatchEvent(XEvent* xevent) { |
| 227 bool have_cookie = false; | 292 bool have_cookie = false; |
| 228 if (xevent->type == GenericEvent && | 293 if (xevent->type == GenericEvent && |
| 229 XGetEventData(xevent->xgeneric.display, &xevent->xcookie)) { | 294 XGetEventData(xevent->xgeneric.display, &xevent->xcookie)) { |
| 230 have_cookie = true; | 295 have_cookie = true; |
| 231 } | 296 } |
| 232 | 297 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 void X11EventSource::BlockOnWindowStructureEvent(XID window, int type) { | 341 void X11EventSource::BlockOnWindowStructureEvent(XID window, int type) { |
| 277 XEvent event; | 342 XEvent event; |
| 278 do { | 343 do { |
| 279 // Block until there's a StructureNotify event of |type| on |window|. Then | 344 // Block until there's a StructureNotify event of |type| on |window|. Then |
| 280 // remove it from the queue and stuff it in |event|. | 345 // remove it from the queue and stuff it in |event|. |
| 281 XWindowEvent(display_, window, StructureNotifyMask, &event); | 346 XWindowEvent(display_, window, StructureNotifyMask, &event); |
| 282 ExtractCookieDataDispatchEvent(&event); | 347 ExtractCookieDataDispatchEvent(&event); |
| 283 } while (event.type != type); | 348 } while (event.type != type); |
| 284 } | 349 } |
| 285 | 350 |
| 351 bool X11EventSource::HasNextReply() { |
| 352 if (request_queue_.empty() || xcb_connection_has_error(connection_)) |
| 353 return false; |
| 354 if (next_reply_ || next_error_) |
| 355 return true; |
| 356 |
| 357 return xcb_poll_for_reply(connection_, request_queue_.front()->sequence(), |
| 358 &next_reply_, &next_error_); |
| 359 } |
| 360 |
| 361 uint32_t X11EventSource::NextReplySequence() { |
| 362 DCHECK(HasNextReply()); |
| 363 return request_queue_.front()->sequence(); |
| 364 } |
| 365 |
| 366 void X11EventSource::ProcessRequest(Request* request, |
| 367 xcb_generic_reply_t* reply, |
| 368 xcb_generic_error_t* error) { |
| 369 base::WeakPtr<Request> weak_ptr = request->GetWeakPtr(); |
| 370 request->OnReply(reply, error); |
| 371 // OnReply() may have chosen to discard this request already. |
| 372 if (weak_ptr) |
| 373 request_queue_.erase(request->it_); |
| 374 } |
| 375 |
| 376 void X11EventSource::ProcessNextReply() { |
| 377 DCHECK(HasNextReply()); |
| 378 |
| 379 ProcessRequest(request_queue_.front().get(), |
| 380 reinterpret_cast<xcb_generic_reply_t*>(next_reply_), |
| 381 next_error_); |
| 382 |
| 383 free(next_reply_); |
| 384 free(next_error_); |
| 385 next_reply_ = nullptr; |
| 386 next_error_ = nullptr; |
| 387 } |
| 388 |
| 389 bool X11EventSource::HasNextEvent() { |
| 390 return XEventsQueued(display_, QueuedAlready); |
| 391 } |
| 392 |
| 393 uint32_t X11EventSource::NextEventSequence() { |
| 394 DCHECK(HasNextEvent()); |
| 395 XEvent event; |
| 396 XPeekEvent(display_, &event); |
| 397 return event.xany.serial; |
| 398 } |
| 399 |
| 400 void X11EventSource::ProcessNextEvent() { |
| 401 DCHECK(HasNextEvent()); |
| 402 XEvent event; |
| 403 XNextEvent(display_, &event); |
| 404 ExtractCookieDataDispatchEvent(&event); |
| 405 } |
| 406 |
| 286 void X11EventSource::StopCurrentEventStream() { | 407 void X11EventSource::StopCurrentEventStream() { |
| 287 continue_stream_ = false; | 408 continue_stream_ = false; |
| 288 } | 409 } |
| 289 | 410 |
| 290 void X11EventSource::OnDispatcherListChanged() { | 411 void X11EventSource::OnDispatcherListChanged() { |
| 291 if (!hotplug_event_handler_) { | 412 if (!hotplug_event_handler_) { |
| 292 hotplug_event_handler_.reset(new X11HotplugEventHandler()); | 413 hotplug_event_handler_.reset(new X11HotplugEventHandler()); |
| 293 // Force the initial device query to have an update list of active devices. | 414 // Force the initial device query to have an update list of active devices. |
| 294 hotplug_event_handler_->OnHotplugEvent(); | 415 hotplug_event_handler_->OnHotplugEvent(); |
| 295 } | 416 } |
| 296 } | 417 } |
| 297 | 418 |
| 298 } // namespace ui | 419 } // namespace ui |
| OLD | NEW |