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 <X11/extensions/XInput2.h> 8 #include <X11/X.h> 9 #include <X11/Xlib.h> 10 #include <X11/XKBlib.h> 11 12 #include "base/logging.h" 13 #include "ui/events/event_utils.h" 14 #include "ui/events/platform/platform_event_dispatcher.h" 15 #include "ui/events/x/device_data_manager_x11.h" 16 #include "ui/events/x/hotplug_event_handler_x11.h" 17 #include "ui/gfx/x/x11_types.h" 18 19 namespace ui { 20 21 namespace { 22 23 int g_xinput_opcode = -1; 24 25 bool InitializeXInput2(XDisplay* display) { 26 if (!display) 27 return false; 28 29 int event, err; 30 31 int xiopcode; 32 if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) { 33 DVLOG(1) << "X Input extension not available."; 34 return false; 35 } 36 g_xinput_opcode = xiopcode; 37 38 #if defined(USE_XI2_MT) 39 // USE_XI2_MT also defines the required XI2 minor minimum version. 40 int major = 2, minor = USE_XI2_MT; 41 #else 42 int major = 2, minor = 0; 43 #endif 44 if (XIQueryVersion(display, &major, &minor) == BadRequest) { 45 DVLOG(1) << "XInput2 not supported in the server."; 46 return false; 47 } 48 #if defined(USE_XI2_MT) 49 if (major < 2 || (major == 2 && minor < USE_XI2_MT)) { 50 DVLOG(1) << "XI version on server is " << major << "." << minor << ". " 51 << "But 2." << USE_XI2_MT << " is required."; 52 return false; 53 } 54 #endif 55 56 return true; 57 } 58 59 bool InitializeXkb(XDisplay* display) { 60 if (!display) 61 return false; 62 63 int opcode, event, error; 64 int major = XkbMajorVersion; 65 int minor = XkbMinorVersion; 66 if (!XkbQueryExtension(display, &opcode, &event, &error, &major, &minor)) { 67 DVLOG(1) << "Xkb extension not available."; 68 return false; 69 } 70 71 // Ask the server not to send KeyRelease event when the user holds down a key. 72 // crbug.com/138092 73 Bool supported_return; 74 if (!XkbSetDetectableAutoRepeat(display, True, &supported_return)) { 75 DVLOG(1) << "XKB not supported in the server."; 76 return false; 77 } 78 79 return true; 80 } 81 82 } // namespace 83 84 X11EventSource::X11EventSource(XDisplay* display) 85 : display_(display), 86 continue_stream_(true) { 87 CHECK(display_); 88 DeviceDataManagerX11::CreateInstance(); 89 hotplug_event_handler_.reset( 90 new HotplugEventHandlerX11(DeviceDataManager::GetInstance())); 91 InitializeXInput2(display_); 92 InitializeXkb(display_); 93 94 // Force the initial device query to have an update list of active devices. 95 hotplug_event_handler_->OnHotplugEvent(); 96 } 97 98 X11EventSource::~X11EventSource() { 99 } 100 101 // static 102 X11EventSource* X11EventSource::GetInstance() { 103 return static_cast<X11EventSource*>(PlatformEventSource::GetInstance()); 104 } 105 106 //////////////////////////////////////////////////////////////////////////////// 107 // X11EventSource, public 108 109 void X11EventSource::DispatchXEvents() { 110 DCHECK(display_); 111 // Handle all pending events. 112 // It may be useful to eventually align this event dispatch with vsync, but 113 // not yet. 114 continue_stream_ = true; 115 while (XPending(display_) && continue_stream_) { 116 XEvent xevent; 117 XNextEvent(display_, &xevent); 118 DispatchEvent(&xevent); 119 } 120 } 121 122 void X11EventSource::BlockUntilWindowMapped(XID window) { 123 XEvent event; 124 do { 125 // Block until there's a message of |event_mask| type on |w|. Then remove 126 // it from the queue and stuff it in |event|. 127 XWindowEvent(display_, window, StructureNotifyMask, &event); 128 DispatchEvent(&event); 129 } while (event.type != MapNotify); 130 } 131 132 //////////////////////////////////////////////////////////////////////////////// 133 // X11EventSource, private 134 135 uint32_t X11EventSource::DispatchEvent(XEvent* xevent) { 136 bool have_cookie = false; 137 if (xevent->type == GenericEvent && 138 XGetEventData(xevent->xgeneric.display, &xevent->xcookie)) { 139 have_cookie = true; 140 } 141 142 uint32_t action = PlatformEventSource::DispatchEvent(xevent); 143 if (xevent->type == GenericEvent && 144 xevent->xgeneric.evtype == XI_HierarchyChanged) { 145 ui::UpdateDeviceList(); 146 hotplug_event_handler_->OnHotplugEvent(); 147 } 148 149 if (have_cookie) 150 XFreeEventData(xevent->xgeneric.display, &xevent->xcookie); 151 return action; 152 } 153 154 void X11EventSource::StopCurrentEventStream() { 155 continue_stream_ = false; 156 } 157 158 } // namespace ui 159