| 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_glib_x.h" | 5 #include "base/message_pump_glib_x.h" |
| 6 | 6 |
| 7 #include <gdk/gdkx.h> | 7 #include <gdk/gdkx.h> |
| 8 #if defined(HAVE_XINPUT2) | 8 #if defined(HAVE_XINPUT2) |
| 9 #include <X11/extensions/XInput2.h> | 9 #include <X11/extensions/XInput2.h> |
| 10 #else | 10 #else |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 namespace base { | 26 namespace base { |
| 27 | 27 |
| 28 MessagePumpGlibX::MessagePumpGlibX() : base::MessagePumpForUI(), | 28 MessagePumpGlibX::MessagePumpGlibX() : base::MessagePumpForUI(), |
| 29 #if defined(HAVE_XINPUT2) | 29 #if defined(HAVE_XINPUT2) |
| 30 xiopcode_(-1), | 30 xiopcode_(-1), |
| 31 #endif | 31 #endif |
| 32 gdksource_(NULL), | 32 gdksource_(NULL), |
| 33 dispatching_event_(false), | 33 dispatching_event_(false), |
| 34 capture_x_events_(0), | 34 capture_x_events_(0), |
| 35 capture_gdk_events_(0) { | 35 capture_gdk_events_(0) { |
| 36 gdk_window_add_filter(NULL, &GdkEventFilter, this); |
| 36 gdk_event_handler_set(&EventDispatcherX, this, NULL); | 37 gdk_event_handler_set(&EventDispatcherX, this, NULL); |
| 37 | 38 |
| 38 #if defined(HAVE_XINPUT2) | 39 #if defined(HAVE_XINPUT2) |
| 39 InitializeXInput2(); | 40 InitializeXInput2(); |
| 40 #endif | 41 #endif |
| 41 InitializeEventsToCapture(); | 42 InitializeEventsToCapture(); |
| 42 } | 43 } |
| 43 | 44 |
| 44 MessagePumpGlibX::~MessagePumpGlibX() { | 45 MessagePumpGlibX::~MessagePumpGlibX() { |
| 45 } | 46 } |
| 46 | 47 |
| 48 bool MessagePumpGlibX::ShouldCaptureXEvent(XEvent* xev) { |
| 49 return capture_x_events_[xev->type] |
| 50 #if defined(HAVE_XINPUT2) |
| 51 && (xev->type != GenericEvent || xev->xcookie.extension == xiopcode_) |
| 52 #endif |
| 53 ; |
| 54 } |
| 55 |
| 56 |
| 57 bool MessagePumpGlibX::ProcessXEvent(XEvent* xev) { |
| 58 bool should_quit = false; |
| 59 |
| 60 #if defined(HAVE_XINPUT2) |
| 61 bool have_cookie = false; |
| 62 if (xev->type == GenericEvent && |
| 63 XGetEventData(xev->xgeneric.display, &xev->xcookie)) { |
| 64 have_cookie = true; |
| 65 } |
| 66 #endif |
| 67 |
| 68 if (!WillProcessXEvent(xev)) { |
| 69 MessagePumpGlibXDispatcher::DispatchStatus status = |
| 70 static_cast<MessagePumpGlibXDispatcher*> |
| 71 (GetDispatcher())->DispatchX(xev); |
| 72 |
| 73 if (status == MessagePumpGlibXDispatcher::EVENT_QUIT) { |
| 74 should_quit = true; |
| 75 Quit(); |
| 76 } else if (status == MessagePumpGlibXDispatcher::EVENT_IGNORED) { |
| 77 DLOG(WARNING) << "Event (" << xev->type << ") not handled."; |
| 78 } |
| 79 } |
| 80 |
| 81 #if defined(HAVE_XINPUT2) |
| 82 if (have_cookie) { |
| 83 XFreeEventData(xev->xgeneric.display, &xev->xcookie); |
| 84 } |
| 85 #endif |
| 86 |
| 87 return should_quit; |
| 88 } |
| 89 |
| 47 bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) { | 90 bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) { |
| 48 GdkDisplay* gdisp = gdk_display_get_default(); | 91 GdkDisplay* gdisp = gdk_display_get_default(); |
| 49 if (!gdisp || !GetDispatcher()) | 92 if (!gdisp || !GetDispatcher()) |
| 50 return MessagePumpForUI::RunOnce(context, block); | 93 return MessagePumpForUI::RunOnce(context, block); |
| 51 | 94 |
| 52 Display* display = GDK_DISPLAY_XDISPLAY(gdisp); | 95 Display* display = GDK_DISPLAY_XDISPLAY(gdisp); |
| 53 bool should_quit = false; | |
| 54 | 96 |
| 55 if (XPending(display)) { | 97 if (XPending(display)) { |
| 56 XEvent xev; | 98 XEvent xev; |
| 57 XPeekEvent(display, &xev); | 99 XPeekEvent(display, &xev); |
| 58 if (capture_x_events_[xev.type] | 100 |
| 59 #if defined(HAVE_XINPUT2) | 101 if (ShouldCaptureXEvent(&xev)) { |
| 60 && (xev.type != GenericEvent || xev.xcookie.extension == xiopcode_) | |
| 61 #endif | |
| 62 ) { | |
| 63 XNextEvent(display, &xev); | 102 XNextEvent(display, &xev); |
| 64 | 103 if (ProcessXEvent(&xev)) |
| 65 #if defined(HAVE_XINPUT2) | 104 return true; |
| 66 bool have_cookie = false; | |
| 67 if (xev.type == GenericEvent && | |
| 68 XGetEventData(xev.xgeneric.display, &xev.xcookie)) { | |
| 69 have_cookie = true; | |
| 70 } | |
| 71 #endif | |
| 72 | |
| 73 if (!WillProcessXEvent(&xev)) { | |
| 74 MessagePumpGlibXDispatcher::DispatchStatus status = | |
| 75 static_cast<MessagePumpGlibXDispatcher*> | |
| 76 (GetDispatcher())->DispatchX(&xev); | |
| 77 | |
| 78 if (status == MessagePumpGlibXDispatcher::EVENT_QUIT) { | |
| 79 should_quit = true; | |
| 80 Quit(); | |
| 81 } else if (status == MessagePumpGlibXDispatcher::EVENT_IGNORED) { | |
| 82 DLOG(WARNING) << "Event (" << xev.type << ") not handled."; | |
| 83 } | |
| 84 } | |
| 85 | |
| 86 #if defined(HAVE_XINPUT2) | |
| 87 if (have_cookie) { | |
| 88 XFreeEventData(xev.xgeneric.display, &xev.xcookie); | |
| 89 } | |
| 90 #endif | |
| 91 } else { | 105 } else { |
| 92 // TODO(sad): A couple of extra events can still sneak in during this. | 106 // TODO(sad): A couple of extra events can still sneak in during this. |
| 93 // Those should be sent back to the X queue from the dispatcher | 107 // Those should be sent back to the X queue from the dispatcher |
| 94 // EventDispatcherX. | 108 // EventDispatcherX. |
| 95 if (gdksource_) | 109 if (gdksource_) |
| 96 gdksource_->source_funcs->dispatch = gdkdispatcher_; | 110 gdksource_->source_funcs->dispatch = gdkdispatcher_; |
| 97 g_main_context_iteration(context, FALSE); | 111 g_main_context_iteration(context, FALSE); |
| 98 } | 112 } |
| 99 } | 113 } |
| 100 | 114 |
| 101 if (should_quit) | |
| 102 return true; | |
| 103 | |
| 104 bool retvalue; | 115 bool retvalue; |
| 105 if (gdksource_) { | 116 if (gdksource_) { |
| 106 // Replace the dispatch callback of the GDK event source temporarily so that | 117 // Replace the dispatch callback of the GDK event source temporarily so that |
| 107 // it doesn't read events from X. | 118 // it doesn't read events from X. |
| 108 gboolean (*cb)(GSource*, GSourceFunc, void*) = | 119 gboolean (*cb)(GSource*, GSourceFunc, void*) = |
| 109 gdksource_->source_funcs->dispatch; | 120 gdksource_->source_funcs->dispatch; |
| 110 gdksource_->source_funcs->dispatch = PlaceholderDispatch; | 121 gdksource_->source_funcs->dispatch = PlaceholderDispatch; |
| 111 | 122 |
| 112 dispatching_event_ = true; | 123 dispatching_event_ = true; |
| 113 retvalue = g_main_context_iteration(context, block); | 124 retvalue = g_main_context_iteration(context, block); |
| 114 dispatching_event_ = false; | 125 dispatching_event_ = false; |
| 115 | 126 |
| 116 gdksource_->source_funcs->dispatch = cb; | 127 gdksource_->source_funcs->dispatch = cb; |
| 117 } else { | 128 } else { |
| 118 retvalue = g_main_context_iteration(context, block); | 129 retvalue = g_main_context_iteration(context, block); |
| 119 } | 130 } |
| 120 | 131 |
| 121 return retvalue; | 132 return retvalue; |
| 122 } | 133 } |
| 123 | 134 |
| 135 GdkFilterReturn MessagePumpGlibX::GdkEventFilter(GdkXEvent* gxevent, |
| 136 GdkEvent* gevent, |
| 137 gpointer data) { |
| 138 MessagePumpGlibX* pump = static_cast<MessagePumpGlibX*>(data); |
| 139 XEvent* xev = static_cast<XEvent*>(gxevent); |
| 140 |
| 141 if (pump->ShouldCaptureXEvent(xev) && pump->GetDispatcher()) { |
| 142 pump->ProcessXEvent(xev); |
| 143 return GDK_FILTER_REMOVE; |
| 144 } |
| 145 |
| 146 return GDK_FILTER_CONTINUE; |
| 147 } |
| 148 |
| 124 bool MessagePumpGlibX::WillProcessXEvent(XEvent* xevent) { | 149 bool MessagePumpGlibX::WillProcessXEvent(XEvent* xevent) { |
| 125 ObserverListBase<Observer>::Iterator it(observers()); | 150 ObserverListBase<Observer>::Iterator it(observers()); |
| 126 Observer* obs; | 151 Observer* obs; |
| 127 while ((obs = it.GetNext()) != NULL) { | 152 while ((obs = it.GetNext()) != NULL) { |
| 128 MessagePumpXObserver* xobs = | 153 MessagePumpXObserver* xobs = |
| 129 static_cast<MessagePumpXObserver*>(obs); | 154 static_cast<MessagePumpXObserver*>(obs); |
| 130 if (xobs->WillProcessXEvent(xevent)) | 155 if (xobs->WillProcessXEvent(xevent)) |
| 131 return true; | 156 return true; |
| 132 } | 157 } |
| 133 return false; | 158 return false; |
| 134 } | 159 } |
| 135 | 160 |
| 136 void MessagePumpGlibX::EventDispatcherX(GdkEvent* event, gpointer data) { | 161 void MessagePumpGlibX::EventDispatcherX(GdkEvent* event, gpointer data) { |
| 137 MessagePumpGlibX* pump_x = reinterpret_cast<MessagePumpGlibX*>(data); | 162 MessagePumpGlibX* pump_x = reinterpret_cast<MessagePumpGlibX*>(data); |
| 138 | 163 |
| 139 if (!pump_x->gdksource_) { | 164 if (!pump_x->gdksource_) { |
| 140 pump_x->gdksource_ = g_main_current_source(); | 165 pump_x->gdksource_ = g_main_current_source(); |
| 141 if (pump_x->gdksource_) | 166 if (pump_x->gdksource_) |
| 142 pump_x->gdkdispatcher_ = pump_x->gdksource_->source_funcs->dispatch; | 167 pump_x->gdkdispatcher_ = pump_x->gdksource_->source_funcs->dispatch; |
| 143 } else if (!pump_x->IsDispatchingEvent()) { | 168 } else if (!pump_x->IsDispatchingEvent()) { |
| 144 if (event->type != GDK_NOTHING && | 169 if (event->type != GDK_NOTHING && |
| 145 pump_x->capture_gdk_events_[event->type]) { | 170 pump_x->capture_gdk_events_[event->type]) { |
| 146 // TODO(sad): An X event is caught by the GDK handler. Put it back in the | 171 NOTREACHED() << "GDK received an event it shouldn't have"; |
| 147 // X queue so that we catch it in the next iteration. When done, the | |
| 148 // following DLOG statement will be removed. | |
| 149 DLOG(WARNING) << "GDK received an event it shouldn't have"; | |
| 150 } | 172 } |
| 151 } | 173 } |
| 152 | 174 |
| 153 pump_x->DispatchEvents(event); | 175 pump_x->DispatchEvents(event); |
| 154 } | 176 } |
| 155 | 177 |
| 156 void MessagePumpGlibX::InitializeEventsToCapture(void) { | 178 void MessagePumpGlibX::InitializeEventsToCapture(void) { |
| 157 // TODO(sad): Decide which events we want to capture and update the tables | 179 // TODO(sad): Decide which events we want to capture and update the tables |
| 158 // accordingly. | 180 // accordingly. |
| 159 capture_x_events_[KeyPress] = true; | 181 capture_x_events_[KeyPress] = true; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 return; | 220 return; |
| 199 } | 221 } |
| 200 } | 222 } |
| 201 #endif // HAVE_XINPUT2 | 223 #endif // HAVE_XINPUT2 |
| 202 | 224 |
| 203 bool MessagePumpXObserver::WillProcessXEvent(XEvent* xev) { | 225 bool MessagePumpXObserver::WillProcessXEvent(XEvent* xev) { |
| 204 return false; | 226 return false; |
| 205 } | 227 } |
| 206 | 228 |
| 207 } // namespace base | 229 } // namespace base |
| OLD | NEW |