Index: ui/events/devices/x11/touch_factory_x11.cc |
diff --git a/ui/events/platform/x11/touch_factory_x11.cc b/ui/events/devices/x11/touch_factory_x11.cc |
similarity index 57% |
rename from ui/events/platform/x11/touch_factory_x11.cc |
rename to ui/events/devices/x11/touch_factory_x11.cc |
index 7a52d6f6603cb7a8ec3b0b3e91aea66df4d29ce3..bd7b15714b347899ef7856d469ac04e0891c866f 100644 |
--- a/ui/events/platform/x11/touch_factory_x11.cc |
+++ b/ui/events/devices/x11/touch_factory_x11.cc |
@@ -2,13 +2,13 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#include "ui/events/platform/x11/touch_factory_x11.h" |
+#include "ui/events/devices/x11/touch_factory_x11.h" |
+#include <X11/Xatom.h> |
#include <X11/cursorfont.h> |
#include <X11/extensions/XInput.h> |
#include <X11/extensions/XInput2.h> |
#include <X11/extensions/XIproto.h> |
-#include <X11/Xatom.h> |
#include "base/basictypes.h" |
#include "base/command_line.h" |
@@ -19,9 +19,9 @@ |
#include "base/strings/string_number_conversions.h" |
#include "base/strings/string_split.h" |
#include "base/sys_info.h" |
+#include "ui/events/devices/x11/device_data_manager_x11.h" |
+#include "ui/events/devices/x11/device_list_cache_x11.h" |
#include "ui/events/event_switches.h" |
-#include "ui/events/platform/x11/device_data_manager_x11.h" |
-#include "ui/events/platform/x11/device_list_cache_x.h" |
#include "ui/gfx/x/x11_types.h" |
namespace ui { |
@@ -30,7 +30,6 @@ TouchFactory::TouchFactory() |
: pointer_device_lookup_(), |
touch_events_disabled_(false), |
touch_device_list_(), |
- max_touch_points_(-1), |
virtual_core_keyboard_device_(-1), |
id_generator_(0) { |
if (!DeviceDataManagerX11::GetInstance()->IsXInput2Available()) |
@@ -40,8 +39,7 @@ TouchFactory::TouchFactory() |
UpdateDeviceList(display); |
base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess(); |
- touch_events_disabled_ = |
- cmdline->HasSwitch(switches::kTouchEvents) && |
+ touch_events_disabled_ = cmdline->HasSwitch(switches::kTouchEvents) && |
cmdline->GetSwitchValueASCII(switches::kTouchEvents) == |
switches::kTouchEventsDisabled; |
} |
@@ -65,11 +63,11 @@ void TouchFactory::SetTouchDeviceListFromCommandLine() { |
if (!touch_devices.empty()) { |
std::vector<std::string> devs; |
- std::vector<unsigned int> device_ids; |
- unsigned int devid; |
+ std::vector<int> device_ids; |
+ int devid; |
base::SplitString(touch_devices, ',', &devs); |
for (std::vector<std::string>::iterator iter = devs.begin(); |
- iter != devs.end(); ++iter) { |
+ iter != devs.end(); ++iter) { |
if (base::StringToInt(*iter, reinterpret_cast<int*>(&devid))) |
device_ids.push_back(devid); |
else |
@@ -84,25 +82,6 @@ void TouchFactory::UpdateDeviceList(Display* display) { |
touch_device_lookup_.reset(); |
touch_device_list_.clear(); |
touchscreen_ids_.clear(); |
- max_touch_points_ = -1; |
- |
-#if !defined(USE_XI2_MT) |
- // 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 |
- // old version of query function (XListInputDevices) is used instead. |
- // If XInput2 is not supported, this will return null (with count of -1) so |
- // we assume there cannot be any touch devices. |
- // With XI2.1 or older, we allow only single touch devices. |
- XDeviceList dev_list = |
- DeviceListCacheX::GetInstance()->GetXDeviceList(display); |
- Atom xi_touchscreen = XInternAtom(display, XI_TOUCHSCREEN, false); |
- for (int i = 0; i < dev_list.count; i++) { |
- if (dev_list[i].type == xi_touchscreen) { |
- touch_device_lookup_[dev_list[i].id] = true; |
- touch_device_list_[dev_list[i].id] = false; |
- } |
- } |
-#endif |
if (!DeviceDataManagerX11::GetInstance()->IsXInput2Available()) |
return; |
@@ -120,46 +99,47 @@ void TouchFactory::UpdateDeviceList(Display* display) { |
// floating device is not connected to a master device. So it is necessary to |
// also select on the floating devices. |
pointer_device_lookup_.reset(); |
- XIDeviceList xi_dev_list = |
- DeviceListCacheX::GetInstance()->GetXI2DeviceList(display); |
+ const XIDeviceList& xi_dev_list = |
+ DeviceListCacheX11::GetInstance()->GetXI2DeviceList(display); |
for (int i = 0; i < xi_dev_list.count; i++) { |
- XIDeviceInfo* devinfo = xi_dev_list.devices + i; |
- if (devinfo->use == XIFloatingSlave || devinfo->use == XIMasterPointer) { |
-#if defined(USE_XI2_MT) |
- for (int k = 0; k < devinfo->num_classes; ++k) { |
- XIAnyClassInfo* xiclassinfo = devinfo->classes[k]; |
+ const XIDeviceInfo& devinfo = xi_dev_list[i]; |
+ if (devinfo.use == XIFloatingSlave || devinfo.use == XIMasterPointer) { |
+ for (int k = 0; k < devinfo.num_classes; ++k) { |
+ XIAnyClassInfo* xiclassinfo = devinfo.classes[k]; |
if (xiclassinfo->type == XITouchClass) { |
XITouchClassInfo* tci = |
reinterpret_cast<XITouchClassInfo*>(xiclassinfo); |
// Only care direct touch device (such as touch screen) right now |
if (tci->mode == XIDirectTouch) { |
- touch_device_lookup_[devinfo->deviceid] = true; |
- touch_device_list_[devinfo->deviceid] = true; |
- if (tci->num_touches > 0 && tci->num_touches > max_touch_points_) |
- max_touch_points_ = tci->num_touches; |
+ touch_device_lookup_[devinfo.deviceid] = true; |
+ touch_device_list_[devinfo.deviceid] = true; |
} |
} |
} |
-#endif |
- pointer_device_lookup_[devinfo->deviceid] = true; |
- } else if (devinfo->use == XIMasterKeyboard) { |
- virtual_core_keyboard_device_ = devinfo->deviceid; |
+ pointer_device_lookup_[devinfo.deviceid] = true; |
+ } else if (devinfo.use == XIMasterKeyboard) { |
+ virtual_core_keyboard_device_ = devinfo.deviceid; |
} |
-#if defined(USE_XI2_MT) |
- if (devinfo->use == XIFloatingSlave || devinfo->use == XISlavePointer) { |
- for (int k = 0; k < devinfo->num_classes; ++k) { |
- XIAnyClassInfo* xiclassinfo = devinfo->classes[k]; |
+ if (devinfo.use == XIFloatingSlave || devinfo.use == XISlavePointer) { |
+ for (int k = 0; k < devinfo.num_classes; ++k) { |
+ XIAnyClassInfo* xiclassinfo = devinfo.classes[k]; |
if (xiclassinfo->type == XITouchClass) { |
XITouchClassInfo* tci = |
reinterpret_cast<XITouchClassInfo*>(xiclassinfo); |
// Only care direct touch device (such as touch screen) right now |
if (tci->mode == XIDirectTouch) |
- CacheTouchscreenIds(display, devinfo->deviceid); |
+ CacheTouchscreenIds(devinfo.deviceid); |
+ if (devinfo.use == XISlavePointer) { |
+ device_master_id_list_[devinfo.deviceid] = devinfo.attachment; |
+ // If the slave device is direct touch device, we also set its |
+ // master device to be touch device. |
+ touch_device_lookup_[devinfo.attachment] = true; |
+ touch_device_list_[devinfo.attachment] = true; |
+ } |
} |
} |
} |
-#endif |
} |
} |
@@ -168,19 +148,35 @@ bool TouchFactory::ShouldProcessXI2Event(XEvent* xev) { |
XIEvent* event = static_cast<XIEvent*>(xev->xcookie.data); |
XIDeviceEvent* xiev = reinterpret_cast<XIDeviceEvent*>(event); |
-#if defined(USE_XI2_MT) |
- if (event->evtype == XI_TouchBegin || event->evtype == XI_TouchUpdate || |
+ if (event->evtype == XI_TouchBegin || |
+ event->evtype == XI_TouchUpdate || |
event->evtype == XI_TouchEnd) { |
- return !touch_events_disabled_ && IsTouchDevice(xiev->deviceid); |
+ // Since SetupXI2ForXWindow() selects events from all devices, for a |
+ // touchscreen attached to a master pointer device, X11 sends two |
+ // events for each touch: one from the slave (deviceid == the id of |
+ // the touchscreen device), and one from the master (deviceid == the |
+ // id of the master pointer device). Instead of processing both |
+ // events, discard the event that comes from the slave, and only |
+ // allow processing the event coming from the master. |
+ // For a 'floating' touchscreen device, X11 sends only one event for |
+ // each touch, with both deviceid and sourceid set to the id of the |
+ // touchscreen device. |
+ bool is_from_master_or_float = touch_device_list_[xiev->deviceid]; |
+ bool is_from_slave_device = !is_from_master_or_float |
+ && xiev->sourceid == xiev->deviceid; |
+ return !touch_events_disabled_ && |
+ IsTouchDevice(xiev->deviceid) && |
+ !is_from_slave_device; |
} |
-#endif |
+ |
// Make sure only key-events from the virtual core keyboard are processed. |
if (event->evtype == XI_KeyPress || event->evtype == XI_KeyRelease) { |
return (virtual_core_keyboard_device_ < 0) || |
(virtual_core_keyboard_device_ == xiev->deviceid); |
} |
- if (event->evtype != XI_ButtonPress && event->evtype != XI_ButtonRelease && |
+ if (event->evtype != XI_ButtonPress && |
+ event->evtype != XI_ButtonRelease && |
event->evtype != XI_Motion) |
return true; |
@@ -203,15 +199,16 @@ void TouchFactory::SetupXI2ForXWindow(Window window) { |
unsigned char mask[XIMaskLen(XI_LASTEVENT)]; |
memset(mask, 0, sizeof(mask)); |
-#if defined(USE_XI2_MT) |
XISetMask(mask, XI_TouchBegin); |
XISetMask(mask, XI_TouchUpdate); |
XISetMask(mask, XI_TouchEnd); |
-#endif |
+ |
XISetMask(mask, XI_ButtonPress); |
XISetMask(mask, XI_ButtonRelease); |
XISetMask(mask, XI_Motion); |
#if defined(OS_CHROMEOS) |
+ // XGrabKey() must be replaced with XI2 keyboard grab if XI2 key events are |
+ // enabled on desktop Linux. |
if (base::SysInfo::IsRunningOnChromeOS()) { |
XISetMask(mask, XI_KeyPress); |
XISetMask(mask, XI_KeyRelease); |
@@ -226,26 +223,33 @@ void TouchFactory::SetupXI2ForXWindow(Window window) { |
XFlush(display); |
} |
-void TouchFactory::SetTouchDeviceList( |
- const std::vector<unsigned int>& devices) { |
+void TouchFactory::SetTouchDeviceList(const std::vector<int>& devices) { |
touch_device_lookup_.reset(); |
touch_device_list_.clear(); |
- for (std::vector<unsigned int>::const_iterator iter = devices.begin(); |
- iter != devices.end(); ++iter) { |
- DCHECK(*iter < touch_device_lookup_.size()); |
- touch_device_lookup_[*iter] = true; |
- touch_device_list_[*iter] = false; |
+ for (int deviceid : devices) { |
+ DCHECK(IsValidDevice(deviceid)); |
+ touch_device_lookup_[deviceid] = true; |
+ touch_device_list_[deviceid] = false; |
+ if (device_master_id_list_.find(deviceid) != device_master_id_list_.end()) { |
+ // When we set the device through the "--touch-devices" flag to slave |
+ // touch device, we also set its master device to be touch device. |
+ touch_device_lookup_[device_master_id_list_[deviceid]] = true; |
+ touch_device_list_[device_master_id_list_[deviceid]] = false; |
+ } |
} |
} |
-bool TouchFactory::IsTouchDevice(unsigned deviceid) const { |
- return deviceid < touch_device_lookup_.size() ? touch_device_lookup_[deviceid] |
- : false; |
+bool TouchFactory::IsValidDevice(int deviceid) const { |
+ return (deviceid >= 0) && |
+ (static_cast<size_t>(deviceid) < touch_device_lookup_.size()); |
+} |
+ |
+bool TouchFactory::IsTouchDevice(int deviceid) const { |
+ return IsValidDevice(deviceid) ? touch_device_lookup_[deviceid] : false; |
} |
-bool TouchFactory::IsMultiTouchDevice(unsigned int deviceid) const { |
- return (deviceid < touch_device_lookup_.size() && |
- touch_device_lookup_[deviceid]) |
+bool TouchFactory::IsMultiTouchDevice(int deviceid) const { |
+ return (IsValidDevice(deviceid) && touch_device_lookup_[deviceid]) |
? touch_device_list_.find(deviceid)->second |
: false; |
} |
@@ -261,42 +265,30 @@ int TouchFactory::GetSlotForTrackingID(uint32 tracking_id) { |
return id_generator_.GetGeneratedID(tracking_id); |
} |
-void TouchFactory::AcquireSlotForTrackingID(uint32 tracking_id) { |
- tracking_id_refcounts_[tracking_id]++; |
-} |
- |
void TouchFactory::ReleaseSlotForTrackingID(uint32 tracking_id) { |
- tracking_id_refcounts_[tracking_id]--; |
- if (tracking_id_refcounts_[tracking_id] == 0) |
- id_generator_.ReleaseNumber(tracking_id); |
+ id_generator_.ReleaseNumber(tracking_id); |
} |
bool TouchFactory::IsTouchDevicePresent() { |
return !touch_events_disabled_ && touch_device_lookup_.any(); |
} |
-int TouchFactory::GetMaxTouchPoints() const { |
- return max_touch_points_; |
-} |
- |
void TouchFactory::ResetForTest() { |
pointer_device_lookup_.reset(); |
touch_device_lookup_.reset(); |
touch_events_disabled_ = false; |
touch_device_list_.clear(); |
touchscreen_ids_.clear(); |
- tracking_id_refcounts_.clear(); |
- max_touch_points_ = -1; |
id_generator_.ResetForTest(); |
} |
void TouchFactory::SetTouchDeviceForTest( |
- const std::vector<unsigned int>& devices) { |
+ const std::vector<int>& devices) { |
touch_device_lookup_.reset(); |
touch_device_list_.clear(); |
- for (std::vector<unsigned int>::const_iterator iter = devices.begin(); |
+ for (std::vector<int>::const_iterator iter = devices.begin(); |
iter != devices.end(); ++iter) { |
- DCHECK(*iter < touch_device_lookup_.size()); |
+ DCHECK(IsValidDevice(*iter)); |
touch_device_lookup_[*iter] = true; |
touch_device_list_[*iter] = true; |
} |
@@ -304,50 +296,27 @@ void TouchFactory::SetTouchDeviceForTest( |
} |
void TouchFactory::SetPointerDeviceForTest( |
- const std::vector<unsigned int>& devices) { |
+ const std::vector<int>& devices) { |
pointer_device_lookup_.reset(); |
- for (std::vector<unsigned int>::const_iterator iter = devices.begin(); |
+ for (std::vector<int>::const_iterator iter = devices.begin(); |
iter != devices.end(); ++iter) { |
pointer_device_lookup_[*iter] = true; |
} |
} |
-void TouchFactory::CacheTouchscreenIds(Display* display, int device_id) { |
- XDevice* device = XOpenDevice(display, device_id); |
- if (!device) |
+void TouchFactory::CacheTouchscreenIds(int device_id) { |
+ if (!DeviceDataManager::HasInstance()) |
return; |
- |
- Atom actual_type_return; |
- int actual_format_return; |
- unsigned long nitems_return; |
- unsigned long bytes_after_return; |
- unsigned char* prop_return; |
- |
- const char kDeviceProductIdString[] = "Device Product ID"; |
- Atom device_product_id_atom = |
- XInternAtom(display, kDeviceProductIdString, false); |
- |
- if (device_product_id_atom != None && |
- XGetDeviceProperty(display, device, device_product_id_atom, 0, 2, False, |
- XA_INTEGER, &actual_type_return, &actual_format_return, |
- &nitems_return, &bytes_after_return, |
- &prop_return) == Success) { |
- if (actual_type_return == XA_INTEGER && actual_format_return == 32 && |
- nitems_return == 2) { |
- // An actual_format_return of 32 implies that the returned data is an |
- // array of longs. See the description of |prop_return| in `man |
- // XGetDeviceProperty` for details. |
- long* ptr = reinterpret_cast<long*>(prop_return); |
- |
- // Internal displays will have a vid and pid of 0. Ignore them. |
- // ptr[0] is the vid, and ptr[1] is the pid. |
- if (ptr[0] || ptr[1]) |
- touchscreen_ids_.insert(std::make_pair(ptr[0], ptr[1])); |
- } |
- XFree(prop_return); |
- } |
- |
- XCloseDevice(display, device); |
+ std::vector<TouchscreenDevice> touchscreens = |
+ DeviceDataManager::GetInstance()->touchscreen_devices(); |
+ const auto it = |
+ std::find_if(touchscreens.begin(), touchscreens.end(), |
+ [device_id](const TouchscreenDevice& touchscreen) { |
+ return touchscreen.id == device_id; |
+ }); |
+ // Internal displays will have a vid and pid of 0. Ignore them. |
+ if (it != touchscreens.end() && it->vendor_id && it->product_id) |
+ touchscreen_ids_.insert(std::make_pair(it->vendor_id, it->product_id)); |
} |
} // namespace ui |