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

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

Powered by Google App Engine
This is Rietveld 408576698