| 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/events/devices/x11/device_data_manager_x11.h" | 15 #include "ui/events/devices/x11/device_data_manager_x11.h" |
| 14 #include "ui/events/devices/x11/touch_factory_x11.h" | 16 #include "ui/events/devices/x11/touch_factory_x11.h" |
| 15 #include "ui/events/event_utils.h" | 17 #include "ui/events/event_utils.h" |
| 16 #include "ui/events/platform/platform_event_dispatcher.h" | 18 #include "ui/events/platform/platform_event_dispatcher.h" |
| 17 #include "ui/events/platform/x11/x11_hotplug_event_handler.h" | 19 #include "ui/events/platform/x11/x11_hotplug_event_handler.h" |
| 18 | 20 |
| 21 #define XLIB_SEQUENCE_COMPARE(a, op, b) (((int64_t)(a) - (int64_t)(b)) op 0) |
| 22 |
| 19 namespace ui { | 23 namespace ui { |
| 20 | 24 |
| 21 namespace { | 25 namespace { |
| 22 | 26 |
| 23 bool InitializeXkb(XDisplay* display) { | 27 bool InitializeXkb(XDisplay* display) { |
| 24 if (!display) | 28 if (!display) |
| 25 return false; | 29 return false; |
| 26 | 30 |
| 27 int opcode, event, error; | 31 int opcode, event, error; |
| 28 int major = XkbMajorVersion; | 32 int major = XkbMajorVersion; |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 84 XEvent* event, | 88 XEvent* event, |
| 85 XPointer arg) { | 89 XPointer arg) { |
| 86 return event->type == PropertyNotify && | 90 return event->type == PropertyNotify && |
| 87 event->xproperty.window == *reinterpret_cast<Window*>(arg); | 91 event->xproperty.window == *reinterpret_cast<Window*>(arg); |
| 88 } | 92 } |
| 89 | 93 |
| 90 } // namespace | 94 } // namespace |
| 91 | 95 |
| 92 X11EventSource* X11EventSource::instance_ = nullptr; | 96 X11EventSource* X11EventSource::instance_ = nullptr; |
| 93 | 97 |
| 98 X11EventSource::Request::Request(uint32_t sequence) : sequence_(sequence) {} |
| 99 X11EventSource::Request::~Request() {} |
| 100 |
| 94 X11EventSource::X11EventSource(X11EventSourceDelegate* delegate, | 101 X11EventSource::X11EventSource(X11EventSourceDelegate* delegate, |
| 95 XDisplay* display) | 102 XDisplay* display) |
| 96 : delegate_(delegate), | 103 : delegate_(delegate), |
| 97 display_(display), | 104 display_(display), |
| 105 connection_(XGetXCBConnection(display_)), |
| 98 event_timestamp_(CurrentTime), | 106 event_timestamp_(CurrentTime), |
| 99 dummy_initialized_(false), | 107 dummy_initialized_(false), |
| 108 next_reply_(nullptr), |
| 109 next_error_(nullptr), |
| 100 continue_stream_(true) { | 110 continue_stream_(true) { |
| 101 DCHECK(!instance_); | 111 DCHECK(!instance_); |
| 102 instance_ = this; | 112 instance_ = this; |
| 103 | 113 |
| 104 DCHECK(delegate_); | 114 DCHECK(delegate_); |
| 105 DCHECK(display_); | 115 DCHECK(display_); |
| 106 DeviceDataManagerX11::CreateInstance(); | 116 DeviceDataManagerX11::CreateInstance(); |
| 107 InitializeXkb(display_); | 117 InitializeXkb(display_); |
| 108 } | 118 } |
| 109 | 119 |
| 110 X11EventSource::~X11EventSource() { | 120 X11EventSource::~X11EventSource() { |
| 111 DCHECK_EQ(this, instance_); | 121 DCHECK_EQ(this, instance_); |
| 122 DCHECK(!next_reply_ && !next_error_); |
| 112 instance_ = nullptr; | 123 instance_ = nullptr; |
| 113 if (dummy_initialized_) | 124 if (dummy_initialized_) |
| 114 XDestroyWindow(display_, dummy_window_); | 125 XDestroyWindow(display_, dummy_window_); |
| 115 } | 126 } |
| 116 | 127 |
| 117 bool X11EventSource::HasInstance() { | 128 bool X11EventSource::HasInstance() { |
| 118 return instance_; | 129 return instance_; |
| 119 } | 130 } |
| 120 | 131 |
| 121 // static | 132 // static |
| 122 X11EventSource* X11EventSource::GetInstance() { | 133 X11EventSource* X11EventSource::GetInstance() { |
| 123 DCHECK(instance_); | 134 DCHECK(instance_); |
| 124 return instance_; | 135 return instance_; |
| 125 } | 136 } |
| 126 | 137 |
| 127 //////////////////////////////////////////////////////////////////////////////// | 138 //////////////////////////////////////////////////////////////////////////////// |
| 128 // X11EventSource, public | 139 // X11EventSource, public |
| 129 | 140 |
| 130 void X11EventSource::DispatchXEvents() { | 141 void X11EventSource::DispatchXEvents() { |
| 131 DCHECK(display_); | 142 DCHECK(display_); |
| 132 // Handle all pending events. | 143 // Handle all pending events. |
| 133 // It may be useful to eventually align this event dispatch with vsync, but | 144 // It may be useful to eventually align this event dispatch with vsync, but |
| 134 // not yet. | 145 // not yet. |
| 135 continue_stream_ = true; | 146 continue_stream_ = true; |
| 136 while (XPending(display_) && continue_stream_) { | 147 |
| 137 XEvent xevent; | 148 // Read all available data. |
| 138 XNextEvent(display_, &xevent); | 149 XEventsQueued(display_, QueuedAfterReading); |
| 139 ExtractCookieDataDispatchEvent(&xevent); | 150 |
| 151 while (HasNextReply() && HasNextEvent() && continue_stream_) { |
| 152 if (XLIB_SEQUENCE_COMPARE(NextReplySequence(), <=, NextEventSequence())) |
| 153 ProcessNextReply(); |
| 154 else |
| 155 ProcessNextEvent(); |
| 140 } | 156 } |
| 157 |
| 158 while (HasNextReply() && continue_stream_) |
| 159 ProcessNextReply(); |
| 160 |
| 161 while (HasNextEvent() && continue_stream_) |
| 162 ProcessNextEvent(); |
| 141 } | 163 } |
| 142 | 164 |
| 143 void X11EventSource::DispatchXEventNow(XEvent* event) { | 165 void X11EventSource::DispatchXEventNow(XEvent* event) { |
| 144 ExtractCookieDataDispatchEvent(event); | 166 ExtractCookieDataDispatchEvent(event); |
| 145 } | 167 } |
| 146 | 168 |
| 147 void X11EventSource::BlockUntilWindowMapped(XID window) { | 169 void X11EventSource::BlockUntilWindowMapped(XID window) { |
| 148 BlockOnWindowStructureEvent(window, MapNotify); | 170 BlockOnWindowStructureEvent(window, MapNotify); |
| 149 } | 171 } |
| 150 | 172 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 182 } | 204 } |
| 183 | 205 |
| 184 Time X11EventSource::GetTimestamp() { | 206 Time X11EventSource::GetTimestamp() { |
| 185 if (event_timestamp_ != CurrentTime) { | 207 if (event_timestamp_ != CurrentTime) { |
| 186 return event_timestamp_; | 208 return event_timestamp_; |
| 187 } | 209 } |
| 188 DVLOG(1) << "Making a round trip to get a recent server timestamp."; | 210 DVLOG(1) << "Making a round trip to get a recent server timestamp."; |
| 189 return GetCurrentServerTime(); | 211 return GetCurrentServerTime(); |
| 190 } | 212 } |
| 191 | 213 |
| 214 void X11EventSource::EnqueueRequest(Request* request) { |
| 215 DCHECK(request); |
| 216 request_queue_.emplace_back(request); |
| 217 request->it_ = --request_queue_.end(); |
| 218 } |
| 219 |
| 220 void X11EventSource::DiscardRequest(Request* request) { |
| 221 DCHECK(connection_); |
| 222 xcb_discard_reply(connection_, request->sequence()); |
| 223 request_queue_.erase(request->it_); |
| 224 } |
| 225 |
| 192 //////////////////////////////////////////////////////////////////////////////// | 226 //////////////////////////////////////////////////////////////////////////////// |
| 193 // X11EventSource, protected | 227 // X11EventSource, protected |
| 194 | 228 |
| 195 void X11EventSource::ExtractCookieDataDispatchEvent(XEvent* xevent) { | 229 void X11EventSource::ExtractCookieDataDispatchEvent(XEvent* xevent) { |
| 196 bool have_cookie = false; | 230 bool have_cookie = false; |
| 197 if (xevent->type == GenericEvent && | 231 if (xevent->type == GenericEvent && |
| 198 XGetEventData(xevent->xgeneric.display, &xevent->xcookie)) { | 232 XGetEventData(xevent->xgeneric.display, &xevent->xcookie)) { |
| 199 have_cookie = true; | 233 have_cookie = true; |
| 200 } | 234 } |
| 201 | 235 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 245 void X11EventSource::BlockOnWindowStructureEvent(XID window, int type) { | 279 void X11EventSource::BlockOnWindowStructureEvent(XID window, int type) { |
| 246 XEvent event; | 280 XEvent event; |
| 247 do { | 281 do { |
| 248 // Block until there's a StructureNotify event of |type| on |window|. Then | 282 // Block until there's a StructureNotify event of |type| on |window|. Then |
| 249 // remove it from the queue and stuff it in |event|. | 283 // remove it from the queue and stuff it in |event|. |
| 250 XWindowEvent(display_, window, StructureNotifyMask, &event); | 284 XWindowEvent(display_, window, StructureNotifyMask, &event); |
| 251 ExtractCookieDataDispatchEvent(&event); | 285 ExtractCookieDataDispatchEvent(&event); |
| 252 } while (event.type != type); | 286 } while (event.type != type); |
| 253 } | 287 } |
| 254 | 288 |
| 289 bool X11EventSource::HasNextReply() { |
| 290 if (request_queue_.empty() || xcb_connection_has_error(connection_)) |
| 291 return false; |
| 292 if (next_reply_ || next_error_) |
| 293 return true; |
| 294 |
| 295 return xcb_poll_for_reply(connection_, request_queue_.front()->sequence(), |
| 296 &next_reply_, &next_error_); |
| 297 } |
| 298 |
| 299 uint32_t X11EventSource::NextReplySequence() { |
| 300 DCHECK(HasNextReply()); |
| 301 return request_queue_.front()->sequence(); |
| 302 } |
| 303 |
| 304 void X11EventSource::ProcessNextReply() { |
| 305 DCHECK(HasNextReply()); |
| 306 |
| 307 uint32_t sequence = request_queue_.front()->sequence(); |
| 308 request_queue_.front()->OnReply( |
| 309 reinterpret_cast<xcb_generic_reply_t*>(next_reply_), next_error_); |
| 310 |
| 311 free(next_reply_); |
| 312 free(next_error_); |
| 313 next_reply_ = nullptr; |
| 314 next_error_ = nullptr; |
| 315 |
| 316 // OnReply() may have already discarded this event. |
| 317 if (!request_queue_.empty() && request_queue_.front()->sequence() == sequence) |
| 318 request_queue_.pop_front(); |
| 319 } |
| 320 |
| 321 bool X11EventSource::HasNextEvent() { |
| 322 return XEventsQueued(display_, QueuedAlready); |
| 323 } |
| 324 |
| 325 uint32_t X11EventSource::NextEventSequence() { |
| 326 DCHECK(HasNextEvent()); |
| 327 XEvent event; |
| 328 XPeekEvent(display_, &event); |
| 329 return event.xany.serial; |
| 330 } |
| 331 |
| 332 void X11EventSource::ProcessNextEvent() { |
| 333 DCHECK(HasNextEvent()); |
| 334 XEvent event; |
| 335 XNextEvent(display_, &event); |
| 336 ExtractCookieDataDispatchEvent(&event); |
| 337 } |
| 338 |
| 255 void X11EventSource::StopCurrentEventStream() { | 339 void X11EventSource::StopCurrentEventStream() { |
| 256 continue_stream_ = false; | 340 continue_stream_ = false; |
| 257 } | 341 } |
| 258 | 342 |
| 259 void X11EventSource::OnDispatcherListChanged() { | 343 void X11EventSource::OnDispatcherListChanged() { |
| 260 if (!hotplug_event_handler_) { | 344 if (!hotplug_event_handler_) { |
| 261 hotplug_event_handler_.reset(new X11HotplugEventHandler()); | 345 hotplug_event_handler_.reset(new X11HotplugEventHandler()); |
| 262 // Force the initial device query to have an update list of active devices. | 346 // Force the initial device query to have an update list of active devices. |
| 263 hotplug_event_handler_->OnHotplugEvent(); | 347 hotplug_event_handler_->OnHotplugEvent(); |
| 264 } | 348 } |
| 265 } | 349 } |
| 266 | 350 |
| 267 } // namespace ui | 351 } // namespace ui |
| OLD | NEW |