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