| OLD | NEW |
| (Empty) |
| 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_pump_x.h" | |
| 6 | |
| 7 #include <X11/extensions/XInput2.h> | |
| 8 | |
| 9 #include "base/basictypes.h" | |
| 10 #include "base/message_loop.h" | |
| 11 | |
| 12 namespace { | |
| 13 | |
| 14 gboolean XSourcePrepare(GSource* source, gint* timeout_ms) { | |
| 15 if (XPending(base::MessagePumpX::GetDefaultXDisplay())) | |
| 16 *timeout_ms = 0; | |
| 17 else | |
| 18 *timeout_ms = -1; | |
| 19 return FALSE; | |
| 20 } | |
| 21 | |
| 22 gboolean XSourceCheck(GSource* source) { | |
| 23 return XPending(base::MessagePumpX::GetDefaultXDisplay()); | |
| 24 } | |
| 25 | |
| 26 gboolean XSourceDispatch(GSource* source, | |
| 27 GSourceFunc unused_func, | |
| 28 gpointer data) { | |
| 29 base::MessagePumpX* pump = static_cast<base::MessagePumpX*>(data); | |
| 30 return pump->DispatchXEvents(); | |
| 31 } | |
| 32 | |
| 33 GSourceFuncs XSourceFuncs = { | |
| 34 XSourcePrepare, | |
| 35 XSourceCheck, | |
| 36 XSourceDispatch, | |
| 37 NULL | |
| 38 }; | |
| 39 | |
| 40 // The message-pump opens a connection to the display and owns it. | |
| 41 Display* g_xdisplay = NULL; | |
| 42 | |
| 43 // The default dispatcher to process native events when no dispatcher | |
| 44 // is specified. | |
| 45 base::MessagePumpDispatcher* g_default_dispatcher = NULL; | |
| 46 | |
| 47 bool InitializeXInput2Internal() { | |
| 48 Display* display = base::MessagePumpX::GetDefaultXDisplay(); | |
| 49 if (!display) | |
| 50 return false; | |
| 51 | |
| 52 int event, err; | |
| 53 | |
| 54 int xiopcode; | |
| 55 if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) { | |
| 56 DVLOG(1) << "X Input extension not available."; | |
| 57 return false; | |
| 58 } | |
| 59 | |
| 60 #if defined(USE_XI2_MT) | |
| 61 // USE_XI2_MT also defines the required XI2 minor minimum version. | |
| 62 int major = 2, minor = USE_XI2_MT; | |
| 63 #else | |
| 64 int major = 2, minor = 0; | |
| 65 #endif | |
| 66 if (XIQueryVersion(display, &major, &minor) == BadRequest) { | |
| 67 DVLOG(1) << "XInput2 not supported in the server."; | |
| 68 return false; | |
| 69 } | |
| 70 #if defined(USE_XI2_MT) | |
| 71 if (major < 2 || (major == 2 && minor < USE_XI2_MT)) { | |
| 72 DVLOG(1) << "XI version on server is " << major << "." << minor << ". " | |
| 73 << "But 2." << USE_XI2_MT << " is required."; | |
| 74 return false; | |
| 75 } | |
| 76 #endif | |
| 77 | |
| 78 return true; | |
| 79 } | |
| 80 | |
| 81 bool InitializeXInput2() { | |
| 82 static bool xinput2_supported = InitializeXInput2Internal(); | |
| 83 return xinput2_supported; | |
| 84 } | |
| 85 | |
| 86 } // namespace | |
| 87 | |
| 88 namespace base { | |
| 89 | |
| 90 MessagePumpX::MessagePumpX() : MessagePumpGlib(), | |
| 91 x_source_(NULL) { | |
| 92 InitializeXInput2(); | |
| 93 InitXSource(); | |
| 94 } | |
| 95 | |
| 96 // static | |
| 97 Display* MessagePumpX::GetDefaultXDisplay() { | |
| 98 if (!g_xdisplay) | |
| 99 g_xdisplay = XOpenDisplay(NULL); | |
| 100 return g_xdisplay; | |
| 101 } | |
| 102 | |
| 103 // static | |
| 104 bool MessagePumpX::HasXInput2() { | |
| 105 return InitializeXInput2(); | |
| 106 } | |
| 107 | |
| 108 // static | |
| 109 void MessagePumpX::SetDefaultDispatcher(MessagePumpDispatcher* dispatcher) { | |
| 110 DCHECK(!g_default_dispatcher || !dispatcher); | |
| 111 g_default_dispatcher = dispatcher; | |
| 112 } | |
| 113 | |
| 114 gboolean MessagePumpX::DispatchXEvents() { | |
| 115 Display* display = GetDefaultXDisplay(); | |
| 116 DCHECK(display); | |
| 117 MessagePumpDispatcher* dispatcher = | |
| 118 GetDispatcher() ? GetDispatcher() : g_default_dispatcher; | |
| 119 | |
| 120 // In the general case, we want to handle all pending events before running | |
| 121 // the tasks. This is what happens in the message_pump_glib case. | |
| 122 while (XPending(display)) { | |
| 123 XEvent xev; | |
| 124 XNextEvent(display, &xev); | |
| 125 if (dispatcher && ProcessXEvent(dispatcher, &xev)) | |
| 126 return TRUE; | |
| 127 } | |
| 128 return TRUE; | |
| 129 } | |
| 130 | |
| 131 MessagePumpX::~MessagePumpX() { | |
| 132 g_source_destroy(x_source_); | |
| 133 g_source_unref(x_source_); | |
| 134 XCloseDisplay(g_xdisplay); | |
| 135 g_xdisplay = NULL; | |
| 136 } | |
| 137 | |
| 138 void MessagePumpX::InitXSource() { | |
| 139 // CHECKs are to help track down crbug.com/113106. | |
| 140 CHECK(!x_source_); | |
| 141 Display* display = GetDefaultXDisplay(); | |
| 142 CHECK(display) << "Unable to get connection to X server"; | |
| 143 x_poll_.reset(new GPollFD()); | |
| 144 CHECK(x_poll_.get()); | |
| 145 x_poll_->fd = ConnectionNumber(display); | |
| 146 x_poll_->events = G_IO_IN; | |
| 147 | |
| 148 x_source_ = g_source_new(&XSourceFuncs, sizeof(GSource)); | |
| 149 g_source_add_poll(x_source_, x_poll_.get()); | |
| 150 g_source_set_can_recurse(x_source_, TRUE); | |
| 151 g_source_set_callback(x_source_, NULL, this, NULL); | |
| 152 g_source_attach(x_source_, g_main_context_default()); | |
| 153 } | |
| 154 | |
| 155 bool MessagePumpX::ProcessXEvent(MessagePumpDispatcher* dispatcher, | |
| 156 XEvent* xev) { | |
| 157 bool should_quit = false; | |
| 158 | |
| 159 bool have_cookie = false; | |
| 160 if (xev->type == GenericEvent && | |
| 161 XGetEventData(xev->xgeneric.display, &xev->xcookie)) { | |
| 162 have_cookie = true; | |
| 163 } | |
| 164 | |
| 165 if (!WillProcessXEvent(xev)) { | |
| 166 if (!dispatcher->Dispatch(xev)) { | |
| 167 should_quit = true; | |
| 168 Quit(); | |
| 169 } | |
| 170 DidProcessXEvent(xev); | |
| 171 } | |
| 172 | |
| 173 if (have_cookie) { | |
| 174 XFreeEventData(xev->xgeneric.display, &xev->xcookie); | |
| 175 } | |
| 176 | |
| 177 return should_quit; | |
| 178 } | |
| 179 | |
| 180 bool MessagePumpX::WillProcessXEvent(XEvent* xevent) { | |
| 181 if (!observers().might_have_observers()) | |
| 182 return false; | |
| 183 ObserverListBase<MessagePumpObserver>::Iterator it(observers()); | |
| 184 MessagePumpObserver* obs; | |
| 185 while ((obs = it.GetNext()) != NULL) { | |
| 186 if (obs->WillProcessEvent(xevent)) | |
| 187 return true; | |
| 188 } | |
| 189 return false; | |
| 190 } | |
| 191 | |
| 192 void MessagePumpX::DidProcessXEvent(XEvent* xevent) { | |
| 193 FOR_EACH_OBSERVER(MessagePumpObserver, observers(), DidProcessEvent(xevent)); | |
| 194 } | |
| 195 | |
| 196 } // namespace base | |
| OLD | NEW |