OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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_pump_x.h" | 5 #include "base/message_pump_x.h" |
6 | 6 |
7 #include <X11/extensions/XInput2.h> | 7 #include <X11/extensions/XInput2.h> |
8 | 8 |
9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
11 | 11 |
12 #if defined(TOOLKIT_USES_GTK) | |
13 #include <gdk/gdkx.h> | |
14 #endif | |
15 | |
16 namespace { | 12 namespace { |
17 | 13 |
18 gboolean XSourcePrepare(GSource* source, gint* timeout_ms) { | 14 gboolean XSourcePrepare(GSource* source, gint* timeout_ms) { |
19 if (XPending(base::MessagePumpX::GetDefaultXDisplay())) | 15 if (XPending(base::MessagePumpX::GetDefaultXDisplay())) |
20 *timeout_ms = 0; | 16 *timeout_ms = 0; |
21 else | 17 else |
22 *timeout_ms = -1; | 18 *timeout_ms = -1; |
23 return FALSE; | 19 return FALSE; |
24 } | 20 } |
25 | 21 |
(...skipping 13 matching lines...) Expand all Loading... |
39 GSourceFuncs XSourceFuncs = { | 35 GSourceFuncs XSourceFuncs = { |
40 XSourcePrepare, | 36 XSourcePrepare, |
41 XSourceCheck, | 37 XSourceCheck, |
42 XSourceDispatch, | 38 XSourceDispatch, |
43 NULL | 39 NULL |
44 }; | 40 }; |
45 | 41 |
46 // The opcode used for checking events. | 42 // The opcode used for checking events. |
47 int xiopcode = -1; | 43 int xiopcode = -1; |
48 | 44 |
49 #if defined(TOOLKIT_USES_GTK) | 45 // The message-pump opens a connection to the display and owns it. |
50 gboolean PlaceholderDispatch(GSource* source, | |
51 GSourceFunc cb, | |
52 gpointer data) { | |
53 return TRUE; | |
54 } | |
55 #else | |
56 // If the GTK/GDK event processing is not present, the message-pump opens a | |
57 // connection to the display and owns it. | |
58 Display* g_xdisplay = NULL; | 46 Display* g_xdisplay = NULL; |
59 #endif // defined(TOOLKIT_USES_GTK) | |
60 | 47 |
61 void InitializeXInput2(void) { | 48 void InitializeXInput2(void) { |
62 Display* display = base::MessagePumpX::GetDefaultXDisplay(); | 49 Display* display = base::MessagePumpX::GetDefaultXDisplay(); |
63 if (!display) | 50 if (!display) |
64 return; | 51 return; |
65 | 52 |
66 int event, err; | 53 int event, err; |
67 | 54 |
68 if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) { | 55 if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) { |
69 DVLOG(1) << "X Input extension not available."; | 56 DVLOG(1) << "X Input extension not available."; |
(...skipping 20 matching lines...) Expand all Loading... |
90 return; | 77 return; |
91 } | 78 } |
92 #endif | 79 #endif |
93 } | 80 } |
94 | 81 |
95 } // namespace | 82 } // namespace |
96 | 83 |
97 namespace base { | 84 namespace base { |
98 | 85 |
99 MessagePumpX::MessagePumpX() : MessagePumpGlib(), | 86 MessagePumpX::MessagePumpX() : MessagePumpGlib(), |
100 #if defined(TOOLKIT_USES_GTK) | |
101 gdksource_(NULL), | |
102 dispatching_event_(false), | |
103 capture_x_events_(0), | |
104 capture_gdk_events_(0), | |
105 #endif | |
106 x_source_(NULL) { | 87 x_source_(NULL) { |
107 InitializeXInput2(); | 88 InitializeXInput2(); |
108 #if defined(TOOLKIT_USES_GTK) | |
109 gdk_window_add_filter(NULL, &GdkEventFilter, this); | |
110 gdk_event_handler_set(&EventDispatcherX, this, NULL); | |
111 InitializeEventsToCapture(); | |
112 #else | |
113 InitXSource(); | 89 InitXSource(); |
114 #endif | |
115 } | 90 } |
116 | 91 |
117 MessagePumpX::~MessagePumpX() { | 92 MessagePumpX::~MessagePumpX() { |
118 #if defined(TOOLKIT_USES_GTK) | |
119 gdk_window_remove_filter(NULL, &GdkEventFilter, this); | |
120 gdk_event_handler_set(reinterpret_cast<GdkEventFunc>(gtk_main_do_event), | |
121 this, NULL); | |
122 #else | |
123 g_source_destroy(x_source_); | 93 g_source_destroy(x_source_); |
124 g_source_unref(x_source_); | 94 g_source_unref(x_source_); |
125 XCloseDisplay(g_xdisplay); | 95 XCloseDisplay(g_xdisplay); |
126 g_xdisplay = NULL; | 96 g_xdisplay = NULL; |
127 #endif | |
128 } | 97 } |
129 | 98 |
130 // static | 99 // static |
131 Display* MessagePumpX::GetDefaultXDisplay() { | 100 Display* MessagePumpX::GetDefaultXDisplay() { |
132 #if defined(TOOLKIT_USES_GTK) | |
133 static GdkDisplay* display = gdk_display_get_default(); | |
134 return display ? GDK_DISPLAY_XDISPLAY(display) : NULL; | |
135 #else | |
136 if (!g_xdisplay) | 101 if (!g_xdisplay) |
137 g_xdisplay = XOpenDisplay(NULL); | 102 g_xdisplay = XOpenDisplay(NULL); |
138 return g_xdisplay; | 103 return g_xdisplay; |
139 #endif | |
140 } | 104 } |
141 | 105 |
142 // static | 106 // static |
143 bool MessagePumpX::HasXInput2() { | 107 bool MessagePumpX::HasXInput2() { |
144 return xiopcode != -1; | 108 return xiopcode != -1; |
145 } | 109 } |
146 | 110 |
147 void MessagePumpX::InitXSource() { | 111 void MessagePumpX::InitXSource() { |
148 DCHECK(!x_source_); | 112 DCHECK(!x_source_); |
149 GPollFD* x_poll = new GPollFD(); | 113 GPollFD* x_poll = new GPollFD(); |
150 Display* display = GetDefaultXDisplay(); | 114 Display* display = GetDefaultXDisplay(); |
151 DCHECK(display) << "Unable to get connection to X server"; | 115 DCHECK(display) << "Unable to get connection to X server"; |
152 x_poll->fd = ConnectionNumber(display); | 116 x_poll->fd = ConnectionNumber(display); |
153 x_poll->events = G_IO_IN; | 117 x_poll->events = G_IO_IN; |
154 | 118 |
155 x_source_ = g_source_new(&XSourceFuncs, sizeof(GSource)); | 119 x_source_ = g_source_new(&XSourceFuncs, sizeof(GSource)); |
156 g_source_add_poll(x_source_, x_poll); | 120 g_source_add_poll(x_source_, x_poll); |
157 g_source_set_can_recurse(x_source_, FALSE); | 121 g_source_set_can_recurse(x_source_, FALSE); |
158 g_source_attach(x_source_, g_main_context_default()); | 122 g_source_attach(x_source_, g_main_context_default()); |
159 } | 123 } |
160 | 124 |
161 bool MessagePumpX::ShouldCaptureXEvent(XEvent* xev) { | |
162 #if defined(TOOLKIT_USES_GTK) | |
163 return capture_x_events_[xev->type] && | |
164 (xev->type != GenericEvent || xev->xcookie.extension == xiopcode); | |
165 #else | |
166 // When not using GTK, we always handle all events ourselves, and always have | |
167 // to remove it from the queue, whether we do anything with it or not. | |
168 return true; | |
169 #endif | |
170 } | |
171 | |
172 bool MessagePumpX::ProcessXEvent(XEvent* xev) { | 125 bool MessagePumpX::ProcessXEvent(XEvent* xev) { |
173 bool should_quit = false; | 126 bool should_quit = false; |
174 | 127 |
175 bool have_cookie = false; | 128 bool have_cookie = false; |
176 if (xev->type == GenericEvent && | 129 if (xev->type == GenericEvent && |
177 XGetEventData(xev->xgeneric.display, &xev->xcookie)) { | 130 XGetEventData(xev->xgeneric.display, &xev->xcookie)) { |
178 have_cookie = true; | 131 have_cookie = true; |
179 } | 132 } |
180 | 133 |
181 if (WillProcessXEvent(xev) == EVENT_CONTINUE) { | 134 if (WillProcessXEvent(xev) == EVENT_CONTINUE) { |
(...skipping 18 matching lines...) Expand all Loading... |
200 | 153 |
201 bool MessagePumpX::RunOnce(GMainContext* context, bool block) { | 154 bool MessagePumpX::RunOnce(GMainContext* context, bool block) { |
202 Display* display = GetDefaultXDisplay(); | 155 Display* display = GetDefaultXDisplay(); |
203 if (!display || !GetDispatcher()) | 156 if (!display || !GetDispatcher()) |
204 return g_main_context_iteration(context, block); | 157 return g_main_context_iteration(context, block); |
205 | 158 |
206 // In the general case, we want to handle all pending events before running | 159 // In the general case, we want to handle all pending events before running |
207 // the tasks. This is what happens in the message_pump_glib case. | 160 // the tasks. This is what happens in the message_pump_glib case. |
208 while (XPending(display)) { | 161 while (XPending(display)) { |
209 XEvent xev; | 162 XEvent xev; |
210 XPeekEvent(display, &xev); | 163 XNextEvent(display, &xev); |
211 | 164 if (ProcessXEvent(&xev)) |
212 if (ShouldCaptureXEvent(&xev)) { | 165 return true; |
213 XNextEvent(display, &xev); | |
214 if (ProcessXEvent(&xev)) | |
215 return true; | |
216 #if defined(TOOLKIT_USES_GTK) | |
217 } else if (gdksource_) { | |
218 // TODO(sad): A couple of extra events can still sneak in during this. | |
219 // Those should be sent back to the X queue from the dispatcher | |
220 // EventDispatcherX. | |
221 gdksource_->source_funcs->dispatch = gdkdispatcher_; | |
222 g_main_context_iteration(context, FALSE); | |
223 #endif | |
224 } | |
225 #if defined(TOOLKIT_USES_GTK) | |
226 // In the GTK case, we only want to process one event at a time. | |
227 break; | |
228 #endif | |
229 } | 166 } |
230 | 167 |
231 bool retvalue; | 168 return g_main_context_iteration(context, block); |
232 #if defined(TOOLKIT_USES_GTK) | |
233 if (gdksource_) { | |
234 // Replace the dispatch callback of the GDK event source temporarily so that | |
235 // it doesn't read events from X. | |
236 gboolean (*cb)(GSource*, GSourceFunc, void*) = | |
237 gdksource_->source_funcs->dispatch; | |
238 gdksource_->source_funcs->dispatch = PlaceholderDispatch; | |
239 | |
240 dispatching_event_ = true; | |
241 retvalue = g_main_context_iteration(context, block); | |
242 dispatching_event_ = false; | |
243 | |
244 gdksource_->source_funcs->dispatch = cb; | |
245 } else { | |
246 retvalue = g_main_context_iteration(context, block); | |
247 } | |
248 #else | |
249 retvalue = g_main_context_iteration(context, block); | |
250 #endif | |
251 | |
252 return retvalue; | |
253 } | 169 } |
254 | 170 |
255 bool MessagePumpX::WillProcessXEvent(XEvent* xevent) { | 171 bool MessagePumpX::WillProcessXEvent(XEvent* xevent) { |
256 ObserverListBase<MessagePumpObserver>::Iterator it(observers()); | 172 ObserverListBase<MessagePumpObserver>::Iterator it(observers()); |
257 MessagePumpObserver* obs; | 173 MessagePumpObserver* obs; |
258 while ((obs = it.GetNext()) != NULL) { | 174 while ((obs = it.GetNext()) != NULL) { |
259 if (obs->WillProcessEvent(xevent)) | 175 if (obs->WillProcessEvent(xevent)) |
260 return true; | 176 return true; |
261 } | 177 } |
262 return false; | 178 return false; |
263 } | 179 } |
264 | 180 |
265 void MessagePumpX::DidProcessXEvent(XEvent* xevent) { | 181 void MessagePumpX::DidProcessXEvent(XEvent* xevent) { |
266 ObserverListBase<MessagePumpObserver>::Iterator it(observers()); | 182 ObserverListBase<MessagePumpObserver>::Iterator it(observers()); |
267 MessagePumpObserver* obs; | 183 MessagePumpObserver* obs; |
268 while ((obs = it.GetNext()) != NULL) { | 184 while ((obs = it.GetNext()) != NULL) { |
269 obs->DidProcessEvent(xevent); | 185 obs->DidProcessEvent(xevent); |
270 } | 186 } |
271 } | 187 } |
272 | 188 |
273 #if defined(TOOLKIT_USES_GTK) | |
274 GdkFilterReturn MessagePumpX::GdkEventFilter(GdkXEvent* gxevent, | |
275 GdkEvent* gevent, | |
276 gpointer data) { | |
277 MessagePumpX* pump = static_cast<MessagePumpX*>(data); | |
278 XEvent* xev = static_cast<XEvent*>(gxevent); | |
279 | |
280 if (pump->ShouldCaptureXEvent(xev) && pump->GetDispatcher()) { | |
281 pump->ProcessXEvent(xev); | |
282 return GDK_FILTER_REMOVE; | |
283 } | |
284 return GDK_FILTER_CONTINUE; | |
285 } | |
286 | |
287 void MessagePumpX::EventDispatcherX(GdkEvent* event, gpointer data) { | |
288 MessagePumpX* pump_x = reinterpret_cast<MessagePumpX*>(data); | |
289 if (!pump_x->gdksource_) { | |
290 pump_x->gdksource_ = g_main_current_source(); | |
291 if (pump_x->gdksource_) | |
292 pump_x->gdkdispatcher_ = pump_x->gdksource_->source_funcs->dispatch; | |
293 } else if (!pump_x->IsDispatchingEvent()) { | |
294 if (event->type != GDK_NOTHING && | |
295 pump_x->capture_gdk_events_[event->type]) { | |
296 NOTREACHED() << "GDK received an event it shouldn't have:" << event->type; | |
297 } | |
298 } | |
299 | |
300 gtk_main_do_event(event); | |
301 } | |
302 | |
303 void MessagePumpX::InitializeEventsToCapture(void) { | |
304 // TODO(sad): Decide which events we want to capture and update the tables | |
305 // accordingly. | |
306 capture_x_events_[KeyPress] = true; | |
307 capture_gdk_events_[GDK_KEY_PRESS] = true; | |
308 | |
309 capture_x_events_[KeyRelease] = true; | |
310 capture_gdk_events_[GDK_KEY_RELEASE] = true; | |
311 | |
312 capture_x_events_[ButtonPress] = true; | |
313 capture_gdk_events_[GDK_BUTTON_PRESS] = true; | |
314 | |
315 capture_x_events_[ButtonRelease] = true; | |
316 capture_gdk_events_[GDK_BUTTON_RELEASE] = true; | |
317 | |
318 capture_x_events_[MotionNotify] = true; | |
319 capture_gdk_events_[GDK_MOTION_NOTIFY] = true; | |
320 | |
321 capture_x_events_[GenericEvent] = true; | |
322 } | |
323 | |
324 COMPILE_ASSERT(XLASTEvent >= LASTEvent, XLASTEvent_too_small); | |
325 | |
326 #endif // defined(TOOLKIT_USES_GTK) | |
327 | |
328 } // namespace base | 189 } // namespace base |
OLD | NEW |