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

Side by Side Diff: base/message_pump_glib_x.cc

Issue 4894001: Revert 65938 (arm compile fail) - touchui: First pass at XInput2 message pump... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: 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
11 #include <X11/Xlib.h> 8 #include <X11/Xlib.h>
12 #endif
13 9
14 #include "base/message_pump_glib_x_dispatch.h" 10 #include "base/message_pump_glib_x_dispatch.h"
15 11
16 namespace { 12 namespace {
17 13
18 gboolean PlaceholderDispatch(GSource* source, 14 gboolean PlaceholderDispatch(GSource* source,
19 GSourceFunc cb, 15 GSourceFunc cb,
20 gpointer data) { 16 gpointer data) {
21 return TRUE; 17 return TRUE;
22 } 18 }
23 19
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
60 } // namespace 20 } // namespace
61 21
62 namespace base { 22 namespace base {
63 23
64 MessagePumpGlibX::MessagePumpGlibX() : base::MessagePumpForUI(), 24 MessagePumpGlibX::MessagePumpGlibX() : base::MessagePumpForUI(),
65 #if defined(HAVE_XINPUT2)
66 xiopcode_(-1),
67 masters_(),
68 slaves_(),
69 #endif
70 gdksource_(NULL), 25 gdksource_(NULL),
71 dispatching_event_(false), 26 dispatching_event_(false),
72 capture_x_events_(0), 27 capture_x_events_(0),
73 capture_gdk_events_(0) { 28 capture_gdk_events_(0) {
74 gdk_event_handler_set(&EventDispatcherX, this, NULL); 29 gdk_event_handler_set(&EventDispatcherX, this, NULL);
75 30
76 #if defined(HAVE_XINPUT2)
77 InitializeXInput2();
78 #endif
79 InitializeEventsToCapture(); 31 InitializeEventsToCapture();
80 } 32 }
81 33
82 MessagePumpGlibX::~MessagePumpGlibX() { 34 MessagePumpGlibX::~MessagePumpGlibX() {
83 } 35 }
84 36
85 bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) { 37 bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) {
86 GdkDisplay* gdisp = gdk_display_get_default(); 38 GdkDisplay* gdisp = gdk_display_get_default();
87 Display* display = GDK_DISPLAY_XDISPLAY(gdisp); 39 Display* display = GDK_DISPLAY_XDISPLAY(gdisp);
88 if (XPending(display)) { 40 if (XPending(display)) {
89 XEvent xev; 41 XEvent xev;
90 XPeekEvent(display, &xev); 42 XPeekEvent(display, &xev);
91 if (capture_x_events_[xev.type] 43 if (capture_x_events_[xev.type]) {
92 #if defined(HAVE_XINPUT2)
93 && (xev.type != GenericEvent || xev.xcookie.extension == xiopcode_)
94 #endif
95 ) {
96 XNextEvent(display, &xev); 44 XNextEvent(display, &xev);
97 45
98 bool processed = static_cast<MessagePumpGlibXDispatcher*> 46 bool processed = static_cast<MessagePumpGlibXDispatcher*>
99 (GetDispatcher())->Dispatch(&xev); 47 (GetDispatcher())->Dispatch(&xev);
100 48
101 if (!processed) { 49 if (!processed) {
102 DLOG(WARNING) << "Event (" << xev.type << ") not handled."; 50 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);
110 } 51 }
111 } else { 52 } else {
112 // TODO(sad): A couple of extra events can still sneak in during this. 53 // TODO(sad): A couple of extra events can still sneak in during this.
113 // Those should be sent back to the X queue from the dispatcher 54 // Those should be sent back to the X queue from the dispatcher
114 // EventDispatcherX. 55 // EventDispatcherX.
115 g_main_context_iteration(context, FALSE); 56 g_main_context_iteration(context, FALSE);
116 } 57 }
117 } 58 }
118 59
119 bool retvalue; 60 bool retvalue;
(...skipping 26 matching lines...) Expand all
146 capture_gdk_events_[GDK_KEY_RELEASE] = true; 87 capture_gdk_events_[GDK_KEY_RELEASE] = true;
147 88
148 capture_x_events_[ButtonPress] = true; 89 capture_x_events_[ButtonPress] = true;
149 capture_gdk_events_[GDK_BUTTON_PRESS] = true; 90 capture_gdk_events_[GDK_BUTTON_PRESS] = true;
150 91
151 capture_x_events_[ButtonRelease] = true; 92 capture_x_events_[ButtonRelease] = true;
152 capture_gdk_events_[GDK_BUTTON_RELEASE] = true; 93 capture_gdk_events_[GDK_BUTTON_RELEASE] = true;
153 94
154 capture_x_events_[MotionNotify] = true; 95 capture_x_events_[MotionNotify] = true;
155 capture_gdk_events_[GDK_MOTION_NOTIFY] = true; 96 capture_gdk_events_[GDK_MOTION_NOTIFY] = true;
156
157 #if defined(HAVE_XINPUT2)
158 capture_x_events_[GenericEvent] = true;
159 #endif
160 } 97 }
161 98
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
240 void MessagePumpGlibX::EventDispatcherX(GdkEvent* event, gpointer data) { 99 void MessagePumpGlibX::EventDispatcherX(GdkEvent* event, gpointer data) {
241 MessagePumpGlibX* pump_x = reinterpret_cast<MessagePumpGlibX*>(data); 100 MessagePumpGlibX* pump_x = reinterpret_cast<MessagePumpGlibX*>(data);
242 101
243 if (!pump_x->gdksource_) { 102 if (!pump_x->gdksource_) {
244 pump_x->gdksource_ = g_main_current_source(); 103 pump_x->gdksource_ = g_main_current_source();
245 } else if (!pump_x->IsDispatchingEvent()) { 104 } else if (!pump_x->IsDispatchingEvent()) {
246 if (event->type != GDK_NOTHING && 105 if (event->type != GDK_NOTHING &&
247 pump_x->capture_gdk_events_[event->type]) { 106 pump_x->capture_gdk_events_[event->type]) {
248 // TODO(sad): An X event is caught by the GDK handler. Put it back in the 107 // TODO(sad): An X event is caught by the GDK handler. Put it back in the
249 // X queue so that we catch it in the next iteration. When done, the 108 // X queue so that we catch it in the next iteration. When done, the
250 // following DLOG statement will be removed. 109 // following DLOG statement will be removed.
251 DLOG(WARNING) << "GDK received an event it shouldn't have"; 110 DLOG(WARNING) << "GDK received an event it shouldn't have";
252 } 111 }
253 } 112 }
254 113
255 pump_x->DispatchEvents(event); 114 pump_x->DispatchEvents(event);
256 } 115 }
257 116
258 } // namespace base 117 } // 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