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 19namespace ui { 20 21namespace { 22 23int g_xinput_opcode = -1; 24 25bool 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 59bool 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 84X11EventSource::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 98X11EventSource::~X11EventSource() { 99} 100 101// static 102X11EventSource* X11EventSource::GetInstance() { 103 return static_cast<X11EventSource*>(PlatformEventSource::GetInstance()); 104} 105 106//////////////////////////////////////////////////////////////////////////////// 107// X11EventSource, public 108 109void 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 122void 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 135uint32_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 154void X11EventSource::StopCurrentEventStream() { 155 continue_stream_ = false; 156} 157 158} // namespace ui 159