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 <gdk/gdkx.h> |
7 #include <X11/extensions/XInput2.h> | 8 #include <X11/extensions/XInput2.h> |
8 | 9 |
9 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
10 #include "base/message_loop.h" | 11 #include "base/message_loop.h" |
11 | 12 |
12 #if defined(TOOLKIT_USES_GTK) | |
13 #include <gdk/gdkx.h> | |
14 #endif | |
15 | |
16 namespace { | 13 namespace { |
17 | 14 |
18 gboolean XSourcePrepare(GSource* source, gint* timeout_ms) { | 15 gboolean XSourcePrepare(GSource* source, gint* timeout_ms) { |
19 if (XPending(base::MessagePumpX::GetDefaultXDisplay())) | 16 if (XPending(base::MessagePumpX::GetDefaultXDisplay())) |
20 *timeout_ms = 0; | 17 *timeout_ms = 0; |
21 else | 18 else |
22 *timeout_ms = -1; | 19 *timeout_ms = -1; |
23 return FALSE; | 20 return FALSE; |
24 } | 21 } |
25 | 22 |
(...skipping 10 matching lines...) Expand all Loading... |
36 return TRUE; | 33 return TRUE; |
37 } | 34 } |
38 | 35 |
39 GSourceFuncs XSourceFuncs = { | 36 GSourceFuncs XSourceFuncs = { |
40 XSourcePrepare, | 37 XSourcePrepare, |
41 XSourceCheck, | 38 XSourceCheck, |
42 XSourceDispatch, | 39 XSourceDispatch, |
43 NULL | 40 NULL |
44 }; | 41 }; |
45 | 42 |
| 43 // A flag to disable GTK's message pump. This is intermediate step |
| 44 // to remove gtk and will be removed once migration is complete. |
| 45 bool use_gtk_message_pump = true; |
| 46 |
46 // The opcode used for checking events. | 47 // The opcode used for checking events. |
47 int xiopcode = -1; | 48 int xiopcode = -1; |
48 | 49 |
49 // When the GTK/GDK event processing is disabled, the message-pump opens a | 50 // When the GTK/GDK event processing is disabled, the message-pump opens a |
50 // connection to the display and owns it. | 51 // connection to the display and owns it. |
51 Display* g_xdisplay = NULL; | 52 Display* g_xdisplay = NULL; |
52 | 53 |
53 #if defined(TOOLKIT_USES_GTK) | |
54 // A flag to disable GTK's message pump. This is intermediate step | |
55 // to remove gtk and will be removed once migration is complete. | |
56 bool use_gtk_message_pump = true; | |
57 | |
58 gboolean PlaceholderDispatch(GSource* source, | 54 gboolean PlaceholderDispatch(GSource* source, |
59 GSourceFunc cb, | 55 GSourceFunc cb, |
60 gpointer data) { | 56 gpointer data) { |
61 return TRUE; | 57 return TRUE; |
62 } | 58 } |
63 #endif // defined(TOOLKIT_USES_GTK) | |
64 | 59 |
65 void InitializeXInput2(void) { | 60 void InitializeXInput2(void) { |
66 Display* display = base::MessagePumpX::GetDefaultXDisplay(); | 61 Display* display = base::MessagePumpX::GetDefaultXDisplay(); |
67 if (!display) | 62 if (!display) |
68 return; | 63 return; |
69 | 64 |
70 int event, err; | 65 int event, err; |
71 | 66 |
72 if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) { | 67 if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) { |
73 VLOG(1) << "X Input extension not available."; | 68 VLOG(1) << "X Input extension not available."; |
74 xiopcode = -1; | 69 xiopcode = -1; |
75 return; | 70 return; |
76 } | 71 } |
77 | 72 |
78 int major = 2, minor = 0; | 73 int major = 2, minor = 0; |
79 if (XIQueryVersion(display, &major, &minor) == BadRequest) { | 74 if (XIQueryVersion(display, &major, &minor) == BadRequest) { |
80 VLOG(1) << "XInput2 not supported in the server."; | 75 VLOG(1) << "XInput2 not supported in the server."; |
81 xiopcode = -1; | 76 xiopcode = -1; |
82 return; | 77 return; |
83 } | 78 } |
84 } | 79 } |
85 | 80 |
86 } // namespace | 81 } // namespace |
87 | 82 |
88 namespace base { | 83 namespace base { |
89 | 84 |
90 MessagePumpX::MessagePumpX() : MessagePumpGlib(), | 85 MessagePumpX::MessagePumpX() : MessagePumpGlib(), |
91 #if defined(TOOLKIT_USES_GTK) | 86 x_source_(NULL), |
92 gdksource_(NULL), | 87 gdksource_(NULL), |
93 dispatching_event_(false), | 88 dispatching_event_(false), |
94 capture_x_events_(0), | 89 capture_x_events_(0), |
95 capture_gdk_events_(0), | 90 capture_gdk_events_(0) { |
96 #endif | |
97 x_source_(NULL) { | |
98 InitializeXInput2(); | |
99 #if defined(TOOLKIT_USES_GTK) | |
100 if (use_gtk_message_pump) { | 91 if (use_gtk_message_pump) { |
101 gdk_window_add_filter(NULL, &GdkEventFilter, this); | 92 gdk_window_add_filter(NULL, &GdkEventFilter, this); |
102 gdk_event_handler_set(&EventDispatcherX, this, NULL); | 93 gdk_event_handler_set(&EventDispatcherX, this, NULL); |
103 } else { | 94 } else { |
104 InitXSource(); | 95 GPollFD* x_poll = new GPollFD(); |
| 96 x_poll->fd = ConnectionNumber(g_xdisplay); |
| 97 x_poll->events = G_IO_IN; |
| 98 |
| 99 x_source_ = g_source_new(&XSourceFuncs, sizeof(GSource)); |
| 100 g_source_add_poll(x_source_, x_poll); |
| 101 g_source_set_can_recurse(x_source_, FALSE); |
| 102 g_source_attach(x_source_, g_main_context_default()); |
105 } | 103 } |
| 104 |
| 105 InitializeXInput2(); |
106 if (use_gtk_message_pump) | 106 if (use_gtk_message_pump) |
107 InitializeEventsToCapture(); | 107 InitializeEventsToCapture(); |
108 #else | |
109 InitXSource(); | |
110 #endif | |
111 } | 108 } |
112 | 109 |
113 MessagePumpX::~MessagePumpX() { | 110 MessagePumpX::~MessagePumpX() { |
114 #if defined(TOOLKIT_USES_GTK) | |
115 if (use_gtk_message_pump) { | 111 if (use_gtk_message_pump) { |
116 gdk_window_remove_filter(NULL, &GdkEventFilter, this); | 112 gdk_window_remove_filter(NULL, &GdkEventFilter, this); |
117 gdk_event_handler_set(reinterpret_cast<GdkEventFunc>(gtk_main_do_event), | 113 gdk_event_handler_set(reinterpret_cast<GdkEventFunc>(gtk_main_do_event), |
118 this, NULL); | 114 this, NULL); |
119 return; | 115 } else { |
| 116 g_source_destroy(x_source_); |
| 117 g_source_unref(x_source_); |
| 118 XCloseDisplay(g_xdisplay); |
| 119 g_xdisplay = NULL; |
120 } | 120 } |
121 #endif | |
122 | |
123 g_source_destroy(x_source_); | |
124 g_source_unref(x_source_); | |
125 XCloseDisplay(g_xdisplay); | |
126 g_xdisplay = NULL; | |
127 } | 121 } |
128 | 122 |
129 #if defined(TOOLKIT_USES_GTK) | |
130 // static | 123 // static |
131 void MessagePumpX::DisableGtkMessagePump() { | 124 void MessagePumpX::DisableGtkMessagePump() { |
132 use_gtk_message_pump = false; | 125 use_gtk_message_pump = false; |
| 126 g_xdisplay = XOpenDisplay(NULL); |
133 } | 127 } |
134 #endif | |
135 | 128 |
136 // static | 129 // static |
137 Display* MessagePumpX::GetDefaultXDisplay() { | 130 Display* MessagePumpX::GetDefaultXDisplay() { |
138 #if defined(TOOLKIT_USES_GTK) | |
139 if (use_gtk_message_pump) { | 131 if (use_gtk_message_pump) { |
140 static GdkDisplay* display = gdk_display_get_default(); | 132 static GdkDisplay* display = gdk_display_get_default(); |
141 return display ? GDK_DISPLAY_XDISPLAY(display) : NULL; | 133 return display ? GDK_DISPLAY_XDISPLAY(display) : NULL; |
| 134 } else { |
| 135 return g_xdisplay; |
142 } | 136 } |
143 #endif | |
144 if (!g_xdisplay) | |
145 g_xdisplay = XOpenDisplay(NULL); | |
146 return g_xdisplay; | |
147 } | 137 } |
148 | 138 |
149 // static | 139 // static |
150 bool MessagePumpX::HasXInput2() { | 140 bool MessagePumpX::HasXInput2() { |
151 return xiopcode != -1; | 141 return xiopcode != -1; |
152 } | 142 } |
153 | 143 |
154 void MessagePumpX::InitXSource() { | |
155 DCHECK(!x_source_); | |
156 GPollFD* x_poll = new GPollFD(); | |
157 x_poll->fd = ConnectionNumber(g_xdisplay); | |
158 x_poll->events = G_IO_IN; | |
159 | |
160 x_source_ = g_source_new(&XSourceFuncs, sizeof(GSource)); | |
161 g_source_add_poll(x_source_, x_poll); | |
162 g_source_set_can_recurse(x_source_, FALSE); | |
163 g_source_attach(x_source_, g_main_context_default()); | |
164 } | |
165 | |
166 bool MessagePumpX::ShouldCaptureXEvent(XEvent* xev) { | 144 bool MessagePumpX::ShouldCaptureXEvent(XEvent* xev) { |
167 return | 145 return (!use_gtk_message_pump || capture_x_events_[xev->type]) |
168 #if defined(TOOLKIT_USES_GTK) | 146 && (xev->type != GenericEvent || xev->xcookie.extension == xiopcode); |
169 (!use_gtk_message_pump || capture_x_events_[xev->type]) && | |
170 #endif | |
171 (xev->type != GenericEvent || xev->xcookie.extension == xiopcode); | |
172 } | 147 } |
173 | 148 |
174 bool MessagePumpX::ProcessXEvent(XEvent* xev) { | 149 bool MessagePumpX::ProcessXEvent(XEvent* xev) { |
175 bool should_quit = false; | 150 bool should_quit = false; |
176 | 151 |
177 bool have_cookie = false; | 152 bool have_cookie = false; |
178 if (xev->type == GenericEvent && | 153 if (xev->type == GenericEvent && |
179 XGetEventData(xev->xgeneric.display, &xev->xcookie)) { | 154 XGetEventData(xev->xgeneric.display, &xev->xcookie)) { |
180 have_cookie = true; | 155 have_cookie = true; |
181 } | 156 } |
(...skipping 23 matching lines...) Expand all Loading... |
205 return g_main_context_iteration(context, block); | 180 return g_main_context_iteration(context, block); |
206 | 181 |
207 if (XPending(display)) { | 182 if (XPending(display)) { |
208 XEvent xev; | 183 XEvent xev; |
209 XPeekEvent(display, &xev); | 184 XPeekEvent(display, &xev); |
210 | 185 |
211 if (ShouldCaptureXEvent(&xev)) { | 186 if (ShouldCaptureXEvent(&xev)) { |
212 XNextEvent(display, &xev); | 187 XNextEvent(display, &xev); |
213 if (ProcessXEvent(&xev)) | 188 if (ProcessXEvent(&xev)) |
214 return true; | 189 return true; |
215 #if defined(TOOLKIT_USES_GTK) | |
216 } else if (use_gtk_message_pump && gdksource_) { | 190 } else if (use_gtk_message_pump && gdksource_) { |
217 // TODO(sad): A couple of extra events can still sneak in during this. | 191 // TODO(sad): A couple of extra events can still sneak in during this. |
218 // Those should be sent back to the X queue from the dispatcher | 192 // Those should be sent back to the X queue from the dispatcher |
219 // EventDispatcherX. | 193 // EventDispatcherX. |
220 gdksource_->source_funcs->dispatch = gdkdispatcher_; | 194 gdksource_->source_funcs->dispatch = gdkdispatcher_; |
221 g_main_context_iteration(context, FALSE); | 195 g_main_context_iteration(context, FALSE); |
222 #endif | |
223 } | 196 } |
224 } | 197 } |
225 | 198 |
226 bool retvalue; | 199 bool retvalue; |
227 #if defined(TOOLKIT_USES_GTK) | |
228 if (gdksource_ && use_gtk_message_pump) { | 200 if (gdksource_ && use_gtk_message_pump) { |
229 // Replace the dispatch callback of the GDK event source temporarily so that | 201 // Replace the dispatch callback of the GDK event source temporarily so that |
230 // it doesn't read events from X. | 202 // it doesn't read events from X. |
231 gboolean (*cb)(GSource*, GSourceFunc, void*) = | 203 gboolean (*cb)(GSource*, GSourceFunc, void*) = |
232 gdksource_->source_funcs->dispatch; | 204 gdksource_->source_funcs->dispatch; |
233 gdksource_->source_funcs->dispatch = PlaceholderDispatch; | 205 gdksource_->source_funcs->dispatch = PlaceholderDispatch; |
234 | 206 |
235 dispatching_event_ = true; | 207 dispatching_event_ = true; |
236 retvalue = g_main_context_iteration(context, block); | 208 retvalue = g_main_context_iteration(context, block); |
237 dispatching_event_ = false; | 209 dispatching_event_ = false; |
238 | 210 |
239 gdksource_->source_funcs->dispatch = cb; | 211 gdksource_->source_funcs->dispatch = cb; |
240 } else { | 212 } else { |
241 retvalue = g_main_context_iteration(context, block); | 213 retvalue = g_main_context_iteration(context, block); |
242 } | 214 } |
243 #else | |
244 retvalue = g_main_context_iteration(context, block); | |
245 #endif | |
246 | 215 |
247 return retvalue; | 216 return retvalue; |
248 } | 217 } |
249 | 218 |
250 #if defined(TOOLKIT_USES_GTK) | |
251 GdkFilterReturn MessagePumpX::GdkEventFilter(GdkXEvent* gxevent, | 219 GdkFilterReturn MessagePumpX::GdkEventFilter(GdkXEvent* gxevent, |
252 GdkEvent* gevent, | 220 GdkEvent* gevent, |
253 gpointer data) { | 221 gpointer data) { |
254 MessagePumpX* pump = static_cast<MessagePumpX*>(data); | 222 MessagePumpX* pump = static_cast<MessagePumpX*>(data); |
255 XEvent* xev = static_cast<XEvent*>(gxevent); | 223 XEvent* xev = static_cast<XEvent*>(gxevent); |
256 | 224 |
257 if (pump->ShouldCaptureXEvent(xev) && pump->GetDispatcher()) { | 225 if (pump->ShouldCaptureXEvent(xev) && pump->GetDispatcher()) { |
258 pump->ProcessXEvent(xev); | 226 pump->ProcessXEvent(xev); |
259 return GDK_FILTER_REMOVE; | 227 return GDK_FILTER_REMOVE; |
260 } | 228 } |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
304 | 272 |
305 capture_x_events_[ButtonRelease] = true; | 273 capture_x_events_[ButtonRelease] = true; |
306 capture_gdk_events_[GDK_BUTTON_RELEASE] = true; | 274 capture_gdk_events_[GDK_BUTTON_RELEASE] = true; |
307 | 275 |
308 capture_x_events_[MotionNotify] = true; | 276 capture_x_events_[MotionNotify] = true; |
309 capture_gdk_events_[GDK_MOTION_NOTIFY] = true; | 277 capture_gdk_events_[GDK_MOTION_NOTIFY] = true; |
310 | 278 |
311 capture_x_events_[GenericEvent] = true; | 279 capture_x_events_[GenericEvent] = true; |
312 } | 280 } |
313 | 281 |
314 COMPILE_ASSERT(XLASTEvent >= LASTEvent, XLASTEvent_too_small); | |
315 | |
316 #endif // defined(TOOLKIT_USES_GTK) | |
317 | |
318 MessagePumpObserver::EventStatus | 282 MessagePumpObserver::EventStatus |
319 MessagePumpObserver::WillProcessXEvent(XEvent* xev) { | 283 MessagePumpObserver::WillProcessXEvent(XEvent* xev) { |
320 return EVENT_CONTINUE; | 284 return EVENT_CONTINUE; |
321 } | 285 } |
322 | 286 |
| 287 COMPILE_ASSERT(XLASTEvent >= LASTEvent, XLASTEvent_too_small); |
| 288 |
323 } // namespace base | 289 } // namespace base |
OLD | NEW |