Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(198)

Side by Side Diff: base/message_pump_glib_x.cc

Issue 4186004: touchui: First pass at XInput2 message pump. (Closed) Base URL: http://git.chromium.org/git/chromium.git
Patch Set: gyp fiddling Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/message_pump_glib_x.h ('k') | build/linux/system.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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)
9 #include <X11/extensions/XInput2.h>
10 #else
8 #include <X11/Xlib.h> 11 #include <X11/Xlib.h>
12 #endif
9 13
10 #include "base/message_pump_glib_x_dispatch.h" 14 #include "base/message_pump_glib_x_dispatch.h"
11 15
12 namespace { 16 namespace {
13 17
14 gboolean PlaceholderDispatch(GSource* source, 18 gboolean PlaceholderDispatch(GSource* source,
15 GSourceFunc cb, 19 GSourceFunc cb,
16 gpointer data) { 20 gpointer data) {
17 return TRUE; 21 return TRUE;
18 } 22 }
19 23
24 #if defined(HAVE_XINPUT2)
25
26 // Setup XInput2 select for the GtkWidget.
27 gboolean GtkWidgetRealizeCallback(GSignalInvocationHint* hint, guint nparams,
28 const GValue* pvalues, gpointer data) {
29 GtkWidget* widget = GTK_WIDGET(g_value_get_object(pvalues));
30 GdkWindow* window = widget->window;
31 base::MessagePumpGlibX* msgpump = static_cast<base::MessagePumpGlibX*>(data);
32
33 DCHECK(window); // TODO(sad): Remove once determined if necessary.
34
35 // TODO(sad): Do we need to set a flag on |window| to make sure we don't
36 // select for the same GdkWindow multiple times? Does it matter?
37 msgpump->SetupXInput2ForXWindow(GDK_WINDOW_XID(window));
38
39 return true;
40 }
41
42 // We need to capture all the GDK windows that get created, and start
43 // listening for XInput2 events. So we setup a callback to the 'realize'
44 // signal for GTK+ widgets, so that whenever the signal triggers for any
45 // GtkWidget, which means the GtkWidget should now have a GdkWindow, we can
46 // setup XInput2 events for the GdkWindow.
47 void SetupGtkWidgetRealizeNotifier(base::MessagePumpGlibX* msgpump) {
48 guint signal_id;
49 gpointer klass = g_type_class_ref(GTK_TYPE_WIDGET);
50
51 g_signal_parse_name("realize", GTK_TYPE_WIDGET, &signal_id, NULL, FALSE);
52 g_signal_add_emission_hook(signal_id, 0, GtkWidgetRealizeCallback,
53 static_cast<gpointer>(msgpump), NULL);
54
55 g_type_class_unref(klass);
56 }
57
58 #endif // HAVE_XINPUT2
59
20 } // namespace 60 } // namespace
21 61
22 namespace base { 62 namespace base {
23 63
24 MessagePumpGlibX::MessagePumpGlibX() : base::MessagePumpForUI(), 64 MessagePumpGlibX::MessagePumpGlibX() : base::MessagePumpForUI(),
65 #if defined(HAVE_XINPUT2)
66 xiopcode_(-1),
67 masters_(),
68 slaves_(),
69 #endif
25 gdksource_(NULL), 70 gdksource_(NULL),
26 dispatching_event_(false), 71 dispatching_event_(false),
27 capture_x_events_(0), 72 capture_x_events_(0),
28 capture_gdk_events_(0) { 73 capture_gdk_events_(0) {
29 gdk_event_handler_set(&EventDispatcherX, this, NULL); 74 gdk_event_handler_set(&EventDispatcherX, this, NULL);
30 75
76 #if defined(HAVE_XINPUT2)
77 InitializeXInput2();
78 #endif
31 InitializeEventsToCapture(); 79 InitializeEventsToCapture();
32 } 80 }
33 81
34 MessagePumpGlibX::~MessagePumpGlibX() { 82 MessagePumpGlibX::~MessagePumpGlibX() {
35 } 83 }
36 84
37 bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) { 85 bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) {
38 GdkDisplay* gdisp = gdk_display_get_default(); 86 GdkDisplay* gdisp = gdk_display_get_default();
39 Display* display = GDK_DISPLAY_XDISPLAY(gdisp); 87 Display* display = GDK_DISPLAY_XDISPLAY(gdisp);
40 if (XPending(display)) { 88 if (XPending(display)) {
41 XEvent xev; 89 XEvent xev;
42 XPeekEvent(display, &xev); 90 XPeekEvent(display, &xev);
43 if (capture_x_events_[xev.type]) { 91 if (capture_x_events_[xev.type]
92 #if defined(HAVE_XINPUT2)
93 && (xev.type != GenericEvent || xev.xcookie.extension == xiopcode_)
94 #endif
95 ) {
44 XNextEvent(display, &xev); 96 XNextEvent(display, &xev);
45 97
46 bool processed = static_cast<MessagePumpGlibXDispatcher*> 98 bool processed = static_cast<MessagePumpGlibXDispatcher*>
47 (GetDispatcher())->Dispatch(&xev); 99 (GetDispatcher())->Dispatch(&xev);
48 100
49 if (!processed) { 101 if (!processed) {
50 DLOG(WARNING) << "Event (" << xev.type << ") not handled."; 102 DLOG(WARNING) << "Event (" << xev.type << ") not handled.";
103
104 // TODO(sad): It is necessary to put back the event so that the default
105 // GDK events handler can take care of it. Without this, it is
106 // impossible to use the omnibox at the moment. However, this will
107 // eventually be removed once the omnibox code is updated for touchui.
108 XPutBackEvent(display, &xev);
109 g_main_context_iteration(context, FALSE);
51 } 110 }
52 } else { 111 } else {
53 // TODO(sad): A couple of extra events can still sneak in during this. 112 // TODO(sad): A couple of extra events can still sneak in during this.
54 // Those should be sent back to the X queue from the dispatcher 113 // Those should be sent back to the X queue from the dispatcher
55 // EventDispatcherX. 114 // EventDispatcherX.
56 g_main_context_iteration(context, FALSE); 115 g_main_context_iteration(context, FALSE);
57 } 116 }
58 } 117 }
59 118
60 bool retvalue; 119 bool retvalue;
(...skipping 26 matching lines...) Expand all
87 capture_gdk_events_[GDK_KEY_RELEASE] = true; 146 capture_gdk_events_[GDK_KEY_RELEASE] = true;
88 147
89 capture_x_events_[ButtonPress] = true; 148 capture_x_events_[ButtonPress] = true;
90 capture_gdk_events_[GDK_BUTTON_PRESS] = true; 149 capture_gdk_events_[GDK_BUTTON_PRESS] = true;
91 150
92 capture_x_events_[ButtonRelease] = true; 151 capture_x_events_[ButtonRelease] = true;
93 capture_gdk_events_[GDK_BUTTON_RELEASE] = true; 152 capture_gdk_events_[GDK_BUTTON_RELEASE] = true;
94 153
95 capture_x_events_[MotionNotify] = true; 154 capture_x_events_[MotionNotify] = true;
96 capture_gdk_events_[GDK_MOTION_NOTIFY] = true; 155 capture_gdk_events_[GDK_MOTION_NOTIFY] = true;
156
157 #if defined(HAVE_XINPUT2)
158 capture_x_events_[GenericEvent] = true;
159 #endif
97 } 160 }
98 161
162 #if defined(HAVE_XINPUT2)
163 void MessagePumpGlibX::InitializeXInput2(void) {
164 GdkDisplay* display = gdk_display_get_default();
165 Display* xdisplay = GDK_DISPLAY_XDISPLAY(display);
166 int event, err;
167
168 if (!XQueryExtension(xdisplay, "XInputExtension", &xiopcode_, &event, &err)) {
169 DLOG(WARNING) << "X Input extension not available.";
170 xiopcode_ = -1;
171 return;
172 }
173
174 int major = 2, minor = 0;
175 if (XIQueryVersion(xdisplay, &major, &minor) == BadRequest) {
176 DLOG(WARNING) << "XInput2 not supported in the server.";
177 xiopcode_ = -1;
178 return;
179 }
180
181 SetupGtkWidgetRealizeNotifier(this);
182
183 // Instead of asking X for the list of devices all the time, let's maintain a
184 // list of slave (physical) and master (virtual) pointer devices.
185 int count = 0;
186 XIDeviceInfo* devices = XIQueryDevice(xdisplay, XIAllDevices, &count);
187 for (int i = 0; i < count; i++) {
188 XIDeviceInfo* devinfo = devices + i;
189 if (devinfo->use == XISlavePointer) {
190 slaves_.insert(devinfo->deviceid);
191 } else if (devinfo->use == XIMasterPointer) {
192 masters_.insert(devinfo->deviceid);
193 }
194 // We do not need to care about XIFloatingSlave, because the callback for
195 // XI_HierarchyChanged event will take care of it.
196 }
197 XIFreeDeviceInfo(devices);
198
199 // TODO(sad): Select on root for XI_HierarchyChanged so that slaves_ and
200 // masters_ can be kept up-to-date. This is a relatively rare event, so we can
201 // put it off for a later time.
202 // Note: It is not necessary to listen for XI_DeviceChanged events.
203 }
204
205 void MessagePumpGlibX::SetupXInput2ForXWindow(Window xwindow) {
206 Display* xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
207
208 // Setup mask for mouse events.
209 unsigned char mask[(XI_LASTEVENT + 7)/8];
210 memset(mask, 0, sizeof(mask));
211
212 XISetMask(mask, XI_ButtonPress);
213 XISetMask(mask, XI_ButtonRelease);
214 XISetMask(mask, XI_Motion);
215
216 // It is necessary to select only for the master devices. XInput2 provides
217 // enough information to the event callback to decide which slave device
218 // triggered the event, thus decide whether the 'pointer event' is a 'mouse
219 // event' or a 'touch event'. So it is not necessary to select for the slave
220 // devices here.
221 XIEventMask evmasks[masters_.size()];
222 int count = 0;
223 for (std::set<int>::const_iterator iter = masters_.begin();
224 iter != masters_.end();
225 ++iter, ++count) {
226 evmasks[count].deviceid = *iter;
227 evmasks[count].mask_len = sizeof(mask);
228 evmasks[count].mask = mask;
229 }
230
231 XISelectEvents(xdisplay, xwindow, evmasks, masters_.size());
232
233 // TODO(sad): Setup masks for keyboard events.
234
235 XFlush(xdisplay);
236 }
237
238 #endif // HAVE_XINPUT2
239
99 void MessagePumpGlibX::EventDispatcherX(GdkEvent* event, gpointer data) { 240 void MessagePumpGlibX::EventDispatcherX(GdkEvent* event, gpointer data) {
100 MessagePumpGlibX* pump_x = reinterpret_cast<MessagePumpGlibX*>(data); 241 MessagePumpGlibX* pump_x = reinterpret_cast<MessagePumpGlibX*>(data);
101 242
102 if (!pump_x->gdksource_) { 243 if (!pump_x->gdksource_) {
103 pump_x->gdksource_ = g_main_current_source(); 244 pump_x->gdksource_ = g_main_current_source();
104 } else if (!pump_x->IsDispatchingEvent()) { 245 } else if (!pump_x->IsDispatchingEvent()) {
105 if (event->type != GDK_NOTHING && 246 if (event->type != GDK_NOTHING &&
106 pump_x->capture_gdk_events_[event->type]) { 247 pump_x->capture_gdk_events_[event->type]) {
107 // TODO(sad): An X event is caught by the GDK handler. Put it back in the 248 // TODO(sad): An X event is caught by the GDK handler. Put it back in the
108 // X queue so that we catch it in the next iteration. When done, the 249 // X queue so that we catch it in the next iteration. When done, the
109 // following DLOG statement will be removed. 250 // following DLOG statement will be removed.
110 DLOG(WARNING) << "GDK received an event it shouldn't have"; 251 DLOG(WARNING) << "GDK received an event it shouldn't have";
111 } 252 }
112 } 253 }
113 254
114 pump_x->DispatchEvents(event); 255 pump_x->DispatchEvents(event);
115 } 256 }
116 257
117 } // namespace base 258 } // namespace base
OLDNEW
« no previous file with comments | « base/message_pump_glib_x.h ('k') | build/linux/system.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698