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
3 // found in the LICENSE file.
4
5 #include "ui/events/platform/x11/x11_event_source.h"
6
7 #include <algorithm>
8 #include <memory>
9 #include <type_traits>
10
11 #include "base/auto_reset.h"
12 #include "base/logging.h"
13 #include "base/memory/free_deleter.h"
14 #include "base/memory/ref_counted_memory.h"
15 #include "base/metrics/histogram_macros.h"
16 #include "ui/events/devices/x11/device_data_manager_x11.h"
17 #include "ui/events/devices/x11/touch_factory_x11.h"
18 #include "ui/events/event_utils.h"
19 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
20 #include "ui/events/platform/platform_event_dispatcher.h"
21 #include "ui/events/platform/x11/x11_hotplug_event_handler.h"
22 #include "ui/events/x/events_x_utils.h"
23 #include "ui/events/x/x11_event_translation.h"
24 #include "ui/events/x/x11_window_event_manager.h"
25 #include "ui/gfx/x/connection.h"
26 #include "ui/gfx/x/extension_manager.h"
27 #include "ui/gfx/x/x11_atom_cache.h"
28 #include "ui/gfx/x/xkb.h"
29 #include "ui/gfx/x/xproto.h"
30
31 #if defined(USE_GLIB)
32 #include "ui/events/platform/x11/x11_event_watcher_glib.h"
33 #else
34 #include "ui/events/platform/x11/x11_event_watcher_fdwatch.h"
35 #endif
36
37 #if defined(OS_CHROMEOS)
38 #include "ui/events/ozone/chromeos/cursor_controller.h"
39 #endif
40
41 #if defined(USE_OZONE)
42 #include "ui/base/ui_base_features.h"
43 #endif
44
45 namespace ui {
46
47 namespace {
48
InitializeXkb(x11::Connection * connection)49 void InitializeXkb(x11::Connection* connection) {
50 if (!connection)
51 return;
52
53 auto& xkb = connection->xkb();
54
55 // Ask the server not to send KeyRelease event when the user holds down a key.
56 // crbug.com/138092
57 xkb
58 .PerClientFlags({
59 .deviceSpec =
60 static_cast<x11::Xkb::DeviceSpec>(x11::Xkb::Id::UseCoreKbd),
61 .change = x11::Xkb::PerClientFlag::DetectableAutoRepeat,
62 .value = x11::Xkb::PerClientFlag::DetectableAutoRepeat,
63 })
64 .OnResponse(base::BindOnce([](x11::Xkb::PerClientFlagsResponse response) {
65 if (!response ||
66 !static_cast<bool>(response->supported &
67 x11::Xkb::PerClientFlag::DetectableAutoRepeat)) {
68 DVLOG(1) << "Could not set XKB auto repeat flag.";
69 }
70 }));
71
72 constexpr auto kXkbAllMapPartMask = static_cast<x11::Xkb::MapPart>(0xff);
73 xkb.SelectEvents(x11::Xkb::SelectEventsRequest{
74 .deviceSpec = static_cast<x11::Xkb::DeviceSpec>(x11::Xkb::Id::UseCoreKbd),
75 .affectWhich = x11::Xkb::EventType::NewKeyboardNotify,
76 .selectAll = x11::Xkb::EventType::NewKeyboardNotify,
77 .affectMap = kXkbAllMapPartMask,
78 });
79 }
80
ExtractTimeFromXEvent(const x11::Event & xev)81 x11::Time ExtractTimeFromXEvent(const x11::Event& xev) {
82 if (auto* key = xev.As<x11::KeyEvent>())
83 return key->time;
84 if (auto* button = xev.As<x11::ButtonEvent>())
85 return button->time;
86 if (auto* motion = xev.As<x11::MotionNotifyEvent>())
87 return motion->time;
88 if (auto* crossing = xev.As<x11::CrossingEvent>())
89 return crossing->time;
90 if (auto* prop = xev.As<x11::PropertyNotifyEvent>())
91 return prop->time;
92 if (auto* sel_clear = xev.As<x11::SelectionClearEvent>())
93 return sel_clear->time;
94 if (auto* sel_req = xev.As<x11::SelectionRequestEvent>())
95 return sel_req->time;
96 if (auto* sel_notify = xev.As<x11::SelectionNotifyEvent>())
97 return sel_notify->time;
98 if (auto* dev_changed = xev.As<x11::Input::DeviceChangedEvent>())
99 return dev_changed->time;
100 if (auto* device = xev.As<x11::Input::DeviceEvent>())
101 return device->time;
102 if (auto* xi_crossing = xev.As<x11::Input::CrossingEvent>())
103 return xi_crossing->time;
104 return x11::Time::CurrentTime;
105 }
106
UpdateDeviceList()107 void UpdateDeviceList() {
108 auto* connection = x11::Connection::Get();
109 DeviceListCacheX11::GetInstance()->UpdateDeviceList(connection);
110 TouchFactory::GetInstance()->UpdateDeviceList(connection);
111 DeviceDataManagerX11::GetInstance()->UpdateDeviceList(connection);
112 }
113
114 } // namespace
115
116 #if defined(USE_GLIB)
117 using X11EventWatcherImpl = X11EventWatcherGlib;
118 #else
119 using X11EventWatcherImpl = X11EventWatcherFdWatch;
120 #endif
121
X11EventSource(x11::Connection * connection)122 X11EventSource::X11EventSource(x11::Connection* connection)
123 : watcher_(std::make_unique<X11EventWatcherImpl>(this)),
124 connection_(connection),
125 dispatching_event_(nullptr),
126 dummy_initialized_(false),
127 distribution_(0, 999) {
128 DCHECK(connection_);
129 DeviceDataManagerX11::CreateInstance();
130 InitializeXkb(connection_);
131
132 watcher_->StartWatching();
133 }
134
~X11EventSource()135 X11EventSource::~X11EventSource() {
136 if (dummy_initialized_)
137 connection_->DestroyWindow({dummy_window_});
138 }
139
140 // static
HasInstance()141 bool X11EventSource::HasInstance() {
142 return GetInstance();
143 }
144
145 // static
GetInstance()146 X11EventSource* X11EventSource::GetInstance() {
147 return static_cast<X11EventSource*>(PlatformEventSource::GetInstance());
148 }
149
150 ////////////////////////////////////////////////////////////////////////////////
151 // X11EventSource, public
152
DispatchXEvents()153 void X11EventSource::DispatchXEvents() {
154 continue_stream_ = true;
155 connection_->Dispatch(this);
156 }
157
GetCurrentServerTime()158 x11::Time X11EventSource::GetCurrentServerTime() {
159 DCHECK(connection_);
160
161 if (!dummy_initialized_) {
162 // Create a new Window and Atom that will be used for the property change.
163 dummy_window_ = connection_->GenerateId<x11::Window>();
164 connection_->CreateWindow(x11::CreateWindowRequest{
165 .wid = dummy_window_,
166 .parent = connection_->default_root(),
167 .width = 1,
168 .height = 1,
169 .override_redirect = x11::Bool32(true),
170 });
171 dummy_atom_ = gfx::GetAtom("CHROMIUM_TIMESTAMP");
172 dummy_window_events_ = std::make_unique<XScopedEventSelector>(
173 dummy_window_, x11::EventMask::PropertyChange);
174 dummy_initialized_ = true;
175 }
176
177 // No need to measure Linux.X11.ServerRTT on every call.
178 // base::TimeTicks::Now() itself has non-trivial overhead.
179 bool measure_rtt = distribution_(generator_) == 0;
180
181 base::TimeTicks start;
182 if (measure_rtt)
183 start = base::TimeTicks::Now();
184
185 // Make a no-op property change on |dummy_window_|.
186 std::vector<uint8_t> data{0};
187 connection_->ChangeProperty(x11::ChangePropertyRequest{
188 .window = static_cast<x11::Window>(dummy_window_),
189 .property = dummy_atom_,
190 .type = x11::Atom::STRING,
191 .format = CHAR_BIT,
192 .data_len = 1,
193 .data = base::RefCountedBytes::TakeVector(&data),
194 });
195
196 // Observe the resulting PropertyNotify event to obtain the timestamp.
197 connection_->Sync();
198 if (measure_rtt) {
199 UMA_HISTOGRAM_CUSTOM_COUNTS(
200 "Linux.X11.ServerRTT",
201 (base::TimeTicks::Now() - start).InMicroseconds(), 1,
202 base::TimeDelta::FromMilliseconds(50).InMicroseconds(), 50);
203 }
204 connection_->ReadResponses();
205
206 auto time = x11::Time::CurrentTime;
207 auto pred = [&](const x11::Event& event) {
208 auto* prop = event.As<x11::PropertyNotifyEvent>();
209 if (prop && prop->window == dummy_window_) {
210 time = prop->time;
211 return true;
212 }
213 return false;
214 };
215
216 auto& events = connection_->events();
217 auto it = std::find_if(events.begin(), events.end(), pred);
218 if (it != events.end())
219 *it = x11::Event();
220 return time;
221 }
222
GetTimestamp()223 x11::Time X11EventSource::GetTimestamp() {
224 if (dispatching_event_) {
225 auto timestamp = ExtractTimeFromXEvent(*dispatching_event_);
226 if (timestamp != x11::Time::CurrentTime)
227 return timestamp;
228 }
229 DVLOG(1) << "Making a round trip to get a recent server timestamp.";
230 return GetCurrentServerTime();
231 }
232
233 base::Optional<gfx::Point>
GetRootCursorLocationFromCurrentEvent() const234 X11EventSource::GetRootCursorLocationFromCurrentEvent() const {
235 if (!dispatching_event_)
236 return base::nullopt;
237
238 DCHECK(dispatching_event_);
239 x11::Event* event = dispatching_event_;
240
241 auto* device = event->As<x11::Input::DeviceEvent>();
242 auto* crossing = event->As<x11::Input::CrossingEvent>();
243 auto* touch_factory = ui::TouchFactory::GetInstance();
244
245 bool is_valid_event = false;
246 if (event->As<x11::ButtonEvent>() || event->As<x11::MotionNotifyEvent>() ||
247 event->As<x11::CrossingEvent>()) {
248 is_valid_event = true;
249 } else if (device &&
250 (device->opcode == x11::Input::DeviceEvent::ButtonPress ||
251 device->opcode == x11::Input::DeviceEvent::ButtonRelease ||
252 device->opcode == x11::Input::DeviceEvent::Motion)) {
253 is_valid_event = touch_factory->ShouldProcessDeviceEvent(*device);
254 } else if (crossing &&
255 (crossing->opcode == x11::Input::CrossingEvent::Enter ||
256 crossing->opcode == x11::Input::CrossingEvent::Leave)) {
257 is_valid_event = touch_factory->ShouldProcessCrossingEvent(*crossing);
258 }
259
260 if (is_valid_event)
261 return ui::EventSystemLocationFromXEvent(*dispatching_event_);
262 return base::nullopt;
263 }
264
AddXEventDispatcher(XEventDispatcher * dispatcher)265 void X11EventSource::AddXEventDispatcher(XEventDispatcher* dispatcher) {
266 dispatchers_xevent_.AddObserver(dispatcher);
267 PlatformEventDispatcher* event_dispatcher =
268 dispatcher->GetPlatformEventDispatcher();
269 if (event_dispatcher)
270 AddPlatformEventDispatcher(event_dispatcher);
271 }
272
RemoveXEventDispatcher(XEventDispatcher * dispatcher)273 void X11EventSource::RemoveXEventDispatcher(XEventDispatcher* dispatcher) {
274 dispatchers_xevent_.RemoveObserver(dispatcher);
275 PlatformEventDispatcher* event_dispatcher =
276 dispatcher->GetPlatformEventDispatcher();
277 if (event_dispatcher)
278 RemovePlatformEventDispatcher(event_dispatcher);
279 }
280
AddXEventObserver(XEventObserver * observer)281 void X11EventSource::AddXEventObserver(XEventObserver* observer) {
282 CHECK(observer);
283 observers_.AddObserver(observer);
284 }
285
RemoveXEventObserver(XEventObserver * observer)286 void X11EventSource::RemoveXEventObserver(XEventObserver* observer) {
287 CHECK(observer);
288 observers_.RemoveObserver(observer);
289 }
290
291 std::unique_ptr<ScopedXEventDispatcher>
OverrideXEventDispatcher(XEventDispatcher * dispatcher)292 X11EventSource::OverrideXEventDispatcher(XEventDispatcher* dispatcher) {
293 CHECK(dispatcher);
294 overridden_dispatcher_restored_ = false;
295 return std::make_unique<ScopedXEventDispatcher>(&overridden_dispatcher_,
296 dispatcher);
297 }
298
RestoreOverridenXEventDispatcher()299 void X11EventSource::RestoreOverridenXEventDispatcher() {
300 CHECK(overridden_dispatcher_);
301 overridden_dispatcher_restored_ = true;
302 }
303
DispatchPlatformEvent(const PlatformEvent & event,x11::Event * xevent)304 void X11EventSource::DispatchPlatformEvent(const PlatformEvent& event,
305 x11::Event* xevent) {
306 DCHECK(event);
307
308 // First, tell the XEventDispatchers, which can have PlatformEventDispatcher,
309 // an ui::Event is going to be sent next. It must make a promise to handle
310 // next translated |event| sent by PlatformEventSource based on a XID in
311 // |xevent| tested in CheckCanDispatchNextPlatformEvent(). This is needed
312 // because it is not possible to access |event|'s associated NativeEvent* and
313 // check if it is the event's target window (XID).
314 for (XEventDispatcher& dispatcher : dispatchers_xevent_)
315 dispatcher.CheckCanDispatchNextPlatformEvent(xevent);
316
317 DispatchEvent(event);
318
319 // Explicitly reset a promise to handle next translated event.
320 for (XEventDispatcher& dispatcher : dispatchers_xevent_)
321 dispatcher.PlatformEventDispatchFinished();
322 }
323
DispatchXEventToXEventDispatchers(x11::Event * xevent)324 void X11EventSource::DispatchXEventToXEventDispatchers(x11::Event* xevent) {
325 bool stop_dispatching = false;
326
327 for (auto& observer : observers_)
328 observer.WillProcessXEvent(xevent);
329
330 if (overridden_dispatcher_) {
331 stop_dispatching = overridden_dispatcher_->DispatchXEvent(xevent);
332 }
333
334 if (!stop_dispatching) {
335 for (XEventDispatcher& dispatcher : dispatchers_xevent_) {
336 if (dispatcher.DispatchXEvent(xevent))
337 break;
338 }
339 }
340
341 for (auto& observer : observers_)
342 observer.DidProcessXEvent(xevent);
343
344 // If an overridden dispatcher has been destroyed, then the event source
345 // should halt dispatching the current stream of events, and wait until the
346 // next message-loop iteration for dispatching events. This lets any nested
347 // message-loop to unwind correctly and any new dispatchers to receive the
348 // correct sequence of events.
349 if (overridden_dispatcher_restored_)
350 StopCurrentEventStream();
351
352 overridden_dispatcher_restored_ = false;
353 }
354
CheckCanDispatchNextPlatformEvent(x11::Event * xev)355 void XEventDispatcher::CheckCanDispatchNextPlatformEvent(x11::Event* xev) {}
356
PlatformEventDispatchFinished()357 void XEventDispatcher::PlatformEventDispatchFinished() {}
358
GetPlatformEventDispatcher()359 PlatformEventDispatcher* XEventDispatcher::GetPlatformEventDispatcher() {
360 return nullptr;
361 }
362
ProcessXEvent(x11::Event * xevent)363 void X11EventSource::ProcessXEvent(x11::Event* xevent) {
364 auto translated_event = ui::BuildEventFromXEvent(*xevent);
365 // Ignore native platform-events only if they correspond to mouse events.
366 // Allow other types of events to still be handled
367 if (ui::PlatformEventSource::ShouldIgnoreNativePlatformEvents() &&
368 translated_event && translated_event->IsMouseEvent()) {
369 return;
370 }
371 if (translated_event && translated_event->type() != ET_UNKNOWN) {
372 #if defined(OS_CHROMEOS)
373 if (translated_event->IsLocatedEvent()) {
374 ui::CursorController::GetInstance()->SetCursorLocation(
375 translated_event->AsLocatedEvent()->location_f());
376 }
377 #endif
378 DispatchPlatformEvent(translated_event.get(), xevent);
379 } else {
380 // Only if we can't translate XEvent into ui::Event, try to dispatch XEvent
381 // directly to XEventDispatchers.
382 DispatchXEventToXEventDispatchers(xevent);
383 }
384 }
385
386 ////////////////////////////////////////////////////////////////////////////////
387 // X11EventSource, protected
388
PostDispatchEvent(x11::Event * x11_event)389 void X11EventSource::PostDispatchEvent(x11::Event* x11_event) {
390 bool should_update_device_list = false;
391
392 if (x11_event->As<x11::Input::HierarchyEvent>()) {
393 should_update_device_list = true;
394 } else if (auto* device = x11_event->As<x11::Input::DeviceChangedEvent>()) {
395 if (device->reason == x11::Input::ChangeReason::DeviceChange) {
396 should_update_device_list = true;
397 } else if (device->reason == x11::Input::ChangeReason::SlaveSwitch) {
398 ui::DeviceDataManagerX11::GetInstance()->InvalidateScrollClasses(
399 device->sourceid);
400 }
401 }
402
403 if (should_update_device_list) {
404 UpdateDeviceList();
405 hotplug_event_handler_->OnHotplugEvent();
406 }
407
408 auto* crossing = x11_event->As<x11::CrossingEvent>();
409 if (crossing && crossing->opcode == x11::CrossingEvent::EnterNotify &&
410 crossing->detail != x11::NotifyDetail::Inferior &&
411 crossing->mode != x11::NotifyMode::Ungrab) {
412 // Clear stored scroll data
413 ui::DeviceDataManagerX11::GetInstance()->InvalidateScrollClasses(
414 DeviceDataManagerX11::kAllDevices);
415 }
416
417 auto* mapping = x11_event->As<x11::MappingNotifyEvent>();
418 if (mapping && mapping->request == x11::Mapping::Pointer)
419 DeviceDataManagerX11::GetInstance()->UpdateButtonMap();
420 }
421
StopCurrentEventStream()422 void X11EventSource::StopCurrentEventStream() {
423 continue_stream_ = false;
424 }
425
OnDispatcherListChanged()426 void X11EventSource::OnDispatcherListChanged() {
427 watcher_->StartWatching();
428
429 if (!hotplug_event_handler_) {
430 hotplug_event_handler_ = std::make_unique<X11HotplugEventHandler>();
431 // Force the initial device query to have an update list of active devices.
432 hotplug_event_handler_->OnHotplugEvent();
433 }
434 }
435
ShouldContinueStream() const436 bool X11EventSource::ShouldContinueStream() const {
437 return continue_stream_;
438 }
439
DispatchXEvent(x11::Event * event)440 void X11EventSource::DispatchXEvent(x11::Event* event) {
441 // NB: The event should be reset to nullptr when this function
442 // returns, not to its initial value, otherwise nested message loops
443 // will incorrectly think that the current event being dispatched is
444 // an old event. This means base::AutoReset should not be used.
445 dispatching_event_ = event;
446
447 ProcessXEvent(event);
448 PostDispatchEvent(event);
449
450 dispatching_event_ = nullptr;
451 }
452
453 // ScopedXEventDispatcher implementation
ScopedXEventDispatcher(XEventDispatcher ** scoped_dispatcher,XEventDispatcher * new_dispatcher)454 ScopedXEventDispatcher::ScopedXEventDispatcher(
455 XEventDispatcher** scoped_dispatcher,
456 XEventDispatcher* new_dispatcher)
457 : original_(*scoped_dispatcher),
458 restore_(scoped_dispatcher, new_dispatcher) {}
459
~ScopedXEventDispatcher()460 ScopedXEventDispatcher::~ScopedXEventDispatcher() {
461 DCHECK(X11EventSource::HasInstance());
462 X11EventSource::GetInstance()->RestoreOverridenXEventDispatcher();
463 }
464
465 // static
466 #if defined(USE_X11)
CreateDefault()467 std::unique_ptr<PlatformEventSource> PlatformEventSource::CreateDefault() {
468 #if defined(USE_OZONE)
469 if (features::IsUsingOzonePlatform())
470 return nullptr;
471 #endif
472 return std::make_unique<X11EventSource>(x11::Connection::Get());
473 }
474 #endif
475
476 } // namespace ui
477