| 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 |