diff options
author | sadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-20 16:27:40 +0000 |
---|---|---|
committer | sadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-20 16:27:40 +0000 |
commit | bb3be70c22f021a052c5ced2f4ce229ddf66f705 (patch) | |
tree | bd6b5170276aa6eba646841d12ede0664ecad3f7 | |
parent | 86ec4f6ed711a2a58b6e0982b7a0a2fdf95e107a (diff) | |
download | chromium_src-bb3be70c22f021a052c5ced2f4ce229ddf66f705.zip chromium_src-bb3be70c22f021a052c5ced2f4ce229ddf66f705.tar.gz chromium_src-bb3be70c22f021a052c5ced2f4ce229ddf66f705.tar.bz2 |
Maintain the list of devices all in one place.
This effectively moves a bunch of code from the message-pump to the
touch-factory. This way, the list of devices is maintained in one place.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/6882083
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@82307 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | base/message_pump_glib_x.cc | 114 | ||||
-rw-r--r-- | base/message_pump_glib_x.h | 11 | ||||
-rw-r--r-- | views/touchui/touch_factory.cc | 137 | ||||
-rw-r--r-- | views/touchui/touch_factory.h | 11 | ||||
-rw-r--r-- | views/widget/widget_gtk.cc | 5 |
5 files changed, 137 insertions, 141 deletions
diff --git a/base/message_pump_glib_x.cc b/base/message_pump_glib_x.cc index 34313e5..472f68b 100644 --- a/base/message_pump_glib_x.cc +++ b/base/message_pump_glib_x.cc @@ -21,57 +21,6 @@ gboolean PlaceholderDispatch(GSource* source, return TRUE; } -#if defined(HAVE_XINPUT2) - -// Setup XInput2 select for the GtkWidget. -gboolean GtkWidgetRealizeCallback(GSignalInvocationHint* hint, guint nparams, - const GValue* pvalues, gpointer data) { - GtkWidget* widget = GTK_WIDGET(g_value_get_object(pvalues)); - GdkWindow* window = widget->window; - base::MessagePumpGlibX* msgpump = static_cast<base::MessagePumpGlibX*>(data); - - DCHECK(window); // TODO(sad): Remove once determined if necessary. - - if (GDK_WINDOW_TYPE(window) != GDK_WINDOW_TOPLEVEL && - GDK_WINDOW_TYPE(window) != GDK_WINDOW_CHILD && - GDK_WINDOW_TYPE(window) != GDK_WINDOW_DIALOG) - return true; - - // TODO(sad): Do we need to set a flag on |window| to make sure we don't - // select for the same GdkWindow multiple times? Does it matter? - msgpump->SetupXInput2ForXWindow(GDK_WINDOW_XID(window)); - - return true; -} - -// We need to capture all the GDK windows that get created, and start -// listening for XInput2 events. So we setup a callback to the 'realize' -// signal for GTK+ widgets, so that whenever the signal triggers for any -// GtkWidget, which means the GtkWidget should now have a GdkWindow, we can -// setup XInput2 events for the GdkWindow. -static guint realize_signal_id = 0; -static guint realize_hook_id = 0; - -void SetupGtkWidgetRealizeNotifier(base::MessagePumpGlibX* msgpump) { - gpointer klass = g_type_class_ref(GTK_TYPE_WIDGET); - - g_signal_parse_name("realize", GTK_TYPE_WIDGET, - &realize_signal_id, NULL, FALSE); - realize_hook_id = g_signal_add_emission_hook(realize_signal_id, 0, - GtkWidgetRealizeCallback, static_cast<gpointer>(msgpump), NULL); - - g_type_class_unref(klass); -} - -void RemoveGtkWidgetRealizeNotifier() { - if (realize_signal_id != 0) - g_signal_remove_emission_hook(realize_signal_id, realize_hook_id); - realize_signal_id = 0; - realize_hook_id = 0; -} - -#endif // HAVE_XINPUT2 - } // namespace namespace base { @@ -79,7 +28,6 @@ namespace base { MessagePumpGlibX::MessagePumpGlibX() : base::MessagePumpForUI(), #if defined(HAVE_XINPUT2) xiopcode_(-1), - pointer_devices_(), #endif gdksource_(NULL), dispatching_event_(false), @@ -94,41 +42,8 @@ MessagePumpGlibX::MessagePumpGlibX() : base::MessagePumpForUI(), } MessagePumpGlibX::~MessagePumpGlibX() { -#if defined(HAVE_XINPUT2) - RemoveGtkWidgetRealizeNotifier(); -#endif } -#if defined(HAVE_XINPUT2) -void MessagePumpGlibX::SetupXInput2ForXWindow(Window xwindow) { - Display* xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); - - // Setup mask for mouse events. - unsigned char mask[(XI_LASTEVENT + 7)/8]; - memset(mask, 0, sizeof(mask)); - - XISetMask(mask, XI_ButtonPress); - XISetMask(mask, XI_ButtonRelease); - XISetMask(mask, XI_Motion); - - XIEventMask evmasks[pointer_devices_.size()]; - int count = 0; - for (std::set<int>::const_iterator iter = pointer_devices_.begin(); - iter != pointer_devices_.end(); - ++iter, ++count) { - evmasks[count].deviceid = *iter; - evmasks[count].mask_len = sizeof(mask); - evmasks[count].mask = mask; - } - - XISelectEvents(xdisplay, xwindow, evmasks, pointer_devices_.size()); - - // TODO(sad): Setup masks for keyboard events. - - XFlush(xdisplay); -} -#endif // HAVE_XINPUT2 - bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) { GdkDisplay* gdisp = gdk_display_get_default(); if (!gdisp || !GetDispatcher()) @@ -277,35 +192,6 @@ void MessagePumpGlibX::InitializeXInput2(void) { xiopcode_ = -1; return; } - - // TODO(sad): Here, we only setup so that the X windows created by GTK+ are - // setup for XInput2 events. We need a way to listen for XInput2 events for X - // windows created by other means (e.g. for context menus). - SetupGtkWidgetRealizeNotifier(this); - - // Instead of asking X for the list of devices all the time, let's maintain a - // list of pointer devices we care about. - // It is not necessary to select for slave devices. XInput2 provides enough - // information to the event callback to decide which slave device triggered - // the event, thus decide whether the 'pointer event' is a 'mouse event' or a - // 'touch event'. - // If the touch device has 'GrabDevice' set and 'SendCoreEvents' unset (which - // is possible), then the device is detected as a floating device, and a - // floating device is not connected to a master device. So it is necessary to - // also select on the floating devices. - int count = 0; - XIDeviceInfo* devices = XIQueryDevice(xdisplay, XIAllDevices, &count); - for (int i = 0; i < count; i++) { - XIDeviceInfo* devinfo = devices + i; - if (devinfo->use == XIFloatingSlave || devinfo->use == XIMasterPointer) - pointer_devices_.insert(devinfo->deviceid); - } - XIFreeDeviceInfo(devices); - - // TODO(sad): Select on root for XI_HierarchyChanged so that floats_ and - // masters_ can be kept up-to-date. This is a relatively rare event, so we can - // put it off for a later time. - // Note: It is not necessary to listen for XI_DeviceChanged events. } #endif // HAVE_XINPUT2 diff --git a/base/message_pump_glib_x.h b/base/message_pump_glib_x.h index e8e92d6..60e3b5d 100644 --- a/base/message_pump_glib_x.h +++ b/base/message_pump_glib_x.h @@ -9,7 +9,6 @@ #include "base/message_pump_glib.h" #include <bitset> -#include <set> #include <glib.h> #include <gtk/gtk.h> @@ -26,11 +25,6 @@ class MessagePumpGlibX : public MessagePumpForUI { // was captured and being processed by GDK (when |false|). bool IsDispatchingEvent(void) { return dispatching_event_; } -#if defined(HAVE_XINPUT2) - // Setup an X Window for XInput2 events. - void SetupXInput2ForXWindow(Window xid); -#endif - // Overridden from MessagePumpForUI: virtual bool RunOnce(GMainContext* context, bool block); @@ -47,11 +41,6 @@ class MessagePumpGlibX : public MessagePumpForUI { // The opcode used for checking events. int xiopcode_; - - // The list of pointer devices we care about. We maintain this list so that - // it is not necessary to query X for the list of devices for each - // GdkWindow created. - std::set<int> pointer_devices_; #endif // The event source for GDK events. diff --git a/views/touchui/touch_factory.cc b/views/touchui/touch_factory.cc index d9a65a1..4ac8ddc 100644 --- a/views/touchui/touch_factory.cc +++ b/views/touchui/touch_factory.cc @@ -4,6 +4,8 @@ #include "views/touchui/touch_factory.h" +#include <gtk/gtk.h> +#include <gdk/gdkx.h> #include <X11/cursorfont.h> #include <X11/extensions/XInput.h> #include <X11/extensions/XInput2.h> @@ -14,28 +16,26 @@ #include "base/logging.h" #include "ui/base/x/x11_util.h" -// The X cursor is hidden if it is idle for kCursorIdleSeconds seconds. -static int kCursorIdleSeconds = 5; - -namespace views { - namespace { +// The X cursor is hidden if it is idle for kCursorIdleSeconds seconds. +int kCursorIdleSeconds = 5; + // Given the TouchParam, return the correspoding valuator index using // the X device information through Atom name matching. char FindTPValuator(Display* display, XIDeviceInfo* info, - TouchFactory::TouchParam touch_param) { + views::TouchFactory::TouchParam touch_param) { // Lookup table for mapping TouchParam to Atom string used in X. // A full set of Atom strings can be found at xserver-properties.h. static struct { - TouchFactory::TouchParam tp; + views::TouchFactory::TouchParam tp; const char* atom; } kTouchParamAtom[] = { - { TouchFactory::TP_TOUCH_MAJOR, "Abs MT Touch Major" }, - { TouchFactory::TP_TOUCH_MINOR, "Abs MT Touch Minor" }, - { TouchFactory::TP_ORIENTATION, "Abs MT Orientation" }, - { TouchFactory::TP_LAST_ENTRY, NULL }, + { views::TouchFactory::TP_TOUCH_MAJOR, "Abs MT Touch Major" }, + { views::TouchFactory::TP_TOUCH_MINOR, "Abs MT Touch Minor" }, + { views::TouchFactory::TP_ORIENTATION, "Abs MT Orientation" }, + { views::TouchFactory::TP_LAST_ENTRY, NULL }, }; const char* atom_tp = NULL; @@ -65,8 +65,52 @@ char FindTPValuator(Display* display, return -1; } +// Setup XInput2 select for the GtkWidget. +gboolean GtkWidgetRealizeCallback(GSignalInvocationHint* hint, guint nparams, + const GValue* pvalues, gpointer data) { + GtkWidget* widget = GTK_WIDGET(g_value_get_object(pvalues)); + GdkWindow* window = widget->window; + views::TouchFactory* factory = static_cast<views::TouchFactory*>(data); + + if (GDK_WINDOW_TYPE(window) != GDK_WINDOW_TOPLEVEL && + GDK_WINDOW_TYPE(window) != GDK_WINDOW_CHILD && + GDK_WINDOW_TYPE(window) != GDK_WINDOW_DIALOG) + return true; + + factory->SetupXI2ForXWindow(GDK_WINDOW_XID(window)); + return true; +} + +// We need to capture all the GDK windows that get created, and start +// listening for XInput2 events. So we setup a callback to the 'realize' +// signal for GTK+ widgets, so that whenever the signal triggers for any +// GtkWidget, which means the GtkWidget should now have a GdkWindow, we can +// setup XInput2 events for the GdkWindow. +guint realize_signal_id = 0; +guint realize_hook_id = 0; + +void SetupGtkWidgetRealizeNotifier(views::TouchFactory* factory) { + gpointer klass = g_type_class_ref(GTK_TYPE_WIDGET); + + g_signal_parse_name("realize", GTK_TYPE_WIDGET, + &realize_signal_id, NULL, FALSE); + realize_hook_id = g_signal_add_emission_hook(realize_signal_id, 0, + GtkWidgetRealizeCallback, static_cast<gpointer>(factory), NULL); + + g_type_class_unref(klass); +} + +void RemoveGtkWidgetRealizeNotifier() { + if (realize_signal_id != 0) + g_signal_remove_emission_hook(realize_signal_id, realize_hook_id); + realize_signal_id = 0; + realize_hook_id = 0; +} + } // namespace +namespace views { + // static TouchFactory* TouchFactory::GetInstance() { return Singleton<TouchFactory>::get(); @@ -75,6 +119,7 @@ TouchFactory* TouchFactory::GetInstance() { TouchFactory::TouchFactory() : is_cursor_visible_(true), cursor_timer_(), + pointer_devices_(), touch_device_list_() { char nodata[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; XColor black; @@ -87,7 +132,29 @@ TouchFactory::TouchFactory() arrow_cursor_ = XCreateFontCursor(display, XC_arrow); SetCursorVisible(false, false); + UpdateDeviceList(display); + + // TODO(sad): Here, we only setup so that the X windows created by GTK+ are + // setup for XInput2 events. We need a way to listen for XInput2 events for X + // windows created by other means (e.g. for context menus). + SetupGtkWidgetRealizeNotifier(this); + + // TODO(sad): Select on root for XI_HierarchyChanged so that floats_ and + // masters_ can be kept up-to-date. This is a relatively rare event, so we can + // put it off for a later time. + // Note: It is not necessary to listen for XI_DeviceChanged events. +} + +TouchFactory::~TouchFactory() { + SetCursorVisible(true, false); + Display* display = ui::GetXDisplay(); + XFreeCursor(display, invisible_cursor_); + XFreeCursor(display, arrow_cursor_); + RemoveGtkWidgetRealizeNotifier(); +} + +void TouchFactory::UpdateDeviceList(Display* display) { // Detect touch devices. // NOTE: The new API for retrieving the list of devices (XIQueryDevice) does // not provide enough information to detect a touch device. As a result, the @@ -95,6 +162,8 @@ TouchFactory::TouchFactory() // If XInput2 is not supported, this will return null (with count of -1) so // we assume there cannot be any touch devices. int count = 0; + touch_device_lookup_.reset(); + touch_device_list_.clear(); XDeviceInfo* devlist = XListInputDevices(display, &count); for (int i = 0; i < count; i++) { const char* devtype = XGetAtomName(display, devlist[i].type); @@ -106,14 +175,50 @@ TouchFactory::TouchFactory() if (devlist) XFreeDeviceList(devlist); + // Instead of asking X for the list of devices all the time, let's maintain a + // list of pointer devices we care about. + // It is not necessary to select for slave devices. XInput2 provides enough + // information to the event callback to decide which slave device triggered + // the event, thus decide whether the 'pointer event' is a 'mouse event' or a + // 'touch event'. + // If the touch device has 'GrabDevice' set and 'SendCoreEvents' unset (which + // is possible), then the device is detected as a floating device, and a + // floating device is not connected to a master device. So it is necessary to + // also select on the floating devices. + pointer_devices_.clear(); + XIDeviceInfo* devices = XIQueryDevice(display, XIAllDevices, &count); + for (int i = 0; i < count; i++) { + XIDeviceInfo* devinfo = devices + i; + if (devinfo->use == XIFloatingSlave || devinfo->use == XIMasterPointer) { + pointer_devices_.insert(devinfo->deviceid); + } + } + XIFreeDeviceInfo(devices); + SetupValuator(); } -TouchFactory::~TouchFactory() { - SetCursorVisible(true, false); +void TouchFactory::SetupXI2ForXWindow(Window window) { Display* display = ui::GetXDisplay(); - XFreeCursor(display, invisible_cursor_); - XFreeCursor(display, arrow_cursor_); + + unsigned char mask[XIMaskLen(XI_LASTEVENT)]; + memset(mask, 0, sizeof(mask)); + + XISetMask(mask, XI_ButtonPress); + XISetMask(mask, XI_ButtonRelease); + XISetMask(mask, XI_Motion); + + XIEventMask evmask[pointer_devices_.size()]; + int count = 0; + for (std::set<int>::const_iterator iter = pointer_devices_.begin(); + iter != pointer_devices_.end(); + ++iter, ++count) { + evmask[count].deviceid = *iter; + evmask[count].mask_len = sizeof(mask); + evmask[count].mask = mask; + } + XISelectEvents(display, window, evmask, pointer_devices_.size()); + XFlush(display); } void TouchFactory::SetTouchDeviceList( @@ -139,7 +244,7 @@ bool TouchFactory::GrabTouchDevices(Display* display, ::Window window) { if (touch_device_list_.empty()) return true; - unsigned char mask[(XI_LASTEVENT + 7) / 8]; + unsigned char mask[XIMaskLen(XI_LASTEVENT)]; bool success = true; memset(mask, 0, sizeof(mask)); diff --git a/views/touchui/touch_factory.h b/views/touchui/touch_factory.h index f4c6f05..0890d22 100644 --- a/views/touchui/touch_factory.h +++ b/views/touchui/touch_factory.h @@ -7,6 +7,7 @@ #pragma once #include <bitset> +#include <set> #include <vector> #include "base/memory/singleton.h" @@ -33,6 +34,12 @@ class TouchFactory { // Returns the TouchFactory singleton. static TouchFactory* GetInstance(); + // Updates the list of devices. + void UpdateDeviceList(Display* display); + + // Setup an X Window for XInput2 events. + void SetupXI2ForXWindow(::Window xid); + // Keeps a list of touch devices so that it is possible to determine if a // pointer event is a touch-event or a mouse-event. The list is reset each // time this is called. @@ -104,6 +111,10 @@ class TouchFactory { static const int kMaxDeviceNum = 128; + // A quick lookup table for determining if events from the pointer device + // should be processed. + std::set<int> pointer_devices_; + // A quick lookup table for determining if a device is a touch device. std::bitset<kMaxDeviceNum> touch_device_lookup_; diff --git a/views/widget/widget_gtk.cc b/views/widget/widget_gtk.cc index 245ebeb..23e1e23 100644 --- a/views/widget/widget_gtk.cc +++ b/views/widget/widget_gtk.cc @@ -305,6 +305,11 @@ WidgetGtk::WidgetGtk(Type type) should_handle_menu_key_release_(false), dragged_view_(NULL), painted_(false) { +#if defined(TOUCH_UI) && defined(HAVE_XINPUT2) + // Make sure the touch factory is initialized so that it can setup XInput2 for + // the widget. + TouchFactory::GetInstance(); +#endif set_native_widget(this); static bool installed_message_loop_observer = false; if (!installed_message_loop_observer) { |