1 // Copyright (c) 2012 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 "base/message_loop/message_pump_aurax11.h" 6 7 #include <glib.h> 8 #include <X11/X.h> 9 #include <X11/extensions/XInput2.h> 10 #include <X11/XKBlib.h> 11 12 #include "base/basictypes.h" 13 #include "base/message_loop/message_loop.h" 14 15 namespace base { 16 17 namespace { 18 19 gboolean XSourcePrepare(GSource* source, gint* timeout_ms) { 20 if (XPending(MessagePumpAuraX11::GetDefaultXDisplay())) 21 *timeout_ms = 0; 22 else 23 *timeout_ms = -1; 24 return FALSE; 25 } 26 27 gboolean XSourceCheck(GSource* source) { 28 return XPending(MessagePumpAuraX11::GetDefaultXDisplay()); 29 } 30 31 gboolean XSourceDispatch(GSource* source, 32 GSourceFunc unused_func, 33 gpointer data) { 34 MessagePumpAuraX11* pump = static_cast<MessagePumpAuraX11*>(data); 35 return pump->DispatchXEvents(); 36 } 37 38 GSourceFuncs XSourceFuncs = { 39 XSourcePrepare, 40 XSourceCheck, 41 XSourceDispatch, 42 NULL 43 }; 44 45 // The connection is essentially a global that's accessed through a static 46 // method and destroyed whenever ~MessagePumpAuraX11() is called. We do this 47 // for historical reasons so user code can call 48 // MessagePumpForUI::GetDefaultXDisplay() where MessagePumpForUI is a typedef 49 // to whatever type in the current build. 50 // 51 // TODO(erg): This can be changed to something more sane like 52 // MessagePumpAuraX11::Current()->display() once MessagePumpGtk goes away. 53 Display* g_xdisplay = NULL; 54 int g_xinput_opcode = -1; 55 56 bool InitializeXInput2Internal() { 57 Display* display = MessagePumpAuraX11::GetDefaultXDisplay(); 58 if (!display) 59 return false; 60 61 int event, err; 62 63 int xiopcode; 64 if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) { 65 DVLOG(1) << "X Input extension not available."; 66 return false; 67 } 68 g_xinput_opcode = xiopcode; 69 70 #if defined(USE_XI2_MT) 71 // USE_XI2_MT also defines the required XI2 minor minimum version. 72 int major = 2, minor = USE_XI2_MT; 73 #else 74 int major = 2, minor = 0; 75 #endif 76 if (XIQueryVersion(display, &major, &minor) == BadRequest) { 77 DVLOG(1) << "XInput2 not supported in the server."; 78 return false; 79 } 80 #if defined(USE_XI2_MT) 81 if (major < 2 || (major == 2 && minor < USE_XI2_MT)) { 82 DVLOG(1) << "XI version on server is " << major << "." << minor << ". " 83 << "But 2." << USE_XI2_MT << " is required."; 84 return false; 85 } 86 #endif 87 88 return true; 89 } 90 91 Window FindEventTarget(const NativeEvent& xev) { 92 Window target = xev->xany.window; 93 if (xev->type == GenericEvent && 94 static_cast<XIEvent*>(xev->xcookie.data)->extension == g_xinput_opcode) { 95 target = static_cast<XIDeviceEvent*>(xev->xcookie.data)->event; 96 } 97 return target; 98 } 99 100 bool InitializeXInput2() { 101 static bool xinput2_supported = InitializeXInput2Internal(); 102 return xinput2_supported; 103 } 104 105 bool InitializeXkb() { 106 Display* display = MessagePumpAuraX11::GetDefaultXDisplay(); 107 if (!display) 108 return false; 109 110 int opcode, event, error; 111 int major = XkbMajorVersion; 112 int minor = XkbMinorVersion; 113 if (!XkbQueryExtension(display, &opcode, &event, &error, &major, &minor)) { 114 DVLOG(1) << "Xkb extension not available."; 115 return false; 116 } 117 118 // Ask the server not to send KeyRelease event when the user holds down a key. 119 // crbug.com/138092 120 Bool supported_return; 121 if (!XkbSetDetectableAutoRepeat(display, True, &supported_return)) { 122 DVLOG(1) << "XKB not supported in the server."; 123 return false; 124 } 125 126 return true; 127 } 128 129 } // namespace 130 131 MessagePumpAuraX11::MessagePumpAuraX11() : MessagePumpGlib(), 132 x_source_(NULL) { 133 InitializeXInput2(); 134 InitializeXkb(); 135 InitXSource(); 136 137 // Can't put this in the initializer list because g_xdisplay may not exist 138 // until after InitXSource(). 139 x_root_window_ = DefaultRootWindow(g_xdisplay); 140 } 141 142 MessagePumpAuraX11::~MessagePumpAuraX11() { 143 g_source_destroy(x_source_); 144 g_source_unref(x_source_); 145 XCloseDisplay(g_xdisplay); 146 g_xdisplay = NULL; 147 } 148 149 // static 150 Display* MessagePumpAuraX11::GetDefaultXDisplay() { 151 if (!g_xdisplay) 152 g_xdisplay = XOpenDisplay(NULL); 153 return g_xdisplay; 154 } 155 156 // static 157 bool MessagePumpAuraX11::HasXInput2() { 158 return InitializeXInput2(); 159 } 160 161 // static 162 MessagePumpAuraX11* MessagePumpAuraX11::Current() { 163 MessageLoopForUI* loop = MessageLoopForUI::current(); 164 return static_cast<MessagePumpAuraX11*>(loop->pump_ui()); 165 } 166 167 void MessagePumpAuraX11::AddDispatcherForWindow( 168 MessagePumpDispatcher* dispatcher, 169 unsigned long xid) { 170 dispatchers_.insert(std::make_pair(xid, dispatcher)); 171 } 172 173 void MessagePumpAuraX11::RemoveDispatcherForWindow(unsigned long xid) { 174 dispatchers_.erase(xid); 175 } 176 177 void MessagePumpAuraX11::AddDispatcherForRootWindow( 178 MessagePumpDispatcher* dispatcher) { 179 root_window_dispatchers_.AddObserver(dispatcher); 180 } 181 182 void MessagePumpAuraX11::RemoveDispatcherForRootWindow( 183 MessagePumpDispatcher* dispatcher) { 184 root_window_dispatchers_.RemoveObserver(dispatcher); 185 } 186 187 bool MessagePumpAuraX11::DispatchXEvents() { 188 Display* display = GetDefaultXDisplay(); 189 DCHECK(display); 190 MessagePumpDispatcher* dispatcher = 191 GetDispatcher() ? GetDispatcher() : this; 192 193 // In the general case, we want to handle all pending events before running 194 // the tasks. This is what happens in the message_pump_glib case. 195 while (XPending(display)) { 196 XEvent xev; 197 XNextEvent(display, &xev); 198 if (dispatcher && ProcessXEvent(dispatcher, &xev)) 199 return TRUE; 200 } 201 return TRUE; 202 } 203 204 void MessagePumpAuraX11::BlockUntilWindowMapped(unsigned long xid) { 205 XEvent event; 206 207 Display* display = GetDefaultXDisplay(); 208 DCHECK(display); 209 210 MessagePumpDispatcher* dispatcher = 211 GetDispatcher() ? GetDispatcher() : this; 212 213 do { 214 // Block until there's a message of |event_mask| type on |w|. Then remove 215 // it from the queue and stuff it in |event|. 216 XWindowEvent(display, xid, StructureNotifyMask, &event); 217 ProcessXEvent(dispatcher, &event); 218 } while (event.type != MapNotify); 219 } 220 221 void MessagePumpAuraX11::InitXSource() { 222 // CHECKs are to help track down crbug.com/113106. 223 CHECK(!x_source_); 224 Display* display = GetDefaultXDisplay(); 225 CHECK(display) << "Unable to get connection to X server"; 226 x_poll_.reset(new GPollFD()); 227 CHECK(x_poll_.get()); 228 x_poll_->fd = ConnectionNumber(display); 229 x_poll_->events = G_IO_IN; 230 231 x_source_ = g_source_new(&XSourceFuncs, sizeof(GSource)); 232 g_source_add_poll(x_source_, x_poll_.get()); 233 g_source_set_can_recurse(x_source_, TRUE); 234 g_source_set_callback(x_source_, NULL, this, NULL); 235 g_source_attach(x_source_, g_main_context_default()); 236 } 237 238 bool MessagePumpAuraX11::ProcessXEvent(MessagePumpDispatcher* dispatcher, 239 XEvent* xev) { 240 bool should_quit = false; 241 242 bool have_cookie = false; 243 if (xev->type == GenericEvent && 244 XGetEventData(xev->xgeneric.display, &xev->xcookie)) { 245 have_cookie = true; 246 } 247 248 if (!WillProcessXEvent(xev)) { 249 if (!dispatcher->Dispatch(xev)) { 250 should_quit = true; 251 Quit(); 252 } 253 DidProcessXEvent(xev); 254 } 255 256 if (have_cookie) { 257 XFreeEventData(xev->xgeneric.display, &xev->xcookie); 258 } 259 260 return should_quit; 261 } 262 263 bool MessagePumpAuraX11::WillProcessXEvent(XEvent* xevent) { 264 if (!observers().might_have_observers()) 265 return false; 266 ObserverListBase<MessagePumpObserver>::Iterator it(observers()); 267 MessagePumpObserver* obs; 268 while ((obs = it.GetNext()) != NULL) { 269 if (obs->WillProcessEvent(xevent)) 270 return true; 271 } 272 return false; 273 } 274 275 void MessagePumpAuraX11::DidProcessXEvent(XEvent* xevent) { 276 FOR_EACH_OBSERVER(MessagePumpObserver, observers(), DidProcessEvent(xevent)); 277 } 278 279 MessagePumpDispatcher* MessagePumpAuraX11::GetDispatcherForXEvent( 280 const NativeEvent& xev) const { 281 ::Window x_window = FindEventTarget(xev); 282 DispatchersMap::const_iterator it = dispatchers_.find(x_window); 283 return it != dispatchers_.end() ? it->second : NULL; 284 } 285 286 bool MessagePumpAuraX11::Dispatch(const NativeEvent& xev) { 287 // MappingNotify events (meaning that the keyboard or pointer buttons have 288 // been remapped) aren't associated with a window; send them to all 289 // dispatchers. 290 if (xev->type == MappingNotify) { 291 for (DispatchersMap::const_iterator it = dispatchers_.begin(); 292 it != dispatchers_.end(); ++it) { 293 it->second->Dispatch(xev); 294 } 295 return true; 296 } 297 298 if (FindEventTarget(xev) == x_root_window_) { 299 FOR_EACH_OBSERVER(MessagePumpDispatcher, root_window_dispatchers_, 300 Dispatch(xev)); 301 return true; 302 } 303 MessagePumpDispatcher* dispatcher = GetDispatcherForXEvent(xev); 304 return dispatcher ? dispatcher->Dispatch(xev) : true; 305 } 306 307 } // namespace base 308