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