Index: ui/base/touch/touch_factory.cc |
=================================================================== |
--- ui/base/touch/touch_factory.cc (revision 126124) |
+++ ui/base/touch/touch_factory.cc (working copy) |
@@ -9,10 +9,14 @@ |
#include <X11/extensions/XInput2.h> |
#include <X11/extensions/XIproto.h> |
+#include <string> |
+ |
#include "base/basictypes.h" |
#include "base/compiler_specific.h" |
#include "base/logging.h" |
#include "base/message_loop.h" |
+#include "ui/base/touch/multi_touch_device.h" |
+#include "ui/base/touch/multi_touch_device_x11.h" |
#include "ui/base/x/x11_util.h" |
namespace { |
@@ -20,6 +24,35 @@ |
// The X cursor is hidden if it is idle for kCursorIdleSeconds seconds. |
int kCursorIdleSeconds = 5; |
+ui::Axis::Type TouchParamToAxisType(ui::TouchFactory::TouchParam tp) { |
+ ui::Axis::Type type = ui::Axis::AXIS_TYPE_UNKNOWN; |
+ switch (tp) { |
+ case ui::TouchFactory::TP_TOUCH_MAJOR: |
+ // Length of the touch area. |
+ type = ui::Axis::AXIS_TYPE_TOUCH_MAJOR; |
+ break; |
+ case ui::TouchFactory::TP_TOUCH_MINOR: |
+ // Width of the touch area. |
+ type = ui::Axis::AXIS_TYPE_TOUCH_MINOR; |
+ break; |
+ case ui::TouchFactory::TP_ORIENTATION: |
+ // Angle between the X-axis and the major axis of the |
+ // touch area. |
+ type = ui::Axis::AXIS_TYPE_ORIENTATION; |
+ break; |
+ case ui::TouchFactory::TP_PRESSURE: |
+ // Pressure of the touch contact. |
+ type = ui::Axis::AXIS_TYPE_PRESSURE; |
+ case ui::TouchFactory::TP_TRACKING_ID: |
+ // ID of the touch point. |
+ type = ui::Axis::AXIS_TYPE_TRACKING_ID; |
+ default: |
+ break; |
+ } |
+ |
+ return type; |
+} |
+ |
// Given the TouchParam, return the correspoding XIValuatorClassInfo using |
// the X device information through Atom name matching. |
XIValuatorClassInfo* FindTPValuator(Display* display, |
@@ -72,7 +105,6 @@ |
return NULL; |
} |
- |
} // namespace |
namespace ui { |
@@ -83,12 +115,19 @@ |
} |
TouchFactory::TouchFactory() |
- : is_cursor_visible_(true), |
+ : device_observer_list_( |
+ new ObserverListThreadSafe<TouchFactory::DeviceObserver>()), |
+ is_cursor_visible_(true), |
cursor_timer_(), |
pointer_device_lookup_(), |
touch_device_available_(false), |
touch_device_list_(), |
#if defined(USE_XI2_MT) |
+#if defined(USE_AURA) |
+#if defined(USE_UTOUCH) |
+ utouch_frame_handle_(NULL), |
+#endif // USE_UTOUCH |
+#endif // USE_AURA |
min_available_slot_(0), |
#endif |
slots_used_() { |
@@ -101,13 +140,25 @@ |
XColor black; |
black.red = black.green = black.blue = 0; |
Display* display = ui::GetXDisplay(); |
+ |
+#if defined(USE_AURA) && defined(USE_UTOUCH) |
+ if (UFStatusSuccess != frame_x11_new(display, &utouch_frame_handle_)) { |
+ LOG(ERROR) << "Failed to create utouch frame instance"; |
+ } else { |
+ fd_set set; |
+ FD_ZERO(&set); |
+ FD_SET(frame_get_fd(utouch_frame_handle_), &set); |
+ } |
+#endif // USE_AURA && USE_UTOUCH |
+ |
Pixmap blank = XCreateBitmapFromData(display, ui::GetX11RootWindow(), |
nodata, 8, 8); |
invisible_cursor_ = XCreatePixmapCursor(display, blank, blank, |
&black, &black, 0, 0); |
arrow_cursor_ = XCreateFontCursor(display, XC_arrow); |
- SetCursorVisible(false, false); |
+ // TODO(tvoss): Selectively enable visibility for indirect touch devs. |
+ // SetCursorVisible(false, false); |
UpdateDeviceList(display); |
// Make sure the list of devices is kept up-to-date by listening for |
@@ -128,8 +179,12 @@ |
#if defined(USE_AURA) |
if (!base::MessagePumpForUI::HasXInput2()) |
return; |
-#endif |
+#if defined(USE_UTOUCH) |
+ frame_x11_delete(utouch_frame_handle_); |
+#endif // USE_UTOUCH |
+#endif // USE_AURA |
+ |
// The XDisplay may be lost by the time we get destroyed. |
if (ui::XDisplayExists()) { |
SetCursorVisible(true, false); |
@@ -139,6 +194,21 @@ |
} |
} |
+void TouchFactory::AddDeviceObserver(TouchFactory::DeviceObserver * observer) { |
+ device_observer_list_->AddObserver(observer); |
+ |
+ // Make sure that every new observer is provided with an |
+ // initial list of devices. |
+ device_observer_list_->Notify( |
+ &DeviceObserver::OnDevicesUpdated, |
+ touch_device_list_); |
+} |
+ |
+void TouchFactory::RemoveDeviceObserver( |
+ TouchFactory::DeviceObserver * observer) { |
+ device_observer_list_->RemoveObserver(observer); |
+} |
+ |
void TouchFactory::UpdateDeviceList(Display* display) { |
// Detect touch devices. |
// NOTE: The new API for retrieving the list of devices (XIQueryDevice) does |
@@ -183,16 +253,24 @@ |
for (int i = 0; i < count; i++) { |
XIDeviceInfo* devinfo = devices + i; |
#if defined(USE_XI2_MT) |
+ MultiTouchDevice mtDevice; |
+ if (ui::xi_device_info_to_mt_device(devinfo, mtDevice)) |
+ touch_device_list_[devinfo->deviceid] = mtDevice; |
+ |
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; |
- touch_device_available_ = true; |
+ switch (tci->mode) { |
+ case XIDirectTouch: |
+ touch_device_lookup_[devinfo->deviceid] = true; |
+ touch_device_available_ = true; |
+ break; |
+ case XIDependentTouch: |
+ touch_device_lookup_[devinfo->deviceid] = true; |
+ touch_device_available_ = true; |
+ break; |
} |
} |
} |
@@ -204,6 +282,9 @@ |
XIFreeDeviceInfo(devices); |
SetupValuator(); |
+ |
+ device_observer_list_->Notify( |
+ &DeviceObserver::OnDevicesUpdated, touch_device_list_); |
} |
bool TouchFactory::ShouldProcessXI2Event(XEvent* xev) { |
@@ -212,6 +293,8 @@ |
XIDeviceEvent* xiev = reinterpret_cast<XIDeviceEvent*>(event); |
#if defined(USE_XI2_MT) |
+ if (event->evtype == XI_HierarchyChanged) |
+ return true; |
if (event->evtype == XI_TouchBegin || |
event->evtype == XI_TouchUpdate || |
event->evtype == XI_TouchEnd) { |
@@ -226,6 +309,24 @@ |
return pointer_device_lookup_[xiev->deviceid]; |
} |
+#if defined(USE_UTOUCH) |
+void TouchFactory::ProcessXI2Event(XEvent* event) { |
+ // Commented out under the assumption that the window host |
+ // already loaded all event data. |
+ /* XGenericEventCookie *xcookie = &event->xcookie; |
+ if(!XGetEventData(ui::GetXDisplay(), xcookie)) { |
+ LOG(ERROR) << "Failed to get X generic event data"; |
+ return; |
+ }else |
+ printf( "Successfully retrieved X generic event data\n" ); |
+ */ |
+ if (UFStatusSuccess != |
+ frame_x11_process_event(utouch_frame_handle_, &event->xcookie)) { |
+ LOG(ERROR) << "Failed to inject X event"; |
+ } |
+} |
+#endif // USE_UTOUCH |
+ |
void TouchFactory::SetupXI2ForXWindow(Window window) { |
// Setup mask for mouse events. It is possible that a device is loaded/plugged |
// in after we have setup XInput2 on a window. In such cases, we need to |
@@ -243,11 +344,13 @@ |
XISetMask(mask, XI_TouchBegin); |
XISetMask(mask, XI_TouchUpdate); |
XISetMask(mask, XI_TouchEnd); |
-#endif |
+ XISetMask(mask, XI_TouchOwnership); |
+ XISetMask(mask, XI_HierarchyChanged); |
+#else |
XISetMask(mask, XI_ButtonPress); |
XISetMask(mask, XI_ButtonRelease); |
XISetMask(mask, XI_Motion); |
- |
+#endif |
XIEventMask evmask; |
evmask.deviceid = XIAllDevices; |
evmask.mask_len = sizeof(mask); |
@@ -264,7 +367,6 @@ |
iter != devices.end(); ++iter) { |
DCHECK(*iter < touch_device_lookup_.size()); |
touch_device_lookup_[*iter] = true; |
- touch_device_list_[*iter] = false; |
} |
SetupValuator(); |
@@ -278,8 +380,8 @@ |
bool TouchFactory::IsMultiTouchDevice(unsigned int deviceid) const { |
return (deviceid < touch_device_lookup_.size() && |
touch_device_lookup_[deviceid]) ? |
- touch_device_list_.find(deviceid)->second : |
- false; |
+ touch_device_list_.find(deviceid) != touch_device_list_.end() : |
+ false; |
} |
#if defined(USE_XI2_MT) |
@@ -343,15 +445,18 @@ |
XISetMask(mask, XI_TouchBegin); |
XISetMask(mask, XI_TouchUpdate); |
XISetMask(mask, XI_TouchEnd); |
-#endif |
+ XISetMask(mask, XI_TouchOwnership); |
+ XISetMask(mask, XI_HierarchyChanged); |
+#else |
XISetMask(mask, XI_ButtonPress); |
XISetMask(mask, XI_ButtonRelease); |
XISetMask(mask, XI_Motion); |
+#endif |
XIEventMask evmask; |
evmask.mask_len = sizeof(mask); |
evmask.mask = mask; |
- for (std::map<int, bool>::const_iterator iter = |
+ for (TouchDeviceList::const_iterator iter = |
touch_device_list_.begin(); |
iter != touch_device_list_.end(); ++iter) { |
evmask.deviceid = iter->first; |
@@ -370,7 +475,7 @@ |
#endif |
bool success = true; |
- for (std::map<int, bool>::const_iterator iter = |
+ for (TouchDeviceList::const_iterator iter = |
touch_device_list_.begin(); |
iter != touch_device_list_.end(); ++iter) { |
Status status = XIUngrabDevice(display, iter->first, CurrentTime); |
@@ -445,13 +550,13 @@ |
// tracking_id valuator. Without these we'll treat the device as a |
// single-touch device (like a mouse). |
// TODO(rbyers): Multi-touch is disabled: http://crbug.com/112329 |
- //if (valuator_lookup_[info->deviceid][TP_SLOT_ID] == -1 || |
+ // if (valuator_lookup_[info->deviceid][TP_SLOT_ID] == -1 || |
// valuator_lookup_[info->deviceid][TP_TRACKING_ID] == -1) { |
DVLOG(1) << "Touch device " << info->deviceid << |
" does not provide enough information for multi-touch, treating as " |
"a single-touch device."; |
touch_device_list_[info->deviceid] = false; |
- //} |
+ // } |
#endif |
} |
@@ -499,12 +604,29 @@ |
TouchParam tp, |
float* min, |
float* max) { |
+#if defined(USE_XI2_MT) |
+ TouchDeviceList::const_iterator it = touch_device_list_.find(deviceid); |
+ if (it == touch_device_list_.end()) |
+ return false; |
+ |
+ MultiTouchDevice::Axes::const_iterator ita = |
+ it->second.axes().find(TouchParamToAxisType(tp)); |
+ |
+ if (ita == it->second.axes().end()) |
+ return false; |
+ |
+ *min = ita->second.min(); |
+ *max = ita->second.max(); |
+ |
+ return true; |
+#else |
if (valuator_lookup_[deviceid][tp] >= 0) { |
*min = touch_param_min_[deviceid][tp]; |
*max = touch_param_max_[deviceid][tp]; |
return true; |
} |
return false; |
+#endif |
} |
} // namespace ui |