OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "ui/aura/gestures/gesture_recognizer_grail.h" |
| 6 |
| 7 #include <utouch/grail.h> |
| 8 |
| 9 #include "base/logging.h" |
| 10 #include "base/memory/scoped_ptr.h" |
| 11 #include "base/memory/singleton.h" |
| 12 #include "base/time.h" |
| 13 #include "chrome/browser/ui/browser.h" |
| 14 #include "chrome/browser/ui/browser_list.h" |
| 15 #include "content/public/browser/web_contents.h" |
| 16 #include "content/public/browser/web_contents_view.h" |
| 17 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| 18 #include "ui/aura/event.h" |
| 19 #include "ui/aura/window.h" |
| 20 #include "ui/base/events.h" |
| 21 #include "ui/base/x/x11_util.h" |
| 22 #include "ui/base/touch/touch_factory.h" |
| 23 |
| 24 namespace { |
| 25 |
| 26 static const base::TimeDelta kLongPressTimeThreshold |
| 27 = base::TimeDelta::FromMilliseconds(3000); |
| 28 |
| 29 static const base::TimeDelta kDoubleTapTimeout |
| 30 = base::TimeDelta::FromMilliseconds(300); |
| 31 |
| 32 bool GetDeviceAndWindowFromEvent( |
| 33 const UFEvent event, |
| 34 UFDevice* device, |
| 35 UFWindowId* window_id) { |
| 36 |
| 37 UFFrame frame; |
| 38 UFStatus status = frame_event_get_property(event, UFEventPropertyFrame, |
| 39 &frame); |
| 40 if (status != UFStatusSuccess) { |
| 41 LOG(ERROR) << "failed to get frame from event\n"; |
| 42 return false; |
| 43 } |
| 44 |
| 45 *device = frame_frame_get_device(frame); |
| 46 *window_id = frame_frame_get_window_id(frame); |
| 47 |
| 48 char * deviceName; |
| 49 if (UFStatusSuccess == |
| 50 frame_device_get_property(*device, UFDevicePropertyName, &deviceName)) |
| 51 DLOG(INFO) << "Considering device: " << deviceName; |
| 52 else |
| 53 DLOG(INFO) << "Problem reading out device name."; |
| 54 |
| 55 return true; |
| 56 } |
| 57 |
| 58 int SubscribeForGestures( |
| 59 UGHandle handle, |
| 60 UFDevice device, |
| 61 ::Window window, |
| 62 UGSubscription subscription) { |
| 63 char * deviceName = NULL; |
| 64 if (UFStatusSuccess == |
| 65 frame_device_get_property(device, UFDevicePropertyName, &deviceName)) |
| 66 DLOG(INFO) << "Subscribing to device: " << deviceName; |
| 67 |
| 68 UGStatus status; |
| 69 |
| 70 int touches_start = 2; |
| 71 int touches_max = 2; |
| 72 int touches_min = 2; |
| 73 int atomic = 1; |
| 74 |
| 75 UFWindowId window_id = frame_x11_create_window_id(window); |
| 76 const UGGestureTypeMask mask = |
| 77 UGGestureTypeDrag | |
| 78 UGGestureTypePinch | |
| 79 UGGestureTypeTap; |
| 80 status = grail_subscription_new(&subscription); |
| 81 if (status != UGStatusSuccess) { |
| 82 LOG(ERROR) << "Failed to create subscription"; |
| 83 return 0; |
| 84 } |
| 85 |
| 86 status = grail_subscription_set_property(subscription, |
| 87 UGSubscriptionPropertyDevice, |
| 88 &device); |
| 89 if (status != UGStatusSuccess) { |
| 90 LOG(ERROR) << "Failed to set subscription device"; |
| 91 return 0; |
| 92 } |
| 93 |
| 94 status = grail_subscription_set_property(subscription, |
| 95 UGSubscriptionPropertyWindow, |
| 96 &window_id); |
| 97 if (status != UGStatusSuccess) { |
| 98 LOG(ERROR) << "Failed to set subscription window"; |
| 99 return 0; |
| 100 } |
| 101 |
| 102 status = grail_subscription_set_property(subscription, |
| 103 UGSubscriptionPropertyAtomicGestures, |
| 104 &atomic); |
| 105 if (status != UGStatusSuccess) { |
| 106 LOG(ERROR) << "Failed to set atomic gestures subscription property."; |
| 107 return 0; |
| 108 } |
| 109 |
| 110 status = grail_subscription_set_property(subscription, |
| 111 UGSubscriptionPropertyTouchesStart, |
| 112 &touches_start); |
| 113 if (status != UGStatusSuccess) { |
| 114 LOG(ERROR) << "Failed to set subscription start touches."; |
| 115 return 0; |
| 116 } |
| 117 |
| 118 status = grail_subscription_set_property(subscription, |
| 119 UGSubscriptionPropertyTouchesMaximum, |
| 120 &touches_max); |
| 121 if (status != UGStatusSuccess) { |
| 122 LOG(ERROR) << "Failed to set subscription start touches."; |
| 123 return 0; |
| 124 } |
| 125 |
| 126 status = grail_subscription_set_property(subscription, |
| 127 UGSubscriptionPropertyTouchesMinimum, |
| 128 &touches_min); |
| 129 if (status != UGStatusSuccess) { |
| 130 LOG(ERROR) << "Failed to set subscription min touches."; |
| 131 return 0; |
| 132 } |
| 133 |
| 134 status = grail_subscription_set_property(subscription, |
| 135 UGSubscriptionPropertyMask, |
| 136 &mask); |
| 137 if (status != UGStatusSuccess) { |
| 138 LOG(ERROR) << "Failed to set subscription mask"; |
| 139 return 0; |
| 140 } |
| 141 |
| 142 status = grail_subscription_activate(handle, subscription); |
| 143 if (status != UGStatusSuccess) { |
| 144 LOG(ERROR) << "Failed to activate subscription\n"; |
| 145 return 0; |
| 146 } |
| 147 |
| 148 DLOG(INFO) << "Successfully configured and activated grail subscription"; |
| 149 |
| 150 return 1; |
| 151 } |
| 152 |
| 153 } // namespace |
| 154 |
| 155 namespace aura { |
| 156 |
| 157 class GrailHolder { |
| 158 public: |
| 159 static GrailHolder* GetInstance() { |
| 160 return Singleton<GrailHolder>::get(); |
| 161 } |
| 162 |
| 163 UGHandle handle() const { |
| 164 return utouch_grail_handle_; |
| 165 } |
| 166 |
| 167 private: |
| 168 friend struct DefaultSingletonTraits<GrailHolder>; |
| 169 |
| 170 GrailHolder() |
| 171 : utouch_grail_handle_(NULL) { |
| 172 if (UGStatusSuccess != grail_new( |
| 173 ui::TouchFactory::GetInstance()->handle(), |
| 174 &utouch_grail_handle_)) { |
| 175 LOG(ERROR) << "Problem initializing grail api."; |
| 176 } else { |
| 177 fd_set set; |
| 178 FD_ZERO(&set); |
| 179 int fd = grail_get_fd(utouch_grail_handle_); |
| 180 FD_SET(fd, &set); |
| 181 } |
| 182 } |
| 183 |
| 184 ~GrailHolder() { |
| 185 if (utouch_grail_handle_ != NULL) |
| 186 grail_delete_v3(utouch_grail_handle_); |
| 187 } |
| 188 |
| 189 UGHandle utouch_grail_handle_; |
| 190 |
| 191 DISALLOW_COPY_AND_ASSIGN(GrailHolder); |
| 192 }; |
| 193 |
| 194 struct GestureRecognizerGrail::Private { |
| 195 typedef std::map<UFDevice, UGSubscription> SubscriptionMap; |
| 196 |
| 197 explicit Private(RootWindow* window) |
| 198 : flags_(0), |
| 199 window_(window) { |
| 200 } |
| 201 |
| 202 ~Private() { |
| 203 SubscriptionMap::iterator it; |
| 204 for (it = subscriptions_.begin(); |
| 205 it != subscriptions_.end(); |
| 206 ++it) { |
| 207 grail_subscription_delete(it->second); |
| 208 } |
| 209 } |
| 210 |
| 211 void ProcessSlice( |
| 212 UGSlice slice, |
| 213 uint64_t time, |
| 214 const TouchEvent& event, |
| 215 GestureRecognizer::Gestures * result) { |
| 216 assert(result != NULL); |
| 217 |
| 218 const UGGestureTypeMask recognized = grail_slice_get_recognized(slice); |
| 219 |
| 220 if (recognized & UGGestureTypePinch) { |
| 221 linked_ptr<GestureEvent> lp(ProcessPinch(slice, event)); |
| 222 if (lp.get() != NULL) |
| 223 result->push_back(lp); |
| 224 } |
| 225 |
| 226 if (recognized & UGGestureTypeDrag) { |
| 227 linked_ptr<GestureEvent> lp(ProcessDrag(slice, event)); |
| 228 if (lp.get() != NULL) |
| 229 result->push_back(lp); |
| 230 } |
| 231 |
| 232 if (recognized & UGGestureTypeTap) { |
| 233 linked_ptr<GestureEvent> lp(ProcessTap(slice, event)); |
| 234 if (lp.get() != NULL) |
| 235 result->push_back(lp); |
| 236 } |
| 237 } |
| 238 |
| 239 linked_ptr<GestureEvent> ProcessDrag(UGSlice slice, |
| 240 const TouchEvent& touch_event) { |
| 241 ui::EventType event_type = ui::ET_UNKNOWN; |
| 242 |
| 243 switch (grail_slice_get_state(slice)) { |
| 244 case UGGestureStateBegin: |
| 245 event_type = ui::ET_GESTURE_SCROLL_BEGIN; |
| 246 break; |
| 247 case UGGestureStateUpdate: |
| 248 event_type = ui::ET_GESTURE_SCROLL_UPDATE; |
| 249 break; |
| 250 case UGGestureStateEnd: |
| 251 event_type = ui::ET_GESTURE_SCROLL_END; |
| 252 break; |
| 253 } |
| 254 |
| 255 const UGTransform *transform = |
| 256 grail_slice_get_transform(slice); |
| 257 |
| 258 GestureEvent::Properties props; |
| 259 props.delta_x = -(*transform)[0][2]; |
| 260 props.delta_y = -(*transform)[1][2]; |
| 261 |
| 262 GestureEvent * result = new GestureEvent(event_type, |
| 263 touch_event.x(), |
| 264 touch_event.y(), |
| 265 touch_event.flags(), |
| 266 base::Time::Now(), |
| 267 props); |
| 268 return linked_ptr<GestureEvent>(result); |
| 269 } |
| 270 |
| 271 linked_ptr<GestureEvent> ProcessPinch(UGSlice slice, |
| 272 const TouchEvent & touch_event) { |
| 273 ui::EventType event_type = ui::ET_UNKNOWN; |
| 274 switch (grail_slice_get_state(slice)) { |
| 275 case UGGestureStateBegin: |
| 276 event_type = ui::ET_GESTURE_PINCH_BEGIN; |
| 277 break; |
| 278 case UGGestureStateUpdate: |
| 279 event_type = ui::ET_GESTURE_PINCH_UPDATE; |
| 280 break; |
| 281 case UGGestureStateEnd: |
| 282 event_type = ui::ET_GESTURE_PINCH_END; |
| 283 break; |
| 284 } |
| 285 |
| 286 const UGTransform *transform = |
| 287 grail_slice_get_cumulative_transform(slice); |
| 288 |
| 289 GestureEvent::Properties props; |
| 290 props.delta_x = (*transform)[0][0]; |
| 291 props.delta_y = (*transform)[1][1]; |
| 292 props.scale_x = (*transform)[0][0]; |
| 293 props.scale_y = (*transform)[1][1]; |
| 294 |
| 295 GestureEvent * result = new GestureEvent(event_type, |
| 296 touch_event.x(), |
| 297 touch_event.y(), |
| 298 touch_event.flags(), |
| 299 base::Time::Now(), |
| 300 props); |
| 301 |
| 302 return linked_ptr<GestureEvent>(result); |
| 303 } |
| 304 |
| 305 linked_ptr<GestureEvent> ProcessTap(UGSlice slice, |
| 306 const TouchEvent & touch_event) { |
| 307 ui::EventType event_type = ui::ET_UNKNOWN; |
| 308 switch (grail_slice_get_state(slice)) { |
| 309 case UGGestureStateBegin: |
| 310 gesture_tap_start_ = base::Time::Now(); |
| 311 return linked_ptr<GestureEvent>(NULL); |
| 312 break; |
| 313 case UGGestureStateUpdate: |
| 314 return linked_ptr<GestureEvent>(NULL); |
| 315 break; |
| 316 case UGGestureStateEnd: { |
| 317 base::Time now = base::Time::Now(); |
| 318 base::TimeDelta dlp = now - gesture_tap_start_; |
| 319 base::TimeDelta ddt = now - last_gesture_tap_completed_; |
| 320 if (dlp >= kLongPressTimeThreshold) { |
| 321 event_type = ui::ET_GESTURE_LONG_PRESS; |
| 322 } else if (ddt < kDoubleTapTimeout) { |
| 323 event_type = ui::ET_GESTURE_DOUBLE_TAP; |
| 324 } else { |
| 325 event_type = ui::ET_GESTURE_TAP; |
| 326 last_gesture_tap_completed_ = now; |
| 327 } |
| 328 gesture_tap_start_ = base::Time::Now(); |
| 329 break; |
| 330 } |
| 331 } |
| 332 |
| 333 return linked_ptr<GestureEvent>(new GestureEvent( |
| 334 event_type, |
| 335 touch_event.x(), |
| 336 touch_event.y(), |
| 337 touch_event.flags(), |
| 338 base::Time::Now(), |
| 339 GestureEvent::Properties())); |
| 340 } |
| 341 |
| 342 int flags_; |
| 343 RootWindow* window_; |
| 344 |
| 345 base::Time last_gesture_tap_completed_; |
| 346 base::Time gesture_tap_start_; |
| 347 |
| 348 SubscriptionMap subscriptions_; |
| 349 }; |
| 350 |
| 351 |
| 352 //////////////////////////////////////////////////////////////////////////////// |
| 353 // GestureRecognizerGrail Public: |
| 354 |
| 355 GestureRecognizerGrail::GestureRecognizerGrail(RootWindow* window) |
| 356 : d_(new Private(window)) { |
| 357 } |
| 358 |
| 359 GestureRecognizer::Gestures* |
| 360 GestureRecognizerGrail::ProcessTouchEventForGesture( |
| 361 const TouchEvent& event, |
| 362 ui::TouchStatus status) { |
| 363 |
| 364 UFEvent ufEvent; |
| 365 while (frame_get_event( |
| 366 ui::TouchFactory::GetInstance()->handle(), |
| 367 &ufEvent) == |
| 368 UFStatusSuccess) { |
| 369 grail_process_frame_event( |
| 370 GrailHolder::GetInstance()->handle(), |
| 371 ufEvent); |
| 372 |
| 373 switch (frame_event_get_type(ufEvent)) { |
| 374 case UFEventTypeDeviceAdded: { |
| 375 UFDevice device = NULL; |
| 376 UFStatus status = frame_event_get_property(ufEvent, |
| 377 UFEventPropertyDevice, |
| 378 &device); |
| 379 |
| 380 if (status != UFStatusSuccess) |
| 381 LOG(ERROR) << "Failed to get device from event."; |
| 382 else |
| 383 SubscribeForGestures( |
| 384 GrailHolder::GetInstance()->handle(), |
| 385 device, |
| 386 ui::TouchFactory::GetInstance()->native_root_window_aura(), |
| 387 d_->subscriptions_[device]); |
| 388 |
| 389 break; |
| 390 } |
| 391 |
| 392 case UFEventTypeDeviceRemoved: { |
| 393 UFDevice device = NULL; |
| 394 UFStatus status = frame_event_get_property(ufEvent, |
| 395 UFEventPropertyDevice, |
| 396 &device); |
| 397 |
| 398 if (status != UFStatusSuccess) { |
| 399 LOG(ERROR) << "Failed to get device from event."; |
| 400 } else { |
| 401 Private::SubscriptionMap::iterator it = |
| 402 d_->subscriptions_.find(device); |
| 403 if (it != d_->subscriptions_.end()) { |
| 404 grail_subscription_delete(it->second); |
| 405 d_->subscriptions_.erase(it); |
| 406 } |
| 407 } |
| 408 break; |
| 409 } |
| 410 default: |
| 411 break; |
| 412 } |
| 413 |
| 414 frame_event_unref(ufEvent); |
| 415 } |
| 416 |
| 417 Gestures * result = new Gestures(); |
| 418 UGEvent ugEvent; |
| 419 while (grail_get_event(GrailHolder::GetInstance()->handle(), &ugEvent) == |
| 420 UGStatusSuccess) { |
| 421 switch (grail_event_get_type(ugEvent)) { |
| 422 case UGEventTypeSlice: { |
| 423 UGSlice slice; |
| 424 UGStatus status; |
| 425 status = grail_event_get_property(ugEvent, |
| 426 UGEventPropertySlice, &slice); |
| 427 if (status != UGStatusSuccess) { |
| 428 break; |
| 429 } |
| 430 |
| 431 d_->ProcessSlice(slice, |
| 432 grail_event_get_time(ugEvent), |
| 433 event, |
| 434 result); |
| 435 break; |
| 436 } |
| 437 default: |
| 438 break; |
| 439 } |
| 440 |
| 441 grail_event_unref(ugEvent); |
| 442 } |
| 443 |
| 444 return result; |
| 445 } |
| 446 |
| 447 // GestureRecognizer, static |
| 448 GestureRecognizer* GestureRecognizer::Create(RootWindow* window) { |
| 449 return new GestureRecognizerGrail(window); |
| 450 } |
| 451 |
| 452 } // namespace aura |
OLD | NEW |