summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-20 16:27:40 +0000
committersadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-20 16:27:40 +0000
commitbb3be70c22f021a052c5ced2f4ce229ddf66f705 (patch)
treebd6b5170276aa6eba646841d12ede0664ecad3f7
parent86ec4f6ed711a2a58b6e0982b7a0a2fdf95e107a (diff)
downloadchromium_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.cc114
-rw-r--r--base/message_pump_glib_x.h11
-rw-r--r--views/touchui/touch_factory.cc137
-rw-r--r--views/touchui/touch_factory.h11
-rw-r--r--views/widget/widget_gtk.cc5
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) {