Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1656)

Side by Side Diff: ui/aura/gestures/gesture_recognizer_grail.cc

Issue 9773024: This patch implements Chromium's Aura gesture recognizer in terms of utouch-grail and utouch-frame … (Closed) Base URL: https://src.chromium.org/svn/trunk/src/
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(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 "base/logging.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/memory/singleton.h"
10 #include "base/time.h"
11 #include "third_party/utouch-frame/include/utouch/frame.h"
12 #include "third_party/utouch-frame/include/utouch/frame_x11.h"
13 #include "third_party/utouch-grail/include/utouch/grail.h"
14 #include "ui/aura/event.h"
15 #include "ui/aura/gestures/gesture_configuration.h"
16 #include "ui/aura/root_window_host_linux.h"
17 #include "ui/aura/root_window.h"
18 #include "ui/aura/window.h"
19 #include "ui/base/events.h"
20 #include "ui/base/touch/touch_factory.h"
21 #include "ui/base/x/x11_util.h"
22
23 namespace {
24
25 static const base::TimeDelta kLongPressTimeThreshold
26 = base::TimeDelta::FromMilliseconds(3000);
27
28 static const base::TimeDelta kDoubleTapTimeout
29 = base::TimeDelta::FromSeconds(
30 aura::GestureConfiguration::max_seconds_between_double_click());
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 // Subscribes to the grail instance (handle)
59 // for two-finger taps, drags and pinches. Please
60 // note that subscribing to the grail instance is non-blocking.
61 // Returns an int with boolean semantics to indicate success or failure.
62 int SubscribeForGestures(
63 UGHandle handle,
64 UFDevice device,
65 ::Window window,
66 UGSubscription subscription) {
67 char * deviceName = NULL;
68 if (UFStatusSuccess ==
69 frame_device_get_property(device, UFDevicePropertyName, &deviceName))
70 DLOG(INFO) << "Subscribing to device: " << deviceName;
71
72 UGStatus status;
73
74 int touches_start = 2;
75 int touches_max = 2;
76 int touches_min = 2;
77 int atomic = 1;
78
79 UFWindowId window_id = frame_x11_create_window_id(window);
80 const UGGestureTypeMask mask =
81 UGGestureTypeDrag |
82 UGGestureTypePinch |
83 UGGestureTypeTap;
84 status = grail_subscription_new(&subscription);
85 if (status != UGStatusSuccess) {
86 LOG(ERROR) << "Failed to create subscription";
87 return 0;
88 }
89
90 status = grail_subscription_set_property(subscription,
91 UGSubscriptionPropertyDevice,
92 &device);
93 if (status != UGStatusSuccess) {
94 LOG(ERROR) << "Failed to set subscription device";
95 return 0;
96 }
97
98 status = grail_subscription_set_property(subscription,
99 UGSubscriptionPropertyWindow,
100 &window_id);
101 if (status != UGStatusSuccess) {
102 LOG(ERROR) << "Failed to set subscription window";
103 return 0;
104 }
105
106 status = grail_subscription_set_property(subscription,
107 UGSubscriptionPropertyAtomicGestures,
108 &atomic);
109 if (status != UGStatusSuccess) {
110 LOG(ERROR) << "Failed to set atomic gestures subscription property.";
111 return 0;
112 }
113
114 status = grail_subscription_set_property(subscription,
115 UGSubscriptionPropertyTouchesStart,
116 &touches_start);
117 if (status != UGStatusSuccess) {
118 LOG(ERROR) << "Failed to set subscription start touches.";
119 return 0;
120 }
121
122 status = grail_subscription_set_property(subscription,
123 UGSubscriptionPropertyTouchesMaximum,
124 &touches_max);
125 if (status != UGStatusSuccess) {
126 LOG(ERROR) << "Failed to set subscription start touches.";
127 return 0;
128 }
129
130 status = grail_subscription_set_property(subscription,
131 UGSubscriptionPropertyTouchesMinimum,
132 &touches_min);
133 if (status != UGStatusSuccess) {
134 LOG(ERROR) << "Failed to set subscription min touches.";
135 return 0;
136 }
137
138 status = grail_subscription_set_property(subscription,
139 UGSubscriptionPropertyMask,
140 &mask);
141 if (status != UGStatusSuccess) {
142 LOG(ERROR) << "Failed to set subscription mask";
143 return 0;
144 }
145
146 status = grail_subscription_activate(handle, subscription);
147 if (status != UGStatusSuccess) {
148 LOG(ERROR) << "Failed to activate subscription\n";
149 return 0;
150 }
151
152 DLOG(INFO) << "Successfully configured and activated grail subscription";
153
154 return 1;
155 }
156
157 } // namespace
158
159 namespace aura {
160
161 // Implements a singleton for a raw grail instance and
162 // makes sure that RAII.
163 class GrailHolder {
164 public:
165 // Returns the singleton instance
166 static GrailHolder* GetInstance() {
167 return Singleton<GrailHolder>::get();
168 }
169
170 // Returns the handle managed by the instance
171 UGHandle handle() const {
172 return utouch_grail_handle_;
173 }
174
175 private:
176 friend struct DefaultSingletonTraits<GrailHolder>;
177
178 GrailHolder()
179 : utouch_grail_handle_(NULL) {
180 if (UGStatusSuccess != grail_new(
181 ui::TouchFactory::GetInstance()->handle(),
182 &utouch_grail_handle_)) {
183 LOG(ERROR) << "Problem initializing grail api.";
184 } else {
185 fd_set set;
186 FD_ZERO(&set);
187 int fd = grail_get_fd(utouch_grail_handle_);
188 FD_SET(fd, &set);
189 }
190 }
191
192 ~GrailHolder() {
193 if (utouch_grail_handle_ != NULL)
194 grail_delete_v3(utouch_grail_handle_);
195 }
196
197 UGHandle utouch_grail_handle_;
198
199 DISALLOW_COPY_AND_ASSIGN(GrailHolder);
200 };
201
202 struct GestureRecognizerGrail::Private {
203 typedef std::map<UFDevice, UGSubscription> SubscriptionMap;
204
205 explicit Private(RootWindow* window)
206 : flags_(0),
207 window_(window) {
208 }
209
210 ~Private() {
211 SubscriptionMap::iterator it;
212 for (it = subscriptions_.begin();
213 it != subscriptions_.end();
214 ++it) {
215 grail_subscription_delete(it->second);
216 }
217 }
218
219 void UpdateFrameInstance(XEvent* xEvent) {
220 if (xEvent != NULL) {
221 if (UFStatusSuccess !=
222 frame_x11_process_event(
223 ui::TouchFactory::GetInstance()->handle(),
224 &xEvent->xcookie)) {
225 LOG(ERROR) << "Failed to inject X event";
226 }
227 } else {
228 LOG(ERROR) << "Failed to extract native event";
229 }
230 }
231
232 void ProcessFrameEvents() {
233 UFEvent ufEvent;
234 while (frame_get_event(
235 ui::TouchFactory::GetInstance()->handle(),
236 &ufEvent) ==
237 UFStatusSuccess) {
238 grail_process_frame_event(
239 GrailHolder::GetInstance()->handle(),
240 ufEvent);
241
242 switch (frame_event_get_type(ufEvent)) {
243 case UFEventTypeDeviceAdded: {
244 UFDevice device = NULL;
245 UFStatus status = frame_event_get_property(ufEvent,
246 UFEventPropertyDevice,
247 &device);
248
249 if (status != UFStatusSuccess)
250 LOG(ERROR) << "Failed to get device from event.";
251 else
252 SubscribeForGestures(
253 GrailHolder::GetInstance()->handle(),
254 device,
255 window_->GetNativeWindow(),
256 subscriptions_[device]);
257
258 break;
259 }
260
261 case UFEventTypeDeviceRemoved: {
262 UFDevice device = NULL;
263 UFStatus status = frame_event_get_property(ufEvent,
264 UFEventPropertyDevice,
265 &device);
266
267 if (status != UFStatusSuccess) {
268 LOG(ERROR) << "Failed to get device from event.";
269 } else {
270 Private::SubscriptionMap::iterator it =
271 subscriptions_.find(device);
272 if (it != subscriptions_.end()) {
273 grail_subscription_delete(it->second);
274 subscriptions_.erase(it);
275 }
276 }
277 break;
278 }
279 default:
280 break;
281 }
282
283 frame_event_unref(ufEvent);
284 }
285 }
286
287 void ProcessSlice(
288 UGSlice slice,
289 uint64_t time,
290 const TouchEvent& event,
291 GestureRecognizer::Gestures * result) {
292 DCHECK(result != NULL);
293
294 const UGGestureTypeMask recognized = grail_slice_get_recognized(slice);
295
296 if (recognized & UGGestureTypePinch) {
297 ProcessPinch(slice, event, result);
298 }
299
300 if (recognized & UGGestureTypeDrag) {
301 ProcessDrag(slice, event, result);
302 }
303
304 if (recognized & UGGestureTypeTap) {
305 ProcessTap(slice, event, result);
306 }
307 }
308
309 void ProcessDrag(UGSlice slice,
310 const TouchEvent& touch_event,
311 Gestures* gestures) {
312 DCHECK(gestures != NULL);
313 ui::EventType event_type = ui::ET_UNKNOWN;
314
315 switch (grail_slice_get_state(slice)) {
316 case UGGestureStateBegin:
317 event_type = ui::ET_GESTURE_SCROLL_BEGIN;
318 break;
319 case UGGestureStateUpdate:
320 event_type = ui::ET_GESTURE_SCROLL_UPDATE;
321 break;
322 case UGGestureStateEnd:
323 event_type = ui::ET_GESTURE_SCROLL_END;
324 break;
325 }
326
327 const UGTransform *transform =
328 grail_slice_get_transform(slice);
329
330 GestureEvent::Properties props;
331 props.delta_x = -(*transform)[0][2];
332 props.delta_y = -(*transform)[1][2];
333
334 GestureEvent * result = new GestureEvent(event_type,
335 touch_event.x(),
336 touch_event.y(),
337 touch_event.flags(),
338 base::Time::Now(),
339 props);
340 gestures->push_back(linked_ptr<GestureEvent>(result));
341 }
342
343 void ProcessPinch(UGSlice slice,
344 const TouchEvent & touch_event,
345 Gestures* gestures) {
346 DCHECK(gestures != NULL);
347 ui::EventType event_type = ui::ET_UNKNOWN;
348 switch (grail_slice_get_state(slice)) {
349 case UGGestureStateBegin:
350 event_type = ui::ET_GESTURE_PINCH_BEGIN;
351 break;
352 case UGGestureStateUpdate:
353 event_type = ui::ET_GESTURE_PINCH_UPDATE;
354 break;
355 case UGGestureStateEnd:
356 event_type = ui::ET_GESTURE_PINCH_END;
357 break;
358 }
359
360 const UGTransform *transform =
361 grail_slice_get_cumulative_transform(slice);
362
363 GestureEvent::Properties props;
364 props.delta_x = (*transform)[0][0];
365 props.delta_y = (*transform)[1][1];
366 props.scale_x = (*transform)[0][0];
367 props.scale_y = (*transform)[1][1];
368
369 GestureEvent * result = new GestureEvent(event_type,
370 touch_event.x(),
371 touch_event.y(),
372 touch_event.flags(),
373 base::Time::Now(),
374 props);
375 gestures->push_back(linked_ptr<GestureEvent>(result));
376 }
377
378 void ProcessTap(UGSlice slice,
379 const TouchEvent & touch_event,
380 Gestures* gestures) {
381 DCHECK(gestures != NULL);
382 ui::EventType event_type = ui::ET_UNKNOWN;
383 switch (grail_slice_get_state(slice)) {
384 case UGGestureStateBegin:
385 gesture_tap_start_ = base::Time::Now();
386 return;
387 break;
388 case UGGestureStateUpdate:
389 return;
390 break;
391 case UGGestureStateEnd: {
392 base::Time now = base::Time::Now();
393 base::TimeDelta dlp = now - gesture_tap_start_;
394 base::TimeDelta ddt = now - last_gesture_tap_completed_;
395 if (dlp >= kLongPressTimeThreshold) {
396 event_type = ui::ET_GESTURE_LONG_PRESS;
397 } else if (ddt < kDoubleTapTimeout) {
398 event_type = ui::ET_GESTURE_DOUBLE_TAP;
399 } else {
400 event_type = ui::ET_GESTURE_TAP;
401 last_gesture_tap_completed_ = now;
402 }
403 gesture_tap_start_ = base::Time::Now();
404 break;
405 }
406 }
407 GestureEvent* result = new GestureEvent(event_type,
408 touch_event.x(),
409 touch_event.y(),
410 touch_event.flags(),
411 base::Time::Now(),
412 GestureEvent::Properties());
413 gestures->push_back(linked_ptr<GestureEvent>(result));
414 }
415
416 int flags_;
417 RootWindow* window_;
418
419 base::Time last_gesture_tap_completed_;
420 base::Time gesture_tap_start_;
421
422 SubscriptionMap subscriptions_;
423 };
424
425
426 ////////////////////////////////////////////////////////////////////////////////
427 // GestureRecognizerGrail Public:
428
429 GestureRecognizerGrail::GestureRecognizerGrail(RootWindow* window)
430 : d_(new Private(window)) {
431 }
432
433 GestureRecognizer::Gestures*
434 GestureRecognizerGrail::ProcessTouchEventForGesture(
435 const TouchEvent& event,
436 ui::TouchStatus status) {
437
438 d_->UpdateFrameInstance(
439 static_cast<XEvent*>(event.native_event()));
440
441 d_->ProcessFrameEvents();
442
443 Gestures * result = new Gestures();
444
445 UGEvent ugEvent;
446 while (grail_get_event(GrailHolder::GetInstance()->handle(), &ugEvent) ==
447 UGStatusSuccess) {
448 switch (grail_event_get_type(ugEvent)) {
449 case UGEventTypeSlice: {
450 UGSlice slice;
451 UGStatus status;
452 status = grail_event_get_property(ugEvent,
453 UGEventPropertySlice, &slice);
454 if (status != UGStatusSuccess) {
455 break;
456 }
457
458 d_->ProcessSlice(slice,
459 grail_event_get_time(ugEvent),
460 event,
461 result);
462 break;
463 }
464 default:
465 break;
466 }
467
468 grail_event_unref(ugEvent);
469 }
470
471 return result;
472 }
473
474 void GestureRecognizerGrail::QueueTouchEventForGesture(
475 Window* /*window*/,
476 const TouchEvent& /*event*/) {
477 }
478
479 GestureRecognizer::Gestures* GestureRecognizerGrail::AdvanceTouchQueue(
480 Window* /*window*/,
481 bool /*processed*/) {
482 return NULL;
483 }
484
485 void GestureRecognizerGrail::FlushTouchQueue(Window* /*window*/) {
486 }
487
488 // GestureRecognizer, static
489 GestureRecognizer* GestureRecognizer::Create(RootWindow* window) {
490 return new GestureRecognizerGrail(window);
491 }
492
493 } // namespace aura
494
OLDNEW
« no previous file with comments | « ui/aura/gestures/gesture_recognizer_grail.h ('k') | ui/aura/gestures/gesture_recognizer_grail_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698