Chromium Code Reviews| 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) { |
|
sadrul
2012/04/03 19:52:01
We have way too many types as it is. Either get ri
|
| + 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,20 @@ |
| } |
| 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) |
| + native_root_window_aura_(ui::GetX11RootWindow()), |
| +#if defined(USE_UTOUCH) |
| + utouch_frame_handle_(NULL), |
| +#endif // USE_UTOUCH |
| +#endif // USE_AURA |
| min_available_slot_(0), |
| #endif |
| slots_used_() { |
| @@ -101,13 +141,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 |
| @@ -125,11 +177,19 @@ |
| } |
| TouchFactory::~TouchFactory() { |
| + device_observer_list_->Release(); |
| + ObserverListThreadSafeTraits<DeviceObserver>::Destruct( |
| + device_observer_list_); |
| + |
| #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,7 +199,25 @@ |
| } |
| } |
| +void TouchFactory::AddDeviceObserver(TouchFactory::DeviceObserver * observer) { |
| + device_observer_list_->AddObserver(observer); |
| + |
| + base::AutoLock al(touch_device_list_lock_); |
| + // 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) { |
| + base::AutoLock al(touch_device_list_lock_); |
|
sadrul
2012/04/03 19:52:01
Why?
|
| + |
| // 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 |
| @@ -183,16 +261,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 +290,9 @@ |
| XIFreeDeviceInfo(devices); |
| SetupValuator(); |
| + |
| + device_observer_list_->Notify( |
| + &DeviceObserver::OnDevicesUpdated, touch_device_list_); |
| } |
| bool TouchFactory::ShouldProcessXI2Event(XEvent* xev) { |
| @@ -212,6 +301,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 +317,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,17 +352,25 @@ |
| 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); |
| evmask.mask = mask; |
| XISelectEvents(display, window, &evmask, 1); |
| XFlush(display); |
| + |
| +#if defined(USE_XI2_MT) |
| +#if defined(USE_AURA) |
| + native_root_window_aura_ = window; |
| +#endif |
| +#endif |
| } |
| void TouchFactory::SetTouchDeviceList( |
| @@ -264,7 +381,6 @@ |
| iter != devices.end(); ++iter) { |
| DCHECK(*iter < touch_device_lookup_.size()); |
| touch_device_lookup_[*iter] = true; |
| - touch_device_list_[*iter] = false; |
| } |
| SetupValuator(); |
| @@ -278,8 +394,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 +459,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 +489,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 +564,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 +618,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 |