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