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

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 "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);
Elliot Glaysher 2012/03/28 17:49:00 I know nothing about grail. I assume this all runs
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698