1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// found in the LICENSE file.
4513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
5513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "base/message_pump_glib_x.h"
6513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
7513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include <gdk/gdkx.h>
84a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#if defined(HAVE_XINPUT2)
94a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include <X11/extensions/XInput2.h>
104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#else
11513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include <X11/Xlib.h>
124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#endif
13513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
14513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "base/message_pump_glib_x_dispatch.h"
15513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
16513209b27ff55e2841eac0e4120199c23acce758Ben Murdochnamespace {
17513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
18513209b27ff55e2841eac0e4120199c23acce758Ben Murdochgboolean PlaceholderDispatch(GSource* source,
19513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                             GSourceFunc cb,
20513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                             gpointer data) {
21513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return TRUE;
22513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
23513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#if defined(HAVE_XINPUT2)
254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// Setup XInput2 select for the GtkWidget.
274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochgboolean GtkWidgetRealizeCallback(GSignalInvocationHint* hint, guint nparams,
284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                  const GValue* pvalues, gpointer data) {
294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  GtkWidget* widget = GTK_WIDGET(g_value_get_object(pvalues));
304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  GdkWindow* window = widget->window;
314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  base::MessagePumpGlibX* msgpump = static_cast<base::MessagePumpGlibX*>(data);
324a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
334a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  DCHECK(window);  // TODO(sad): Remove once determined if necessary.
344a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
35dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (GDK_WINDOW_TYPE(window) != GDK_WINDOW_TOPLEVEL &&
36dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      GDK_WINDOW_TYPE(window) != GDK_WINDOW_CHILD &&
37dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      GDK_WINDOW_TYPE(window) != GDK_WINDOW_DIALOG)
38dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return true;
39dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
404a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // TODO(sad): Do we need to set a flag on |window| to make sure we don't
414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // select for the same GdkWindow multiple times? Does it matter?
424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  msgpump->SetupXInput2ForXWindow(GDK_WINDOW_XID(window));
434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return true;
454a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
474a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// We need to capture all the GDK windows that get created, and start
484a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// listening for XInput2 events. So we setup a callback to the 'realize'
494a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// signal for GTK+ widgets, so that whenever the signal triggers for any
504a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// GtkWidget, which means the GtkWidget should now have a GdkWindow, we can
514a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// setup XInput2 events for the GdkWindow.
52dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenstatic guint realize_signal_id = 0;
53dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenstatic guint realize_hook_id = 0;
54dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid SetupGtkWidgetRealizeNotifier(base::MessagePumpGlibX* msgpump) {
564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  gpointer klass = g_type_class_ref(GTK_TYPE_WIDGET);
574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
58dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  g_signal_parse_name("realize", GTK_TYPE_WIDGET,
59dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                      &realize_signal_id, NULL, FALSE);
60dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  realize_hook_id = g_signal_add_emission_hook(realize_signal_id, 0,
61dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      GtkWidgetRealizeCallback, static_cast<gpointer>(msgpump), NULL);
624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  g_type_class_unref(klass);
644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
66dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid RemoveGtkWidgetRealizeNotifier() {
67dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (realize_signal_id != 0)
68dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    g_signal_remove_emission_hook(realize_signal_id, realize_hook_id);
69dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  realize_signal_id = 0;
70dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  realize_hook_id = 0;
71dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
72dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
734a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#endif  // HAVE_XINPUT2
744a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
75513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}  // namespace
76513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
77513209b27ff55e2841eac0e4120199c23acce758Ben Murdochnamespace base {
78513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
79513209b27ff55e2841eac0e4120199c23acce758Ben MurdochMessagePumpGlibX::MessagePumpGlibX() : base::MessagePumpForUI(),
804a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#if defined(HAVE_XINPUT2)
814a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    xiopcode_(-1),
82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    pointer_devices_(),
834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#endif
84513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    gdksource_(NULL),
85513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    dispatching_event_(false),
86513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    capture_x_events_(0),
87513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    capture_gdk_events_(0) {
88513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  gdk_event_handler_set(&EventDispatcherX, this, NULL);
89513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#if defined(HAVE_XINPUT2)
914a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  InitializeXInput2();
924a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#endif
93513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  InitializeEventsToCapture();
94513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
95513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
96513209b27ff55e2841eac0e4120199c23acce758Ben MurdochMessagePumpGlibX::~MessagePumpGlibX() {
97dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#if defined(HAVE_XINPUT2)
98dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  RemoveGtkWidgetRealizeNotifier();
99dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#endif
100513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
101513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
10272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#if defined(HAVE_XINPUT2)
10372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid MessagePumpGlibX::SetupXInput2ForXWindow(Window xwindow) {
10472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  Display* xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
10572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
10672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Setup mask for mouse events.
10772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  unsigned char mask[(XI_LASTEVENT + 7)/8];
10872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  memset(mask, 0, sizeof(mask));
10972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
11072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  XISetMask(mask, XI_ButtonPress);
11172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  XISetMask(mask, XI_ButtonRelease);
11272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  XISetMask(mask, XI_Motion);
11372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  XIEventMask evmasks[pointer_devices_.size()];
11572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int count = 0;
116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (std::set<int>::const_iterator iter = pointer_devices_.begin();
117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen       iter != pointer_devices_.end();
11872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen       ++iter, ++count) {
11972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    evmasks[count].deviceid = *iter;
12072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    evmasks[count].mask_len = sizeof(mask);
12172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    evmasks[count].mask = mask;
12272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
12372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  XISelectEvents(xdisplay, xwindow, evmasks, pointer_devices_.size());
12572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
12672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // TODO(sad): Setup masks for keyboard events.
12772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
12872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  XFlush(xdisplay);
12972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
13072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#endif  // HAVE_XINPUT2
13172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
132513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) {
133513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  GdkDisplay* gdisp = gdk_display_get_default();
134dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!gdisp || !GetDispatcher())
1353f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    return MessagePumpForUI::RunOnce(context, block);
1363f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
137513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  Display* display = GDK_DISPLAY_XDISPLAY(gdisp);
13821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  bool should_quit = false;
13921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
140513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (XPending(display)) {
141513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    XEvent xev;
142513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    XPeekEvent(display, &xev);
1434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (capture_x_events_[xev.type]
1444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#if defined(HAVE_XINPUT2)
1454a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        && (xev.type != GenericEvent || xev.xcookie.extension == xiopcode_)
1464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#endif
1474a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        ) {
148513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      XNextEvent(display, &xev);
149513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
15021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#if defined(HAVE_XINPUT2)
15121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      bool have_cookie = false;
15221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (xev.type == GenericEvent &&
15321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen          XGetEventData(xev.xgeneric.display, &xev.xcookie)) {
15421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        have_cookie = true;
15521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      }
15621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#endif
15721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
15821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      MessagePumpGlibXDispatcher::DispatchStatus status =
15921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen          static_cast<MessagePumpGlibXDispatcher*>
16072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          (GetDispatcher())->DispatchX(&xev);
161513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
16221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (status == MessagePumpGlibXDispatcher::EVENT_QUIT) {
16321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        should_quit = true;
16421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        Quit();
16521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      } else if (status == MessagePumpGlibXDispatcher::EVENT_IGNORED) {
166513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        DLOG(WARNING) << "Event (" << xev.type << ") not handled.";
1674a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1684a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        // TODO(sad): It is necessary to put back the event so that the default
1694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        // GDK events handler can take care of it. Without this, it is
1704a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        // impossible to use the omnibox at the moment. However, this will
1714a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        // eventually be removed once the omnibox code is updated for touchui.
1724a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        XPutBackEvent(display, &xev);
17321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        if (gdksource_)
17421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen          gdksource_->source_funcs->dispatch = gdkdispatcher_;
1754a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        g_main_context_iteration(context, FALSE);
176513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      }
17721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
17821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#if defined(HAVE_XINPUT2)
17921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (have_cookie) {
18021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        XFreeEventData(xev.xgeneric.display, &xev.xcookie);
18121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      }
18221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#endif
183513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    } else {
184513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      // TODO(sad): A couple of extra events can still sneak in during this.
185513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      // Those should be sent back to the X queue from the dispatcher
186513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      // EventDispatcherX.
18721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (gdksource_)
18821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        gdksource_->source_funcs->dispatch = gdkdispatcher_;
189513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      g_main_context_iteration(context, FALSE);
190513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
191513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
192513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
19321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (should_quit)
19421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return true;
19521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
196513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  bool retvalue;
197513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (gdksource_) {
198513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // Replace the dispatch callback of the GDK event source temporarily so that
199513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // it doesn't read events from X.
200513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    gboolean (*cb)(GSource*, GSourceFunc, void*) =
201513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        gdksource_->source_funcs->dispatch;
202513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    gdksource_->source_funcs->dispatch = PlaceholderDispatch;
203513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
204513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    dispatching_event_ = true;
205513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    retvalue = g_main_context_iteration(context, block);
206513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    dispatching_event_ = false;
207513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
208513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    gdksource_->source_funcs->dispatch = cb;
209513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  } else {
210513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    retvalue = g_main_context_iteration(context, block);
211513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
212513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
213513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return retvalue;
214513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
215513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
21672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid MessagePumpGlibX::EventDispatcherX(GdkEvent* event, gpointer data) {
21772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  MessagePumpGlibX* pump_x = reinterpret_cast<MessagePumpGlibX*>(data);
21872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
21972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!pump_x->gdksource_) {
22072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    pump_x->gdksource_ = g_main_current_source();
221ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (pump_x->gdksource_)
222ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      pump_x->gdkdispatcher_ = pump_x->gdksource_->source_funcs->dispatch;
22372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  } else if (!pump_x->IsDispatchingEvent()) {
22472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (event->type != GDK_NOTHING &&
22572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        pump_x->capture_gdk_events_[event->type]) {
22672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      // TODO(sad): An X event is caught by the GDK handler. Put it back in the
22772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      // X queue so that we catch it in the next iteration. When done, the
22872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      // following DLOG statement will be removed.
22972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      DLOG(WARNING) << "GDK received an event it shouldn't have";
23072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
23172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
23272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
23372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  pump_x->DispatchEvents(event);
23472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
23572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
236513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid MessagePumpGlibX::InitializeEventsToCapture(void) {
237513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // TODO(sad): Decide which events we want to capture and update the tables
238513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // accordingly.
239513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  capture_x_events_[KeyPress] = true;
240513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  capture_gdk_events_[GDK_KEY_PRESS] = true;
241513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
242513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  capture_x_events_[KeyRelease] = true;
243513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  capture_gdk_events_[GDK_KEY_RELEASE] = true;
244513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
245513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  capture_x_events_[ButtonPress] = true;
246513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  capture_gdk_events_[GDK_BUTTON_PRESS] = true;
247513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
248513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  capture_x_events_[ButtonRelease] = true;
249513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  capture_gdk_events_[GDK_BUTTON_RELEASE] = true;
250513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
251513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  capture_x_events_[MotionNotify] = true;
252513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  capture_gdk_events_[GDK_MOTION_NOTIFY] = true;
2534a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
2544a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#if defined(HAVE_XINPUT2)
2554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  capture_x_events_[GenericEvent] = true;
2564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#endif
2574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
2584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
2594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#if defined(HAVE_XINPUT2)
2604a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid MessagePumpGlibX::InitializeXInput2(void) {
2614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  GdkDisplay* display = gdk_display_get_default();
2623f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  if (!display)
2633f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    return;
2643f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
2654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  Display* xdisplay = GDK_DISPLAY_XDISPLAY(display);
2664a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  int event, err;
2674a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
2684a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (!XQueryExtension(xdisplay, "XInputExtension", &xiopcode_, &event, &err)) {
2694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    DLOG(WARNING) << "X Input extension not available.";
2704a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    xiopcode_ = -1;
2714a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return;
2724a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
2734a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
2744a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  int major = 2, minor = 0;
2754a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (XIQueryVersion(xdisplay, &major, &minor) == BadRequest) {
2764a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    DLOG(WARNING) << "XInput2 not supported in the server.";
2774a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    xiopcode_ = -1;
2784a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return;
2794a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
2804a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
28121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // TODO(sad): Here, we only setup so that the X windows created by GTK+ are
28221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // setup for XInput2 events. We need a way to listen for XInput2 events for X
28321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // windows created by other means (e.g. for context menus).
2844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  SetupGtkWidgetRealizeNotifier(this);
2854a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
2864a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // Instead of asking X for the list of devices all the time, let's maintain a
287ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // list of pointer devices we care about.
288ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // It is not necessary to select for slave devices. XInput2 provides enough
289ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // information to the event callback to decide which slave device triggered
290ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // the event, thus decide whether the 'pointer event' is a 'mouse event' or a
291ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // 'touch event'.
292ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // If the touch device has 'GrabDevice' set and 'SendCoreEvents' unset (which
293ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // is possible), then the device is detected as a floating device, and a
294ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // floating device is not connected to a master device. So it is necessary to
295ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // also select on the floating devices.
2964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  int count = 0;
2974a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  XIDeviceInfo* devices = XIQueryDevice(xdisplay, XIAllDevices, &count);
2984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  for (int i = 0; i < count; i++) {
2994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    XIDeviceInfo* devinfo = devices + i;
300ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (devinfo->use == XIFloatingSlave || devinfo->use == XIMasterPointer)
301ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      pointer_devices_.insert(devinfo->deviceid);
3024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
3034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  XIFreeDeviceInfo(devices);
3044a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
305ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(sad): Select on root for XI_HierarchyChanged so that floats_ and
3064a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // masters_ can be kept up-to-date. This is a relatively rare event, so we can
3074a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // put it off for a later time.
3084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // Note: It is not necessary to listen for XI_DeviceChanged events.
309513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
3104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#endif  // HAVE_XINPUT2
3114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
312513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}  // namespace base
313