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