Merge lp:~chasedouglas/grail/touch-states into lp:grail

Proposed by Chase Douglas
Status: Merged
Approved by: Daniel d'Andrada
Approved revision: 224
Merged at revision: 219
Proposed branch: lp:~chasedouglas/grail/touch-states
Merge into: lp:grail
Prerequisite: lp:~chasedouglas/grail/indent-fixes
Diff against target: 1725 lines (+567/-461)
14 files modified
src/Makefile.am (+3/-1)
src/v3/atomic-recognizer.cpp (+64/-54)
src/v3/atomic-recognizer.h (+2/-2)
src/v3/forward.h (+9/-3)
src/v3/gesture.cpp (+41/-71)
src/v3/gesture.h (+10/-10)
src/v3/recognizer.cpp (+58/-94)
src/v3/recognizer.h (+15/-15)
src/v3/regular-recognizer.cpp (+177/-164)
src/v3/regular-recognizer.h (+8/-8)
src/v3/slice.cpp (+22/-34)
src/v3/slice.h (+5/-5)
src/v3/touch.cpp (+89/-0)
src/v3/touch.h (+64/-0)
To merge this branch: bzr merge lp:~chasedouglas/grail/touch-states
Reviewer Review Type Date Requested Status
Daniel d'Andrada (community) Approve
Chase Douglas (community) Needs Resubmitting
Review via email: mp+99566@code.launchpad.net

This proposal supersedes a proposal from 2012-03-26.

Description of the change

Fix touch state accounting. With this branch, unity gestures should
function appropriately, modulo bugs in unity itself.

I am proposing this now so the code can be reviewed. I will write a test
and propose it before merging this branch.

If this is deemed to be an inappropriate fix, we can take some of the
individual fixes that really fix things and backport them to the current
code. However, I think this gives us a better base going forward for
touch accounting.

The branch contains some miscellaneous format cleanups here and there.
They are all indentation fixes IIRC.

To post a comment you must log in.
Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

* some changes merely fix indentation. That pollutes the commit diff and bzr history.
* touch.h and touch.cpp headers should have a 2012 copyright and should be LGPL.
* I don't like the cyclic reference "Touch <-> Recognizer" even though Touch doesn't hold a shared_ptr of Recognizer. I think it would be cleaner to pass device and window_id to Touch instead of the recognizer himself. As for the Recognizer::DeleteTouch() call, since recognizer holds weak pointers things are still under control. When querying all_touches_ you would just have to also check whether the content is null and if so remove it from the list. Can we use sigc++ or some library that provides signals and slots? That would be the best solution.

Revision history for this message
Chase Douglas (chasedouglas) wrote : Posted in a previous version of this proposal

> * some changes merely fix indentation. That pollutes the commit diff and bzr
> history.

I don't usually see any issues with fixing formatting as you go. It would be nicer to always have it split out into separate commits, but the burden for maintaining those commits usually means people don't bother with them, even when it's within the same area of code. In other words, I would rather allow for a few format fixes than potentially forgo format fixing contributions because of the extra effort involved for trivial gain.

I wouldn't mind proposing this as a question to the utouch team to get feedback and make a policy decision.

> * touch.h and touch.cpp headers should have a 2012 copyright and should be
> LGPL.

Good catch :).

> * I don't like the cyclic reference "Touch <-> Recognizer" even though Touch
> doesn't hold a shared_ptr of Recognizer. I think it would be cleaner to pass
> device and window_id to Touch instead of the recognizer himself. As for the
> Recognizer::DeleteTouch() call, since recognizer holds weak pointers things
> are still under control. When querying all_touches_ you would just have to
> also check whether the content is null and if so remove it from the list.

The reason Recognizer needs the all_touches_ map is so it can update an existing touch state object that it may not have a reference to. If a touch is past the composition time, it will no longer exist in the free_touches_ map. The all_touches_ map is basically a per-recognizer global touch set.

I originally passed the device and window id directly to the touch object. I had to switch to the all_touches_ map because of the above issue.

> Can
> we use sigc++ or some library that provides signals and slots? That would be
> the best solution.

How would that resolve this issue?

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

> [...]
> > Can
> > we use sigc++ or some library that provides signals and slots? That would be
> > the best solution.
>
> How would that resolve this issue?

Recognizer {
  connect touch.destroyed(id) to this::DeleteTouch(id)
}

Touch {
  ~Touch() {
    emit destroyed(id);
  }
}

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

> > * some changes merely fix indentation. That pollutes the commit diff and bzr
> > history.
>
> I don't usually see any issues with fixing formatting as you go. It would be
> nicer to always have it split out into separate commits, [...]

What I meant is to only fix the coding style of the lines your commit has to change anyway. Purely cosmetic/coding style commits wouldn't be made.

Yes, we could propose that policy to the team to collect feedack.

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

AtomicRecognizer::CollectNewTouches() was meant to fill in only the new_touches_ set, hence its name. Now it's also changing all_touches_ and free_touches_ sets. That leaves its name and documentation inconsistent with what it actually does. For clarity's sake I think that method should either be renamed or the other sets updated elsewhere.

Revision history for this message
Chase Douglas (chasedouglas) wrote : Posted in a previous version of this proposal

I have worked around the circular referencing between the recognizer and touch classes. There isn't a need for signals here.

I'm not opposed to signals, Daniel pointed out some good reasons for using them on irc. However, we're too late in the cycle to add a new dependency so any changes we make will need to be done using direct method calls instead of signals.

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

* touch.h - you forgot to remove line 29
* touch.cpp - you forgot to remove line 26
* gesture.h:46 - s/touch_id/touch
* regular-recognizer.cpp
 - 107 - you could take the opportunity and fix that comment. It reffers to accepted stuff instead of unaccepted.
 - 125 - trailing whitespace

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

Looks good, apart from the small issues mentioned in previous commits

review: Needs Fixing
Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

> Looks good, apart from the small issues mentioned in previous commits
s/commits/comments

Revision history for this message
Chase Douglas (chasedouglas) wrote :

All the comments should be addressed by the prerequisite branch and changes in this branch.

review: Needs Resubmitting
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

Looking good!

I would leave commit 218 out but that's up to you

review: Approve
Revision history for this message
Chase Douglas (chasedouglas) wrote :

I have verified on my personal amd64 and i386 systems that all the tests pass and no memory leaks in grail occur.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/Makefile.am'
2--- src/Makefile.am 2012-03-20 20:45:15 +0000
3+++ src/Makefile.am 2012-03-27 17:29:32 +0000
4@@ -65,7 +65,9 @@
5 v3/slice.cpp \
6 v3/slice.h \
7 v3/subscription.cpp \
8- v3/subscription.h
9+ v3/subscription.h \
10+ v3/touch.cpp \
11+ v3/touch.h
12 endif
13
14 INCLUDES = -I$(top_srcdir)/include/ $(FRAME_CFLAGS)
15
16=== modified file 'src/v3/atomic-recognizer.cpp'
17--- src/v3/atomic-recognizer.cpp 2012-03-27 17:29:32 +0000
18+++ src/v3/atomic-recognizer.cpp 2012-03-27 17:29:32 +0000
19@@ -32,6 +32,7 @@
20 #include "v3/handle.h"
21 #include "v3/gesture.h"
22 #include "v3/log.h"
23+#include "v3/touch.h"
24
25 namespace {
26 const uint64_t MAX_TOUCHES_FOR_GESTURES = 5;
27@@ -59,7 +60,7 @@
28 uint64_t event_time = frame_event_get_time(event);
29
30 UpdateTime(event_time);
31- CollectNewTouches(event);
32+ ProcessTouches(event);
33 if (new_touches_.size() > 0) {
34 /* process all new touches at once to avoid the premature initiation of
35 gestures for less touches than what the event brings */
36@@ -83,7 +84,8 @@
37 * subscription, add the touches to the gesture and accept them. Otherwise, end
38 * the gesture and add the current gesture touches to the free touches list.
39 */
40-void AtomicRecognizer::HandleNewTouchesForAcceptedGesture(const SharedGesture& gesture) {
41+void AtomicRecognizer::HandleNewTouchesForAcceptedGesture(
42+ const SharedGesture& gesture) {
43 UGSubscription* subscription = gesture->subscription();
44 if (gesture->current_touches().size() + new_touches_.size() <=
45 subscription->touches_max()) {
46@@ -91,23 +93,21 @@
47 LOG(Dbg) << "new_touches_ have been added to atomic gesture "
48 << gesture->id() << "\n";
49
50- for (UFTouchId touch_id : new_touches_) {
51- if (frame_x11_accept_touch(device_, window_id_, touch_id) !=
52- UFStatusSuccess)
53- LOG(Err) << "touch " << touch_id << " failed to be accepted\n";
54-
55- LOG(Dbg) << "touch " << touch_id
56+ for (const auto& pair : new_touches_) {
57+ const SharedTouch& touch = pair.second;
58+ touch->Accept();
59+ LOG(Dbg) << "touch " << touch->id()
60 << " has been accepted because it has been added to an atomic "
61 "gesture\n";
62
63- INSERT_TOUCH(touch_id, accepted_touches_);
64- ERASE_TOUCH(touch_id, unaccepted_touches_);
65- ERASE_TOUCH(touch_id, free_touches_);
66+ ERASE_TOUCH(touch->id(), free_touches_);
67 }
68 CLEAR_TOUCHES(new_touches_);
69 } else {
70- for (UFTouchId touch : gesture->current_touches())
71+ for (const auto& pair : gesture->current_touches()) {
72+ const SharedTouch& touch = pair.second;
73 INSERT_TOUCH(touch, free_touches_);
74+ }
75 gesture->End();
76 LOG(Dbg) << "ended active atomic gesture " << gesture->id()
77 << " because " << new_touches_.size()
78@@ -130,14 +130,17 @@
79 UGSubscription* subscription = gesture->subscription();
80 if (gesture->current_touches().size() + new_touches_.size() <=
81 subscription->touches_max()) {
82- for (UFTouchId touch_id : new_touches_) {
83- gesture->AddTouch(touch_id);
84- LOG(Dbg) << "touch " << touch_id << " has been added to atomic gesture "
85- << gesture->id() << "\n";
86+ for (const auto& pair : new_touches_) {
87+ const SharedTouch& touch = pair.second;
88+ gesture->AddTouch(touch);
89+ LOG(Dbg) << "touch " << touch->id() << " has been added to atomic "
90+ << "gesture " << gesture->id() << "\n";
91 }
92 } else {
93- for (UFTouchId touch_id : gesture->current_touches())
94- INSERT_TOUCH(touch_id, free_touches_);
95+ for (const auto& pair : gesture->current_touches()) {
96+ const SharedTouch& touch = pair.second;
97+ INSERT_TOUCH(touch, free_touches_);
98+ }
99 gesture->Cancel();
100 LOG(Dbg) << "canceled inactive atomic gesture " << gesture->id()
101 << " because a new touch began and the max touches has been "
102@@ -148,13 +151,13 @@
103
104 /**
105 * @internal
106- * Register all new touches present in the given uTouch-Frame event.
107+ * Process all touches present in the given uTouch-Frame event.
108+ *
109+ * Add new touches to new_touches_ and free_touches_ maps, update the grail
110+ * touch state for existing touches, and remove touches from maps when they
111+ * physically end.
112 */
113-void AtomicRecognizer::CollectNewTouches(const UFEvent event) {
114- /* Check if any subscriptions are active before doing any processing */
115- if (num_subscriptions_ == 0)
116- return;
117-
118+void AtomicRecognizer::ProcessTouches(const UFEvent event) {
119 UFFrame frame;
120 UFStatus status = frame_event_get_property(event, UFEventPropertyFrame,
121 &frame);
122@@ -164,8 +167,6 @@
123 }
124
125 unsigned int num_touches = frame_frame_get_num_touches(frame);
126- uint64_t touch_start_time;
127- UFTouchId touch_id;
128 for (unsigned int i = 0; i < num_touches; ++i) {
129 UFTouch touch;
130 status = frame_frame_get_touch_by_index(frame, i, &touch);
131@@ -174,26 +175,33 @@
132 continue;
133 }
134
135- touch_id = frame_touch_get_id(touch);
136-
137 switch (frame_touch_get_state(touch)) {
138- case UFTouchStateBegin:
139- touch_start_time = frame_touch_get_start_time(touch);
140-
141- /* Note touch start time and add to initial touch lists */
142- start_times_[touch_id] = touch_start_time;
143- LOG(Dbg) << "touch " << touch_id << " began with start time "
144- << start_times_[touch_id] << "\n";
145-
146- INSERT_TOUCH(touch_id, new_touches_);
147- break;
148-
149- case UFTouchStateEnd:
150- ERASE_TOUCH(touch_id, new_touches_);
151- break;
152-
153- default:
154- break;
155+ case UFTouchStateBegin: {
156+ SharedTouch grail_touch(new Touch(touch, device_, window_id_));
157+
158+ LOG(Dbg) << "touch " << grail_touch->id() << " began with start time "
159+ << grail_touch->start_time() << "\n";
160+
161+ INSERT_TOUCH(grail_touch, all_touches_);
162+ INSERT_TOUCH(grail_touch, new_touches_);
163+ break;
164+ }
165+
166+ case UFTouchStateUpdate:
167+ case UFTouchStateEnd: {
168+ auto it = all_touches_.find(frame_touch_get_id(touch));
169+ if (it != all_touches_.end()) {
170+ const SharedTouch& grail_touch = it->second;
171+
172+ grail_touch->Update(touch);
173+
174+ if (grail_touch->pending_end() || grail_touch->ended()) {
175+ ERASE_TOUCH(grail_touch->id(), new_touches_);
176+ ERASE_TOUCH(grail_touch->id(), free_touches_);
177+ }
178+ }
179+ break;
180+ }
181 }
182 }
183 }
184@@ -210,9 +218,9 @@
185 return;
186
187 /* The new touches can now be used */
188- for (UFTouchId touch_id : new_touches_) {
189- INSERT_TOUCH(touch_id, unaccepted_touches_);
190- INSERT_TOUCH(touch_id, free_touches_);
191+ for (const auto& pair : new_touches_) {
192+ const SharedTouch& touch = pair.second;
193+ INSERT_TOUCH(touch, free_touches_);
194 }
195
196 /* HandleNewTouchForAcceptedGesture may erase the gesture from
197@@ -249,15 +257,17 @@
198
199 uint64_t min_start_time = std::numeric_limits<uint64_t>::max();
200 uint64_t max_start_time = 0;
201- for (UFTouchId touch_id : free_touches_) {
202- if (unaccepted_touches_.find(touch_id) == unaccepted_touches_.end())
203+ for (const auto& pair : free_touches_) {
204+ const SharedTouch& touch = pair.second;
205+
206+ if (touch->accepted())
207 continue;
208
209- if (start_times_[touch_id] < min_start_time)
210- min_start_time = start_times_[touch_id];
211+ if (touch->start_time() < min_start_time)
212+ min_start_time = touch->start_time();
213
214- if (start_times_[touch_id] > max_start_time)
215- max_start_time = start_times_[touch_id];
216+ if (touch->start_time() > max_start_time)
217+ max_start_time = touch->start_time();
218 }
219
220 /* All touches in a gesture must begin within a composition timeframe */
221
222=== modified file 'src/v3/atomic-recognizer.h'
223--- src/v3/atomic-recognizer.h 2012-03-26 16:12:59 +0000
224+++ src/v3/atomic-recognizer.h 2012-03-27 17:29:32 +0000
225@@ -37,7 +37,7 @@
226 private:
227 void HandleNewTouchesForAcceptedGesture(const SharedGesture& gesture);
228 void HandleNewTouchesForUnacceptedGesture(const SharedGesture& gesture);
229- void CollectNewTouches(const UFEvent event);
230+ void ProcessTouches(const UFEvent event);
231 void MatchSubscriptionsForNewTouches();
232 void MatchGestures();
233 void FindGesturesToAccept(uint64_t event_time);
234@@ -45,7 +45,7 @@
235
236 /* Touches that have begun but not yet been matched against subscriptions
237 (for the creation of new gestures) or used to update existing gestures. */
238- TouchSet new_touches_;
239+ TouchMap new_touches_;
240 };
241
242 } // namespace grail
243
244=== modified file 'src/v3/forward.h'
245--- src/v3/forward.h 2012-03-26 12:57:55 +0000
246+++ src/v3/forward.h 2012-03-27 17:29:32 +0000
247@@ -21,6 +21,7 @@
248 #ifndef UTOUCH_GRAIL_FORWARD_H_
249 #define UTOUCH_GRAIL_FORWARD_H_
250
251+#include <map>
252 #include <memory>
253 #include <set>
254 #include <sstream>
255@@ -42,22 +43,27 @@
256 class Recognizer;
257 typedef std::shared_ptr<Recognizer> SharedRecognizer;
258
259+class Touch;
260+typedef std::shared_ptr<Touch> SharedTouch;
261+
262 class UGSlice;
263 typedef std::shared_ptr<UGSlice> SharedUGSlice;
264
265 class UGSubscription;
266 typedef std::shared_ptr<UGSubscription> SharedUGSubscription;
267
268-class TouchSet : public std::set<UFTouchId> {
269+typedef std::set<UFTouchId> TouchSet;
270+
271+class TouchMap : public std::map<UFTouchId, SharedTouch> {
272
273 public:
274 std::string ToString() const {
275 std::ostringstream stream;
276 auto it = begin();
277 if (it != end())
278- stream << *it++;
279+ stream << (it++)->first;
280 while (it != end())
281- stream << ", " << *it++;
282+ stream << ", " << (it++)->first;
283 return stream.str();
284 }
285 };
286
287=== modified file 'src/v3/gesture.cpp'
288--- src/v3/gesture.cpp 2012-03-26 17:46:22 +0000
289+++ src/v3/gesture.cpp 2012-03-27 17:29:32 +0000
290@@ -30,6 +30,7 @@
291 #include "v3/log.h"
292 #include "v3/recognizer.h"
293 #include "v3/slice.h"
294+#include "v3/touch.h"
295
296 namespace utouch {
297 namespace grail {
298@@ -39,12 +40,11 @@
299 * Creates a new gesture
300 */
301 Gesture::Gesture(Recognizer* recognizer, UGSubscription* subscription,
302- TouchSet& touches, uint64_t start_time)
303+ TouchMap& touches, uint64_t start_time)
304 : recognizer_(recognizer),
305 id_(recognizer_->handle()->NewGestureID(recognizer_)),
306 subscription_(subscription),
307 current_touches_(touches),
308- unowned_touches_(touches),
309 all_touches_(touches),
310 start_time_(start_time),
311 owned_(false),
312@@ -59,12 +59,11 @@
313 * @internal
314 * Copies an existing gesture, but with the passed in touch set
315 */
316-Gesture::Gesture(const Gesture* other_gesture, TouchSet& touches)
317+Gesture::Gesture(const Gesture* other_gesture, TouchMap& touches)
318 : recognizer_(other_gesture->recognizer_),
319 id_(recognizer_->handle()->NewGestureID(recognizer_)),
320 subscription_(other_gesture->subscription_),
321 current_touches_(touches),
322- unowned_touches_(touches),
323 all_touches_(touches),
324 start_time_(other_gesture->start_time_),
325 owned_(false),
326@@ -78,28 +77,26 @@
327 * @internal
328 * Add a new touch to an existing gesture
329 */
330-void Gesture::AddTouch(UFTouchId touch_id) {
331- current_touches_.insert(touch_id);
332- unowned_touches_.insert(touch_id);
333- all_touches_.insert(touch_id);
334+void Gesture::AddTouch(const SharedTouch& touch) {
335+ current_touches_[touch->id()] = touch;
336+ all_touches_[touch->id()] = touch;
337 }
338
339 /**
340 * @internal
341 * Add a new set of touches to an existing gesture.
342 */
343-void Gesture::AddTouches(TouchSet touch_set) {
344- current_touches_.insert(touch_set.begin(), touch_set.end());
345- unowned_touches_.insert(touch_set.begin(), touch_set.end());
346- all_touches_.insert(touch_set.begin(), touch_set.end());
347+void Gesture::AddTouches(TouchMap touches) {
348+ current_touches_.insert(touches.begin(), touches.end());
349+ all_touches_.insert(touches.begin(), touches.end());
350 }
351
352 /**
353 * @internal
354 * Returns whether that gesture contains the given touch.
355 */
356-bool Gesture::ContainsTouch(UFTouchId touch_id) const {
357- return current_touches_.find(touch_id) != current_touches_.end();
358+bool Gesture::ContainsTouch(const SharedTouch& touch) const {
359+ return current_touches_.find(touch->id()) != current_touches_.end();
360 }
361
362 /**
363@@ -128,37 +125,25 @@
364 TouchSet ended_touches;
365 bool touch_found = false;
366 for (UFTouchId touch_id : modified_touches) {
367+ const auto& it = current_touches_.find(touch_id);
368+
369 /* If the touch is not part of this gesture, skip it */
370- if (current_touches_.find(touch_id) != current_touches_.end())
371+ if (it != current_touches_.end())
372 touch_found = true;
373 else
374 continue;
375
376- UFTouch touch;
377- status = frame_frame_get_touch_by_id(frame, touch_id, &touch);
378- if (status != UFStatusSuccess) {
379- LOG(Warn) << "failed to get touch from frame\n";
380- return;
381- }
382-
383- UFTouchState state = frame_touch_get_state(touch);
384- int owned;
385- status = frame_touch_get_property(touch, UFTouchPropertyOwned, &owned);
386- if (status != UFStatusSuccess) {
387- LOG(Warn) << "failed to get touch from frame\n";
388- return;
389- }
390-
391- if (state == UFTouchStateEnd) {
392- if (owned) {
393- ended_touches.insert(touch_id);
394- } else {
395- /* If we receive a touch end before we own it, someone higher in the
396- * stack accepted it. We need to cancel any handling of the touch. */
397- canceled_ = true;
398- break;
399- }
400- }
401+ const SharedTouch& touch = it->second;
402+
403+ if (touch->ended() && !touch->owned()) {
404+ /* If we receive a touch end before we own it, someone higher in the
405+ * stack accepted it. We need to cancel any handling of the touch. */
406+ canceled_ = true;
407+ break;
408+ }
409+
410+ if (touch->pending_end() || touch->ended())
411+ ended_touches.insert(touch->id());
412 }
413
414 /* If the frame doesn't include any info about the touches in the gesture, or
415@@ -265,6 +250,7 @@
416 if (IsPhysicallyEnded()) {
417 ended_ = true;
418 last_slice_.reset();
419+ LOG(Dbg) << "gesture " << id_ << " has ended\n";
420 }
421 }
422
423@@ -276,41 +262,19 @@
424 if (owned_ || not_owned_)
425 return;
426
427- for (auto it = unowned_touches_.begin(); it != unowned_touches_.end(); ) {
428- UFTouchId touch_id = *it++;
429- UFTouch touch;
430- UFStatus status = frame_frame_get_touch_by_id(slices_.back()->frame(),
431- touch_id, &touch);
432- if (status != UFStatusSuccess) {
433- LOG(Warn) << "failed to get touch " << touch_id << " from frame, gesture "
434- << id_ << " marked as not owned\n";
435- not_owned_ = true;
436- return;
437- }
438+ for (const auto& pair : all_touches_) {
439+ const SharedTouch& touch = pair.second;
440
441- int owned;
442- status = frame_touch_get_property(touch, UFTouchPropertyOwned, &owned);
443- if (status != UFStatusSuccess) {
444+ if (touch->owned()) {
445+ continue;
446+ } else if (touch->ended()) {
447 LOG(Warn) << "failed to get ownership property from touch, gesture "
448 << id_ << " marked as not owned\n";
449 not_owned_ = true;
450 return;
451- }
452-
453- if (owned) {
454- LOG(Dbg) << "touch " << touch_id << " is now owned for gesture " << id_
455- << "\n";
456- unowned_touches_.erase(touch_id);
457- continue;
458- }
459-
460- if (frame_touch_get_state(touch) == UFTouchStateEnd) {
461- LOG(Dbg) << "touch " << touch_id << "ended before it was owned, gesture "
462- << id_ << " marked as not owned\n";
463- not_owned_ = true;
464- }
465-
466- return;
467+ } else {
468+ return;
469+ }
470 }
471
472 LOG(Dbg) << "all touches owned, marking gesture " << id_ << " as owned\n";
473@@ -397,7 +361,8 @@
474 last_slice_.reset();
475 ended_ = true;
476 current_touches_.clear();
477- unowned_touches_.clear();
478+ all_touches_.clear();
479+ LOG(Dbg) << "gesture " << id_ << " has ended\n";
480 }
481
482 /**
483@@ -417,5 +382,10 @@
484 }
485 }
486
487+Gesture::~Gesture()
488+{
489+ LOG(Dbg) << "deleting gesture " << id_ << "\n";
490+}
491+
492 } // namespace grail
493 } // namespace utouch
494
495=== modified file 'src/v3/gesture.h'
496--- src/v3/gesture.h 2012-03-26 12:57:55 +0000
497+++ src/v3/gesture.h 2012-03-27 17:29:32 +0000
498@@ -37,12 +37,13 @@
499 class Gesture : public std::enable_shared_from_this<Gesture> {
500 public:
501 Gesture(Recognizer* recognizer, UGSubscription* subscription,
502- TouchSet& touches, uint64_t start_time);
503- Gesture(const Gesture* gesture, TouchSet& touches);
504+ TouchMap& touches, uint64_t start_time);
505+ Gesture(const Gesture* gesture, TouchMap& touches);
506+ ~Gesture();
507
508- void AddTouch(UFTouchId touch_id);
509- void AddTouches(TouchSet touch_set);
510- bool ContainsTouch(UFTouchId touch_id) const;
511+ void AddTouch(const SharedTouch& touch);
512+ void AddTouches(TouchMap touches);
513+ bool ContainsTouch(const SharedTouch& touch) const;
514 void Update(UFEvent event, TouchSet& touches);
515 bool IsActive() const;
516 bool IsConstructionFinished() const;
517@@ -57,8 +58,8 @@
518 const unsigned int id() const { return id_; }
519 const Recognizer& recognizer() const { return *recognizer_; }
520 UGSubscription* subscription() const { return subscription_; }
521- const TouchSet& current_touches() const { return current_touches_; }
522- const TouchSet& all_touches() const { return all_touches_; }
523+ const TouchMap& current_touches() const { return current_touches_; }
524+ const TouchMap& all_touches() const { return all_touches_; }
525 const uint64_t start_time() const { return start_time_; }
526 bool canceled() const { return canceled_; }
527 bool ended() const { return ended_; }
528@@ -75,9 +76,8 @@
529 Recognizer* recognizer_;
530 unsigned int id_;
531 UGSubscription* subscription_;
532- TouchSet current_touches_; /**< Current touches of the gesture */
533- TouchSet unowned_touches_; /**< Current, unowned touches of the gesture */
534- TouchSet all_touches_; /**< All previous and current touches of the gesture */
535+ TouchMap current_touches_; /**< Current touches of the gesture */
536+ TouchMap all_touches_; /**< All previous and current touches of the gesture */
537 uint64_t start_time_;
538 bool owned_;
539 bool not_owned_;
540
541=== modified file 'src/v3/recognizer.cpp'
542--- src/v3/recognizer.cpp 2012-03-27 17:29:32 +0000
543+++ src/v3/recognizer.cpp 2012-03-27 17:29:32 +0000
544@@ -32,6 +32,7 @@
545 #include "v3/handle.h"
546 #include "v3/gesture.h"
547 #include "v3/log.h"
548+#include "v3/touch.h"
549
550 namespace utouch {
551 namespace grail {
552@@ -144,12 +145,10 @@
553 * @internal
554 * A helper function to get information from a touch frame
555 *
556- * This function retrieves a set of touches that have been modified, including
557- * touches that have ended. It also retrieves the set of touches that have ended
558- * separately.
559+ * This function retrieves a set of touches that have been modified.
560 */
561-void GetModifiedAndEndedTouches(UFFrame frame, TouchSet* modified,
562- TouchSet* ended, uint64_t event_time) {
563+void GetModifiedTouches(UFFrame frame, TouchSet* modified,
564+ uint64_t event_time) {
565 unsigned int num_touches = frame_frame_get_num_touches(frame);
566 for (unsigned int i = 0; i < num_touches; ++i) {
567 UFTouch touch;
568@@ -165,24 +164,6 @@
569 UFTouchId touch_id = frame_touch_get_id(touch);
570
571 modified->insert(touch_id);
572-
573- if (frame_touch_get_state(touch) == UFTouchStateEnd) {
574- ended->insert(touch_id);
575- LOG(Dbg) << "touch " << touch_id << " ended\n";
576- } else {
577- int pending_end_value;
578- status = frame_touch_get_property(touch, UFTouchPropertyPendingEnd,
579- &pending_end_value);
580- if (status != UFStatusSuccess) {
581- LOG(Warn) << "failed to get touch pending end property\n";
582- continue;
583- }
584-
585- if (pending_end_value) {
586- ended->insert(touch_id);
587- LOG(Dbg) << "touch " << touch_id << " is pending end\n";
588- }
589- }
590 }
591 }
592 }
593@@ -203,9 +184,7 @@
594 }
595
596 TouchSet modified_touches;
597- TouchSet ended_touches;
598- GetModifiedAndEndedTouches(frame, &modified_touches,
599- &ended_touches, frame_event_get_time(event));
600+ GetModifiedTouches(frame, &modified_touches, frame_event_get_time(event));
601
602 /* For each accepted gesture, update its state */
603 for (auto it = accepted_gestures_.begin(); it != accepted_gestures_.end(); ) {
604@@ -213,8 +192,12 @@
605 gesture->Update(event, modified_touches);
606 if (gesture->ended()) {
607 /* Allow touches of an ended gesture to be part of a new gesture */
608- for (UFTouchId touch_id : gesture->current_touches())
609- INSERT_TOUCH(touch_id, free_touches_);
610+ for (const auto& pair : gesture->current_touches()) {
611+ const SharedTouch& touch = pair.second;
612+
613+ if (!touch->pending_end() && !touch->ended())
614+ INSERT_TOUCH(touch, free_touches_);
615+ }
616
617 LOG(Dbg) << "gesture " << gesture->id()
618 << " has been erased from accepted gestures\n";
619@@ -235,27 +218,13 @@
620 }
621 }
622
623- /* For each ended touch, reject it if it is unaccepted and is not part of any
624- * remaining gesture */
625- for (UFTouchId touch_id : ended_touches) {
626- for (const SharedGesture& gesture : unaccepted_gestures_)
627- if (gesture->all_touches().find(touch_id) != gesture->all_touches().end())
628- goto next_touch;
629-
630- if (unaccepted_touches_.find(touch_id) != unaccepted_touches_.end()) {
631- if (frame_x11_reject_touch(device_, window_id_, touch_id) !=
632- UFStatusSuccess)
633- LOG(Err) << "touch " << touch_id << " failed to be rejected\n";
634- LOG(Dbg) << "touch " << touch_id
635- << " has been rejected because it has ended and is not part of "
636- "a gesture\n";
637- ERASE_TOUCH(touch_id, unaccepted_touches_);
638- }
639-
640- ERASE_TOUCH(touch_id, free_touches_);
641- start_times_.erase(touch_id);
642-
643-next_touch: ;
644+ /* Delete all ended touches */
645+ for (auto it = all_touches_.begin(); it != all_touches_.end(); ) {
646+ const auto& pair = *it++;
647+ const SharedTouch& touch = pair.second;
648+
649+ if (touch->ended())
650+ all_touches_.erase(touch->id());
651 }
652 }
653
654@@ -277,15 +246,17 @@
655 if (!gesture->IsActive() || gesture->IsConstructionFinished())
656 continue;
657
658- for (UFTouchId touch_id : gesture->current_touches()) {
659- if (time - start_times_[touch_id] < COMPOSITION_TIME)
660+ for (const auto& pair : gesture->current_touches()) {
661+ const SharedTouch& touch = pair.second;
662+
663+ if (time - touch->start_time() < COMPOSITION_TIME)
664 goto next_gesture;
665
666 for (const SharedGesture& other_gesture : unaccepted_gestures_) {
667 if (other_gesture == gesture)
668 continue;
669
670- if (other_gesture->current_touches().find(touch_id) !=
671+ if (other_gesture->current_touches().find(touch->id()) !=
672 other_gesture->current_touches().end() &&
673 !other_gesture->IsActive())
674 goto next_gesture;
675@@ -322,30 +293,20 @@
676 }
677 }
678
679- /* Reject unaccepted touches that are older than the composition time and are
680- * not part of any potential gesture */
681- for (auto it = unaccepted_touches_.begin();
682- it != unaccepted_touches_.end();
683- ) {
684- UFTouchId touch_id = *it++;
685- if (time - start_times_[touch_id] < COMPOSITION_TIME)
686+ /* Remove touches older than the gesture composition time from free_touches_
687+ */
688+ for (auto it = free_touches_.begin(); it != free_touches_.end(); ) {
689+ const auto& pair = *it++;
690+ const SharedTouch& touch = pair.second;
691+
692+ if (time - touch->start_time() < COMPOSITION_TIME)
693 continue;
694
695- for (const SharedGesture& gesture : unaccepted_gestures_)
696- if (gesture->all_touches().find(touch_id) != gesture->all_touches().end())
697- goto next_touch;
698-
699- if (frame_x11_reject_touch(device_, window_id_, touch_id) !=
700- UFStatusSuccess)
701- LOG(Err) << "touch " << touch_id << " failed to be rejected\n";
702- LOG(Dbg) << "touch " << touch_id
703- << " has been rejected because it has timed out and is not part "
704- "of any gesture (time: " << time << ", touch start time: "
705- << start_times_[touch_id] << ")\n";
706- ERASE_TOUCH(touch_id, unaccepted_touches_);
707- ERASE_TOUCH(touch_id, free_touches_);
708-
709-next_touch: ;
710+ LOG(Dbg) << "touch " << touch->id()
711+ << " has been removed from free_touches_ because it is older than "
712+ "the gesture composition time (time: " << time
713+ << ", touch start time: " << touch->start_time() << ")\n";
714+ ERASE_TOUCH(touch->id(), free_touches_);
715 }
716
717 CheckConstructionFinished(time);
718@@ -359,13 +320,16 @@
719 /* Find the minimum timeout of each unaccepted touch that is not part of a
720 * gesture */
721 uint64_t min_timeout = std::numeric_limits<uint64_t>::max();
722- for (UFTouchId touch_id : unaccepted_touches_) {
723+ for (const auto& pair : free_touches_) {
724+ const SharedTouch& touch = pair.second;
725+
726 for (const SharedGesture& gesture : unaccepted_gestures_)
727- if (gesture->all_touches().find(touch_id) != gesture->all_touches().end())
728+ if (gesture->all_touches().find(touch->id()) !=
729+ gesture->all_touches().end())
730 goto next_touch;
731
732- if (COMPOSITION_TIME + start_times_[touch_id] < min_timeout)
733- min_timeout = start_times_[touch_id] + COMPOSITION_TIME;
734+ if (COMPOSITION_TIME + touch->start_time() < min_timeout)
735+ min_timeout = touch->start_time() + COMPOSITION_TIME;
736
737 next_touch: ;
738 }
739@@ -405,17 +369,14 @@
740 LOG(Dbg) << "gesture " << gesture->id() << " has been accepted by the "
741 "client\n";
742
743- for (UFTouchId touch_id : gesture->all_touches()) {
744- if (accepted_touches_.find(touch_id) == accepted_touches_.end()) {
745- /* Accept each unaccepted touch in the gesture */
746- if (frame_x11_accept_touch(device_, window_id_, touch_id) !=
747- UFStatusSuccess)
748- LOG(Err) << "touch " << touch_id << " failed to be accepted\n";
749- LOG(Dbg) << "touch " << touch_id
750+ for (const auto& pair : gesture->all_touches()) {
751+ const SharedTouch& touch = pair.second;
752+
753+ if (!touch->accepted()) {
754+ touch->Accept();
755+ LOG(Dbg) << "touch " << touch->id()
756 << " has been accepted because it is part of an accepted "
757 "gesture\n";
758- INSERT_TOUCH(touch_id, accepted_touches_);
759- ERASE_TOUCH(touch_id, unaccepted_touches_);
760 } else {
761 /* This gesture may be an extension to more touches of an accepted
762 * gesture. Cancel the old gesture and remove any gesture events for it
763@@ -426,10 +387,10 @@
764 it != accepted_gestures_.end();
765 ) {
766 const SharedGesture& other_gesture = *it++;
767- const TouchSet& other_touches = other_gesture->current_touches();
768- if (other_touches.find(touch_id) != other_touches.end()) {
769+ const TouchMap& other_touches = other_gesture->current_touches();
770+ if (other_touches.find(touch->id()) != other_touches.end()) {
771 LOG(Dbg) << "cancelling gesture " << other_gesture->id()
772- << " because it has a touch (" << touch_id << ") "
773+ << " because it has a touch (" << touch->id() << ") "
774 << "that is part of a new accepted gesture\n";
775 other_gesture->Cancel();
776 handle_->RemoveGestureFromEventQueue(other_gesture->id());
777@@ -443,7 +404,7 @@
778
779 /* Remove this touch from the free touches set, it can't be used for new
780 * gestures while it is part of an accepted gesture */
781- ERASE_TOUCH(touch_id, free_touches_);
782+ ERASE_TOUCH(touch->id(), free_touches_);
783 }
784
785 /* Reject any overlapping unaccepted gestures. Atomic subscriptions may have
786@@ -455,11 +416,14 @@
787 const SharedGesture& other_gesture = *it++;
788 if (other_gesture == gesture)
789 continue;
790- for (UFTouchId touch_id : other_gesture->all_touches()) {
791- if (gesture->all_touches().find(touch_id) !=
792+
793+ for (const auto& pair : other_gesture->all_touches()) {
794+ const SharedTouch& touch = pair.second;
795+
796+ if (gesture->all_touches().find(touch->id()) !=
797 gesture->all_touches().end()) {
798 LOG(Dbg) << "rejecting gesture " << other_gesture->id()
799- << "because it has a touch (" << touch_id
800+ << "because it has a touch (" << touch->id()
801 << ") that is part of an accepted gesture\n";
802 RejectGesture(other_gesture);
803 break;
804
805=== modified file 'src/v3/recognizer.h'
806--- src/v3/recognizer.h 2012-03-26 16:08:56 +0000
807+++ src/v3/recognizer.h 2012-03-27 17:29:32 +0000
808@@ -32,27 +32,27 @@
809 #include "v3/forward.h"
810 #include "v3/subscription.h"
811
812-#define INSERT_TOUCH(element, set) \
813+#define INSERT_TOUCH(touch, map) \
814 { \
815- (set).insert(element); \
816- LOG(Dbg) << "touch " << element << " has been added to " #set "\n"; \
817+ (map)[(touch)->id()] = (touch); \
818+ LOG(Dbg) << "touch " << (touch)->id() << " has been added to " #map "\n"; \
819 }
820
821-#define ERASE_TOUCH(element, set) \
822+#define ERASE_TOUCH(touch_id, map) \
823 { \
824- (set).erase(element); \
825- LOG(Dbg) << "touch " << element << " has been erased from " #set "\n"; \
826+ LOG(Dbg) << "touch " << touch_id << " has been erased from " #map "\n"; \
827+ (map).erase(touch_id); \
828 }
829
830 /* OBS: it avoids the "expensive" ToString() call when debug output is not
831 wanted. */
832-#define CLEAR_TOUCHES(set) \
833+#define CLEAR_TOUCHES(map) \
834 { \
835 if (utouch::grail::Logger::instance().level() <= utouch::grail::Logger::Dbg) \
836- if ((set).size() > 0) \
837- LOG(Dbg) << "touch(es) " << (set).ToString() \
838- << " have been erased from " #set "\n"; \
839- (set).clear(); \
840+ if ((map).size() > 0) \
841+ LOG(Dbg) << "touch(es) " << (map).ToString() \
842+ << " have been erased from " #map "\n"; \
843+ (map).clear(); \
844 }
845
846 namespace utouch {
847@@ -76,6 +76,8 @@
848 UGStatus RejectGesture(unsigned int id);
849
850 UGHandle* handle() const { return handle_; }
851+ UFDevice device() const { return device_; }
852+ UFWindowId window_id() const { return window_id_; }
853 float device_x_res() const { return device_x_res_; }
854 float device_y_res() const { return device_y_res_; }
855 bool device_direct() const { return device_direct_; }
856@@ -96,10 +98,8 @@
857 std::set<UGSubscription*> subscriptions_[5];
858 std::set<SharedGesture> unaccepted_gestures_;
859 std::set<SharedGesture> accepted_gestures_;
860- std::map<UFTouchId, uint64_t> start_times_;
861- TouchSet unaccepted_touches_;
862- TouchSet accepted_touches_;
863- TouchSet free_touches_;
864+ TouchMap free_touches_;
865+ TouchMap all_touches_;
866
867 unsigned int num_subscriptions_;
868
869
870=== modified file 'src/v3/regular-recognizer.cpp'
871--- src/v3/regular-recognizer.cpp 2012-03-27 17:29:32 +0000
872+++ src/v3/regular-recognizer.cpp 2012-03-27 17:29:32 +0000
873@@ -32,6 +32,7 @@
874 #include "v3/handle.h"
875 #include "v3/gesture.h"
876 #include "v3/log.h"
877+#include "v3/touch.h"
878
879 namespace utouch {
880 namespace grail {
881@@ -53,19 +54,21 @@
882 LOG(Dbg) << "new event " << event << " with time "
883 << frame_event_get_time(event) << "\n";
884 UpdateTime(frame_event_get_time(event));
885- MatchSubscriptionsForEvent(event);
886+ ProcessTouches(event);
887 ProcessEvent(event);
888 }
889
890 /**
891 * @internal
892- * Analyze a uTouch-Frame event to see if any new gestures should begin
893+ * Process all touches present in the given uTouch-Frame event.
894+ *
895+ * Add new touches to new_touches_ and free_touches_ maps, update the grail
896+ * touch state for existing touches, and remove touches from maps when they
897+ * physically end.
898+ *
899+ * When a touch begins, attempt to match it to all gesture subscriptions.
900 */
901-void RegularRecognizer::MatchSubscriptionsForEvent(const UFEvent event) {
902- /* Check if any subscriptions are active before doing any processing */
903- if (num_subscriptions_ == 0)
904- return;
905-
906+void RegularRecognizer::ProcessTouches(const UFEvent event) {
907 UFFrame frame;
908 UFStatus status = frame_event_get_property(event, UFEventPropertyFrame,
909 &frame);
910@@ -84,43 +87,57 @@
911 continue;
912 }
913
914- if (frame_touch_get_state(touch) != UFTouchStateBegin)
915- continue;
916-
917- UFTouchId touch_id = frame_touch_get_id(touch);
918-
919- /* Note touch start time and add to initial touch lists */
920- start_times_[touch_id] = frame_touch_get_start_time(touch);
921- LOG(Dbg) << "touch " << touch_id << " began with start time "
922- << start_times_[touch_id] << "\n";
923-
924- INSERT_TOUCH(touch_id, unaccepted_touches_);
925- INSERT_TOUCH(touch_id, free_touches_);
926-
927- /* HandleNewTouchForAcceptedGesture may erase the gesture from
928- * accepted_gestures_, so we can't use range-based for loops */
929- for (auto it = accepted_gestures_.begin();
930- it != accepted_gestures_.end();
931- ) {
932- const SharedGesture& gesture = *it++;
933- HandleNewTouchForAcceptedGesture(touch_id, gesture);
934- }
935-
936- /* HandleNewTouchForAcceptedGesture may erase the gesture from
937- * accepted_gestures_, so we can't use range-based for loops */
938- for (auto it = unaccepted_gestures_.begin();
939- it != unaccepted_gestures_.end();
940- ) {
941- const SharedGesture& gesture = *it++;
942- HandleNewTouchForUnacceptedGesture(touch_id, gesture);
943- }
944-
945- /* Attempt to match new gestures for active subscriptions */
946- MatchOneTouchGestures(touch_id);
947- MatchTwoTouchGestures(touch_id);
948- MatchThreeTouchGestures(touch_id);
949- MatchFourTouchGestures(touch_id);
950- MatchFiveTouchGestures(touch_id);
951+ switch (frame_touch_get_state(touch)) {
952+ case UFTouchStateBegin: {
953+ SharedTouch grail_touch(new Touch(touch, device_, window_id_));
954+
955+ LOG(Dbg) << "touch " << grail_touch->id() << " began with start time "
956+ << grail_touch->start_time() << "\n";
957+
958+ INSERT_TOUCH(grail_touch, all_touches_);
959+ INSERT_TOUCH(grail_touch, free_touches_);
960+
961+ /* HandleNewTouchForAcceptedGesture may erase the gesture from
962+ * accepted_gestures_, so we can't use range-based for loops */
963+ for (auto it = accepted_gestures_.begin();
964+ it != accepted_gestures_.end();
965+ ) {
966+ const SharedGesture& gesture = *it++;
967+ HandleNewTouchForAcceptedGesture(grail_touch, gesture);
968+ }
969+
970+ /* HandleNewTouchForUnacceptedGesture may erase the gesture from
971+ * accepted_gestures_, so we can't use range-based for loops */
972+ for (auto it = unaccepted_gestures_.begin();
973+ it != unaccepted_gestures_.end();
974+ ) {
975+ const SharedGesture& gesture = *it++;
976+ HandleNewTouchForUnacceptedGesture(grail_touch, gesture);
977+ }
978+
979+ /* Attempt to match new gestures for active subscriptions */
980+ MatchOneTouchGestures(grail_touch);
981+ MatchTwoTouchGestures(grail_touch);
982+ MatchThreeTouchGestures(grail_touch);
983+ MatchFourTouchGestures(grail_touch);
984+ MatchFiveTouchGestures(grail_touch);
985+ break;
986+ }
987+
988+ case UFTouchStateUpdate:
989+ case UFTouchStateEnd: {
990+ auto it = all_touches_.find(frame_touch_get_id(touch));
991+ if (it != all_touches_.end()) {
992+ const SharedTouch& grail_touch = it->second;
993+
994+ grail_touch->Update(touch);
995+
996+ if (grail_touch->pending_end() || grail_touch->ended())
997+ ERASE_TOUCH(grail_touch->id(), free_touches_);
998+ }
999+ break;
1000+ }
1001+ }
1002 }
1003 }
1004
1005@@ -134,16 +151,16 @@
1006 * Otherwise, do nothing. New gestures may still begin elsewhere.
1007 */
1008 void RegularRecognizer::HandleNewTouchForAcceptedGesture(
1009- UFTouchId touch_id,
1010+ const SharedTouch& touch,
1011 const SharedGesture& gesture) {
1012 UGSubscription* subscription = gesture->subscription();
1013 if (gesture->current_touches().size() < subscription->touches_max()
1014- && !gesture->ContainsTouch(touch_id)) {
1015- TouchSet set(gesture->current_touches());
1016- set.insert(touch_id);
1017- Gesture* new_gesture = new Gesture(gesture.get(), set);
1018- LOG(Dbg) << "touch " << touch_id << " has been added to accepted gesture "
1019- << gesture->id() << " to create new gesture "
1020+ && !gesture->ContainsTouch(touch)) {
1021+ TouchMap map(gesture->current_touches());
1022+ map[touch->id()] = touch;
1023+ Gesture* new_gesture = new Gesture(gesture.get(), map);
1024+ LOG(Dbg) << "touch " << touch->id() << " has been added to accepted "
1025+ << "gesture " << gesture->id() << " to create new gesture "
1026 << new_gesture->id() << "\n";
1027 unaccepted_gestures_.insert(SharedGesture(new_gesture));
1028 LOG(Dbg) << "gesture " << new_gesture
1029@@ -161,15 +178,15 @@
1030 * Otherwise, do nothing. New gestures may still begin elsewhere.
1031 */
1032 void RegularRecognizer::HandleNewTouchForUnacceptedGesture(
1033- UFTouchId touch_id,
1034+ const SharedTouch& touch,
1035 const SharedGesture& gesture) {
1036 UGSubscription* subscription = gesture->subscription();
1037 if (gesture->current_touches().size() < subscription->touches_max()
1038- && !gesture->ContainsTouch(touch_id)) {
1039- TouchSet set(gesture->current_touches());
1040- set.insert(touch_id);
1041- Gesture* new_gesture = new Gesture(gesture.get(), set);
1042- LOG(Dbg) << "touch " << touch_id
1043+ && !gesture->ContainsTouch(touch)) {
1044+ TouchMap map(gesture->current_touches());
1045+ map[touch->id()] = touch;
1046+ Gesture* new_gesture = new Gesture(gesture.get(), map);
1047+ LOG(Dbg) << "touch " << touch->id()
1048 << " has been added to unaccepted gesture " << gesture->id()
1049 << " to create new gesture " << new_gesture->id() << "\n";
1050 unaccepted_gestures_.insert(SharedGesture(new_gesture));
1051@@ -182,17 +199,17 @@
1052 * @internal
1053 * Attempt to match the given touch against one touch subscriptions
1054 */
1055-void RegularRecognizer::MatchOneTouchGestures(UFTouchId touch_id) {
1056+void RegularRecognizer::MatchOneTouchGestures(const SharedTouch& touch) {
1057 for (UGSubscription* subscription : subscriptions_[0]) {
1058- TouchSet set;
1059- set.insert(touch_id);
1060- Gesture* gesture = new Gesture(this, subscription, set,
1061- start_times_[touch_id]);
1062+ TouchMap map;
1063+ map[touch->id()] = touch;
1064+ Gesture* gesture = new Gesture(this, subscription, map,
1065+ touch->start_time());
1066 unaccepted_gestures_.insert(SharedGesture(gesture));
1067
1068 LOG(Dbg) << "New tentative gesture " << gesture->id()
1069 << " matched subscription " << subscription << " with mask "
1070- << subscription->mask() << " for touch " << touch_id << "\n";
1071+ << subscription->mask() << " for touch " << touch->id() << "\n";
1072 }
1073 }
1074
1075@@ -200,30 +217,30 @@
1076 * @internal
1077 * Attempt to match the given touch against two touch subscriptions
1078 */
1079-void RegularRecognizer::MatchTwoTouchGestures(UFTouchId touch_id) {
1080+void RegularRecognizer::MatchTwoTouchGestures(const SharedTouch& touch) {
1081 for (UGSubscription* subscription : subscriptions_[1]) {
1082- for (UFTouchId other_id : free_touches_) {
1083- if (other_id == touch_id)
1084+ for (const auto& pair : free_touches_) {
1085+ const SharedTouch& other = pair.second;
1086+ if (other->id() == touch->id())
1087 continue;
1088
1089 /* All touches in a gesture must begin within a composition timeframe */
1090- uint64_t min_start_time = start_times_[touch_id];
1091- if (start_times_[other_id] < min_start_time &&
1092- unaccepted_touches_.find(other_id) != unaccepted_touches_.end())
1093- min_start_time = start_times_[other_id];
1094+ uint64_t min_start_time = touch->start_time();
1095+ if (other->start_time() < min_start_time && !other->accepted())
1096+ min_start_time = other->start_time();
1097
1098- if (start_times_[touch_id] - min_start_time < COMPOSITION_TIME) {
1099- TouchSet set;
1100- set.insert(touch_id);
1101- set.insert(other_id);
1102- Gesture* gesture = new Gesture(this, subscription, set,
1103- start_times_[touch_id]);
1104+ if (touch->start_time() - min_start_time < COMPOSITION_TIME) {
1105+ TouchMap map;
1106+ map[touch->id()] = touch;
1107+ map[other->id()] = other;
1108+ Gesture* gesture = new Gesture(this, subscription, map,
1109+ touch->start_time());
1110 unaccepted_gestures_.insert(SharedGesture(gesture));
1111
1112 LOG(Dbg) << "New tentative gesture " << gesture->id()
1113 << " matched subscription " << subscription << " with mask "
1114- << subscription->mask() << " for touches " << touch_id << ", "
1115- << other_id << "\n";
1116+ << subscription->mask() << " for touches " << touch->id()
1117+ << ", " << other->id() << "\n";
1118 }
1119 }
1120 }
1121@@ -233,38 +250,38 @@
1122 * @internal
1123 * Attempt to match the given touch against three touch subscriptions
1124 */
1125-void RegularRecognizer::MatchThreeTouchGestures(UFTouchId touch_id) {
1126+void RegularRecognizer::MatchThreeTouchGestures(const SharedTouch& touch) {
1127 for (UGSubscription* subscription : subscriptions_[2]) {
1128- for (UFTouchId other_id_1 : free_touches_) {
1129- if (other_id_1 == touch_id)
1130+ for (const auto& pair_1 : free_touches_) {
1131+ const SharedTouch& other_1 = pair_1.second;
1132+ if (other_1->id() == touch->id())
1133 continue;
1134
1135- for (UFTouchId other_id_2 : free_touches_) {
1136- if (other_id_2 <= other_id_1 || other_id_2 == touch_id)
1137+ for (const auto& pair_2 : free_touches_) {
1138+ const SharedTouch& other_2 = pair_2.second;
1139+ if (other_2->id() <= other_1->id() || other_2->id() == touch->id())
1140 continue;
1141
1142 /* All touches in a gesture must begin within a composition timeframe */
1143- uint64_t min_start_time = start_times_[touch_id];
1144- if (start_times_[other_id_1] < min_start_time &&
1145- unaccepted_touches_.find(other_id_1) != unaccepted_touches_.end())
1146- min_start_time = start_times_[other_id_1];
1147- if (start_times_[other_id_2] < min_start_time &&
1148- unaccepted_touches_.find(other_id_2) != unaccepted_touches_.end())
1149- min_start_time = start_times_[other_id_2];
1150+ uint64_t min_start_time = touch->start_time();
1151+ if (other_1->start_time() < min_start_time && !other_1->accepted())
1152+ min_start_time = other_1->start_time();
1153+ if (other_2->start_time() < min_start_time && !other_2->accepted())
1154+ min_start_time = other_2->start_time();
1155
1156- if (start_times_[touch_id] - min_start_time < COMPOSITION_TIME) {
1157- TouchSet set;
1158- set.insert(touch_id);
1159- set.insert(other_id_1);
1160- set.insert(other_id_2);
1161- Gesture* gesture = new Gesture(this, subscription, set,
1162- start_times_[touch_id]);
1163+ if (touch->start_time() - min_start_time < COMPOSITION_TIME) {
1164+ TouchMap map;
1165+ map[touch->id()] = touch;
1166+ map[other_1->id()] = other_1;
1167+ map[other_2->id()] = other_2;
1168+ Gesture* gesture = new Gesture(this, subscription, map,
1169+ touch->start_time());
1170 unaccepted_gestures_.insert(SharedGesture(gesture));
1171
1172 LOG(Dbg) << "New tentative gesture " << gesture->id()
1173 << " matched subscription " << subscription << " with mask "
1174- << subscription->mask() << " for touches " << touch_id
1175- << ", " << other_id_1 << ", " << other_id_2 << "\n";
1176+ << subscription->mask() << " for touches " << touch->id()
1177+ << ", " << other_1->id() << ", " << other_2->id() << "\n";
1178 }
1179 }
1180 }
1181@@ -275,48 +292,48 @@
1182 * @internal
1183 * Attempt to match the given touch against four touch subscriptions
1184 */
1185-void RegularRecognizer::MatchFourTouchGestures(UFTouchId touch_id) {
1186+void RegularRecognizer::MatchFourTouchGestures(const SharedTouch& touch) {
1187 for (UGSubscription* subscription : subscriptions_[3]) {
1188- for (UFTouchId other_id_1 : free_touches_) {
1189- if (other_id_1 == touch_id)
1190+ for (const auto& pair_1 : free_touches_) {
1191+ const SharedTouch& other_1 = pair_1.second;
1192+ if (other_1->id() == touch->id())
1193 continue;
1194
1195- for (UFTouchId other_id_2 : free_touches_) {
1196- if (other_id_2 <= other_id_1 || other_id_2 == touch_id)
1197+ for (const auto& pair_2 : free_touches_) {
1198+ const SharedTouch& other_2 = pair_2.second;
1199+ if (other_2->id() <= other_1->id() || other_2->id() == touch->id())
1200 continue;
1201
1202- for (UFTouchId other_id_3 : free_touches_) {
1203- if (other_id_3 <= other_id_2 || other_id_3 == touch_id)
1204+ for (const auto& pair_3 : free_touches_) {
1205+ const SharedTouch& other_3 = pair_3.second;
1206+ if (other_3->id() <= other_2->id() || other_3->id() == touch->id())
1207 continue;
1208
1209 /* All touches in a gesture must begin within a composition
1210 * timeframe */
1211- uint64_t min_start_time = start_times_[touch_id];
1212- if (start_times_[other_id_1] < min_start_time &&
1213- unaccepted_touches_.find(other_id_1) != unaccepted_touches_.end())
1214- min_start_time = start_times_[other_id_1];
1215- if (start_times_[other_id_2] < min_start_time &&
1216- unaccepted_touches_.find(other_id_2) != unaccepted_touches_.end())
1217- min_start_time = start_times_[other_id_2];
1218- if (start_times_[other_id_3] < min_start_time &&
1219- unaccepted_touches_.find(other_id_3) != unaccepted_touches_.end())
1220- min_start_time = start_times_[other_id_3];
1221+ uint64_t min_start_time = touch->start_time();
1222+ if (other_1->start_time() < min_start_time && !other_1->accepted())
1223+ min_start_time = other_1->start_time();
1224+ if (other_2->start_time() < min_start_time && !other_2->accepted())
1225+ min_start_time = other_2->start_time();
1226+ if (other_3->start_time() < min_start_time && !other_3->accepted())
1227+ min_start_time = other_3->start_time();
1228
1229- if (start_times_[touch_id] - min_start_time < COMPOSITION_TIME) {
1230- TouchSet set;
1231- set.insert(touch_id);
1232- set.insert(other_id_1);
1233- set.insert(other_id_2);
1234- set.insert(other_id_3);
1235- Gesture* gesture = new Gesture(this, subscription, set,
1236- start_times_[touch_id]);
1237+ if (touch->start_time() - min_start_time < COMPOSITION_TIME) {
1238+ TouchMap map;
1239+ map[touch->id()] = touch;
1240+ map[other_1->id()] = other_1;
1241+ map[other_2->id()] = other_2;
1242+ map[other_3->id()] = other_3;
1243+ Gesture* gesture = new Gesture(this, subscription, map,
1244+ touch->start_time());
1245 unaccepted_gestures_.insert(SharedGesture(gesture));
1246
1247 LOG(Dbg) << "New tentative gesture " << gesture->id()
1248 << " matched subscription " << subscription
1249 << " with mask " << subscription->mask() << " for touches "
1250- << touch_id << ", " << other_id_1 << ", " << other_id_2
1251- << ", " << other_id_3 << "\n";
1252+ << touch->id() << ", " << other_1->id() << ", "
1253+ << other_2->id() << ", " << other_3->id() << "\n";
1254 }
1255 }
1256 }
1257@@ -328,61 +345,57 @@
1258 * @internal
1259 * Attempt to match the given touch against five touch subscriptions
1260 */
1261-void RegularRecognizer::MatchFiveTouchGestures(UFTouchId touch_id) {
1262+void RegularRecognizer::MatchFiveTouchGestures(const SharedTouch& touch) {
1263 for (UGSubscription* subscription : subscriptions_[4]) {
1264- for (UFTouchId other_id_1 : free_touches_) {
1265- if (other_id_1 == touch_id)
1266+ for (const auto& pair_1 : free_touches_) {
1267+ const SharedTouch& other_1 = pair_1.second;
1268+ if (other_1->id() == touch->id())
1269 continue;
1270
1271- for (UFTouchId other_id_2 : free_touches_) {
1272- if (other_id_2 <= other_id_1 || other_id_2 == touch_id)
1273+ for (const auto& pair_2 : free_touches_) {
1274+ const SharedTouch& other_2 = pair_2.second;
1275+ if (other_2->id() <= other_1->id() || other_2->id() == touch->id())
1276 continue;
1277
1278- for (UFTouchId other_id_3 : free_touches_) {
1279- if (other_id_3 <= other_id_2 || other_id_3 == touch_id)
1280+ for (const auto& pair_3 : free_touches_) {
1281+ const SharedTouch& other_3 = pair_3.second;
1282+ if (other_3->id() <= other_2->id() || other_3->id() == touch->id())
1283 continue;
1284
1285- for (UFTouchId other_id_4 : free_touches_) {
1286- if (other_id_4 <= other_id_3 || other_id_4 == touch_id)
1287+ for (const auto& pair_4 : free_touches_) {
1288+ const SharedTouch& other_4 = pair_4.second;
1289+ if (other_4->id() <= other_3->id() || other_4->id() == touch->id())
1290 continue;
1291
1292 /* All touches in a gesture must begin within a composition
1293 * timeframe */
1294- uint64_t min_start_time = start_times_[touch_id];
1295- if (start_times_[other_id_1] < min_start_time &&
1296- unaccepted_touches_.find(other_id_1) !=
1297- unaccepted_touches_.end())
1298- min_start_time = start_times_[other_id_1];
1299- if (start_times_[other_id_2] < min_start_time &&
1300- unaccepted_touches_.find(other_id_2) !=
1301- unaccepted_touches_.end())
1302- min_start_time = start_times_[other_id_2];
1303- if (start_times_[other_id_3] < min_start_time &&
1304- unaccepted_touches_.find(other_id_3) !=
1305- unaccepted_touches_.end())
1306- min_start_time = start_times_[other_id_3];
1307- if (start_times_[other_id_4] < min_start_time &&
1308- unaccepted_touches_.find(other_id_4) !=
1309- unaccepted_touches_.end())
1310- min_start_time = start_times_[other_id_4];
1311+ uint64_t min_start_time = touch->start_time();
1312+ if (other_1->start_time() < min_start_time && !other_1->accepted())
1313+ min_start_time = other_1->start_time();
1314+ if (other_2->start_time() < min_start_time && !other_2->accepted())
1315+ min_start_time = other_2->start_time();
1316+ if (other_3->start_time() < min_start_time && !other_3->accepted())
1317+ min_start_time = other_3->start_time();
1318+ if (other_4->start_time() < min_start_time && !other_4->accepted())
1319+ min_start_time = other_4->start_time();
1320
1321- if (start_times_[touch_id] - min_start_time < COMPOSITION_TIME) {
1322- TouchSet set;
1323- set.insert(touch_id);
1324- set.insert(other_id_1);
1325- set.insert(other_id_2);
1326- set.insert(other_id_3);
1327- set.insert(other_id_4);
1328- Gesture* gesture = new Gesture(this, subscription, set,
1329- start_times_[touch_id]);
1330+ if (touch->start_time() - min_start_time < COMPOSITION_TIME) {
1331+ TouchMap map;
1332+ map[touch->id()] = touch;
1333+ map[other_1->id()] = other_1;
1334+ map[other_2->id()] = other_2;
1335+ map[other_3->id()] = other_3;
1336+ map[other_4->id()] = other_4;
1337+ Gesture* gesture = new Gesture(this, subscription, map,
1338+ touch->start_time());
1339 unaccepted_gestures_.insert(SharedGesture(gesture));
1340
1341 LOG(Dbg) << "New tentative gesture " << gesture->id()
1342 << " matched subscription " << subscription
1343 << " with mask " << subscription->mask()
1344- << " for touches " << touch_id << ", " << other_id_1
1345- << ", " << other_id_2 << ", " << other_id_3 << ", "
1346- << other_id_4 << "\n";
1347+ << " for touches " << touch->id() << ", "
1348+ << other_1->id() << ", " << other_2->id() << ", "
1349+ << other_3->id() << ", " << other_4->id() << "\n";
1350 }
1351 }
1352 }
1353
1354=== modified file 'src/v3/regular-recognizer.h'
1355--- src/v3/regular-recognizer.h 2012-03-26 12:57:55 +0000
1356+++ src/v3/regular-recognizer.h 2012-03-27 17:29:32 +0000
1357@@ -34,16 +34,16 @@
1358 virtual void ProcessFrameEvent(const UFEvent event);
1359
1360 private:
1361- void HandleNewTouchForAcceptedGesture(UFTouchId touch_id,
1362+ void HandleNewTouchForAcceptedGesture(const SharedTouch& touch,
1363 const SharedGesture& gesture);
1364- void HandleNewTouchForUnacceptedGesture(UFTouchId touch_id,
1365+ void HandleNewTouchForUnacceptedGesture(const SharedTouch& touch,
1366 const SharedGesture& gesture);
1367- void MatchSubscriptionsForEvent(const UFEvent event);
1368- void MatchOneTouchGestures(UFTouchId touch_id);
1369- void MatchTwoTouchGestures(UFTouchId touch_id);
1370- void MatchThreeTouchGestures(UFTouchId touch_id);
1371- void MatchFourTouchGestures(UFTouchId touch_id);
1372- void MatchFiveTouchGestures(UFTouchId touch_id);
1373+ void ProcessTouches(const UFEvent event);
1374+ void MatchOneTouchGestures(const SharedTouch& touch);
1375+ void MatchTwoTouchGestures(const SharedTouch& touch);
1376+ void MatchThreeTouchGestures(const SharedTouch& touch);
1377+ void MatchFourTouchGestures(const SharedTouch& touch);
1378+ void MatchFiveTouchGestures(const SharedTouch& touch);
1379 };
1380
1381 } // namespace grail
1382
1383=== modified file 'src/v3/slice.cpp'
1384--- src/v3/slice.cpp 2012-03-26 13:28:53 +0000
1385+++ src/v3/slice.cpp 2012-03-27 17:29:32 +0000
1386@@ -32,6 +32,7 @@
1387 #include "v3/log.h"
1388 #include "v3/recognizer.h"
1389 #include "v3/subscription.h"
1390+#include "v3/touch.h"
1391
1392 namespace {
1393
1394@@ -47,7 +48,7 @@
1395 * Create a gesture begin slice
1396 */
1397 UGSlice::UGSlice(Gesture& gesture, UFEvent event,
1398- const TouchSet& touches, UGGestureTypeMask recognized)
1399+ const TouchMap& touches, UGGestureTypeMask recognized)
1400 : id_(gesture.id()),
1401 event_(event),
1402 frame_(NULL),
1403@@ -128,7 +129,7 @@
1404 * Create a gesture update or end slice based on new touch frame
1405 */
1406 UGSlice::UGSlice(const SharedUGSlice& prev, Gesture &gesture,
1407- UFEvent event, const TouchSet& touches)
1408+ UFEvent event, const TouchMap& touches)
1409 : id_(prev->id_),
1410 event_(event ? : NULL),
1411 frame_(NULL),
1412@@ -189,16 +190,19 @@
1413 * @internal
1414 * Get gesture slice transformation properties
1415 */
1416-void UGSlice::GetValues(Gesture &gesture, const TouchSet& touches,
1417+void UGSlice::GetValues(Gesture &gesture, const TouchMap& touches,
1418 float* x, float* y, float* radius, float* angle,
1419 bool init) {
1420 *x = 0;
1421 *y = 0;
1422
1423 /* Accumulate X and Y positions */
1424- for (UFTouchId touch_id : touches) {
1425+ for (const auto& pair : touches) {
1426+ const SharedTouch& grail_touch = pair.second;
1427+
1428 UFTouch touch;
1429- UFStatus status = frame_frame_get_touch_by_id(frame_, touch_id, &touch);
1430+ UFStatus status = frame_frame_get_touch_by_id(frame_, grail_touch->id(),
1431+ &touch);
1432 if (status != UFStatusSuccess) {
1433 LOG(Warn) << "failed to get touch from frame\n";
1434 continue;
1435@@ -224,12 +228,15 @@
1436 *radius = 0;
1437 *angle = 0;
1438 int num_angles = 0;
1439- for (UFTouchId touch_id : touches) {
1440+ for (const auto& pair : touches) {
1441+ const SharedTouch& grail_touch = pair.second;
1442+
1443 UFTouch touch;
1444 float cur_x;
1445 float cur_y;
1446
1447- UFStatus status = frame_frame_get_touch_by_id(frame_, touch_id, &touch);
1448+ UFStatus status = frame_frame_get_touch_by_id(frame_, grail_touch->id(),
1449+ &touch);
1450 if (status != UFStatusSuccess) {
1451 LOG(Warn) << "failed to get touch from frame\n";
1452 continue;
1453@@ -257,7 +264,7 @@
1454 num_angles++;
1455 } else if (frame_touch_get_state(touch) != UFTouchStateBegin) {
1456 /* Update touch angle if the touch has moved */
1457- float prev_angle = gesture.AngleForTouch(touch_id);
1458+ float prev_angle = gesture.AngleForTouch(grail_touch->id());
1459
1460 if (new_angle - prev_angle < -M_PI)
1461 new_angle += 2 * M_PI;
1462@@ -269,7 +276,7 @@
1463 }
1464
1465 /* Save the touch angle in the gesture state */
1466- gesture.SetAngleForTouch(touch_id, new_angle);
1467+ gesture.SetAngleForTouch(grail_touch->id(), new_angle);
1468 }
1469
1470 /* Calculate the average angle of the touches */
1471@@ -390,30 +397,11 @@
1472 void UGSlice::CheckGestureEnd() {
1473 /* Get number of physically non-ended touches */
1474 unsigned int num_active_touches = 0;
1475- for (UFTouchId touch_id : touches_) {
1476- UFTouch touch;
1477- UFStatus status = frame_frame_get_touch_by_id(frame_, touch_id, &touch);
1478- if (status != UFStatusSuccess) {
1479- LOG(Warn) << "failed to get touch from frame by id\n";
1480- continue;
1481- }
1482-
1483- if (frame_touch_get_state(touch) == UFTouchStateEnd) {
1484- continue;
1485- } else {
1486- int pending_end;
1487- status = frame_touch_get_property(touch, UFTouchPropertyPendingEnd,
1488- &pending_end);
1489- if (status != UFStatusSuccess) {
1490- LOG(Warn) << "failed to get touch pending end property\n";
1491- continue;
1492- }
1493-
1494- if (pending_end)
1495- continue;
1496- }
1497-
1498- num_active_touches++;
1499+ for (const auto& pair : touches_) {
1500+ const SharedTouch& touch = pair.second;
1501+
1502+ if (!touch->pending_end() && !touch->ended())
1503+ num_active_touches++;
1504 }
1505
1506 /* Check if currently active touches is outside range for subscription */
1507@@ -497,7 +485,7 @@
1508 auto it = touches_.cbegin();
1509 std::advance(it, index);
1510
1511- *touch_id = *it;
1512+ *touch_id = it->first;
1513
1514 return UGStatusSuccess;
1515 }
1516
1517=== modified file 'src/v3/slice.h'
1518--- src/v3/slice.h 2012-03-26 13:28:53 +0000
1519+++ src/v3/slice.h 2012-03-27 17:29:32 +0000
1520@@ -35,13 +35,13 @@
1521 class UGSlice : public UGSlice_ {
1522 public:
1523 /** @internal Create a new slice for a new gesture */
1524- UGSlice(Gesture& gesture, UFEvent event, const TouchSet& touches,
1525+ UGSlice(Gesture& gesture, UFEvent event, const TouchMap& touches,
1526 UGGestureTypeMask recognized);
1527 /** @internal Create a new copy of an existing slice */
1528 UGSlice(const SharedUGSlice& prev, bool end = false);
1529 /** @internal Create a new slice by updating an existing slice */
1530 UGSlice(const SharedUGSlice& prev, Gesture &gesture,
1531- UFEvent event, const TouchSet& touches);
1532+ UFEvent event, const TouchMap& touches);
1533
1534 ~UGSlice();
1535
1536@@ -51,7 +51,7 @@
1537 UGStatus GetProperty(UGSliceProperty property, void* value) const;
1538
1539 uint64_t time() const { return time_; }
1540- const TouchSet& touches() { return touches_; }
1541+ const TouchMap& touches() { return touches_; }
1542 const UFFrame& frame() { return frame_; }
1543 UGGestureState state() const { return state_; }
1544 bool physically_ended() const { return physically_ended_; }
1545@@ -66,7 +66,7 @@
1546 unsigned int id_;
1547 const UFEvent event_;
1548 UFFrame frame_;
1549- TouchSet touches_;
1550+ TouchMap touches_;
1551 uint64_t time_;
1552 UGGestureState state_;
1553 bool physically_ended_;
1554@@ -85,7 +85,7 @@
1555 bool touch_count_changed_;
1556 UGSubscription *subscription_;
1557
1558- void GetValues(Gesture &gesture, const TouchSet& touches, float* x, float* y,
1559+ void GetValues(Gesture &gesture, const TouchMap& touches, float* x, float* y,
1560 float* radius, float* angle, bool init);
1561 void SetTransforms(Gesture &gesture);
1562 void SetCenterOfRotation();
1563
1564=== added file 'src/v3/touch.cpp'
1565--- src/v3/touch.cpp 1970-01-01 00:00:00 +0000
1566+++ src/v3/touch.cpp 2012-03-27 17:29:32 +0000
1567@@ -0,0 +1,89 @@
1568+/*****************************************************************************
1569+ *
1570+ * grail - Gesture Recognition And Instantiation Library
1571+ *
1572+ * Copyright (C) 2012 Canonical Ltd.
1573+ *
1574+ * This library is free software: you can redistribute it and/or modify it
1575+ * under the terms of the GNU Lesser General Public License version 3
1576+ * as published by the Free Software Foundation.
1577+ *
1578+ * This library is distributed in the hope that it will be useful, but
1579+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1580+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1581+ * PURPOSE. See the GNU Lesser General Public License for more details.
1582+ *
1583+ * You should have received a copy of the GNU Lesser General Public License
1584+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
1585+ *
1586+ ****************************************************************************/
1587+
1588+#include "v3/touch.h"
1589+
1590+#include <utouch/frame_x11.h>
1591+
1592+#include "v3/log.h"
1593+
1594+namespace utouch {
1595+namespace grail {
1596+
1597+Touch::Touch(UFTouch touch, UFDevice device, UFWindowId window_id)
1598+ : id_(frame_touch_get_id(touch)),
1599+ start_time_(frame_touch_get_start_time(touch)),
1600+ device_(device),
1601+ window_id_(window_id),
1602+ accepted_(false),
1603+ pending_end_(false),
1604+ owned_(false),
1605+ ended_(false) {
1606+ Update(touch);
1607+}
1608+
1609+void Touch::Update(UFTouch touch) {
1610+ if (frame_touch_get_state(touch) == UFTouchStateEnd) {
1611+ ended_ = true;
1612+ LOG(Dbg) << "touch " << id_ << " has ended\n";
1613+ }
1614+
1615+ UFStatus status;
1616+ int value;
1617+
1618+ if (!pending_end_) {
1619+ status = frame_touch_get_property(touch, UFTouchPropertyPendingEnd, &value);
1620+ if (status != UFStatusSuccess) {
1621+ LOG(Warn) << "failed to get touch pending end property\n";
1622+ } else if (value) {
1623+ pending_end_ = true;
1624+ LOG(Dbg) << "touch " << id_ << " is pending end\n";
1625+ }
1626+ }
1627+
1628+ if (!owned_) {
1629+ status = frame_touch_get_property(touch, UFTouchPropertyOwned, &value);
1630+ if (status != UFStatusSuccess) {
1631+ LOG(Warn) << "failed to get touch owned property\n";
1632+ } else if (value) {
1633+ owned_ = true;
1634+ LOG(Dbg) << "touch " << id_ << " is owned\n";
1635+ }
1636+ }
1637+}
1638+
1639+void Touch::Accept() {
1640+ LOG(Dbg) << "accepting touch " << id_ << "\n";
1641+ if (frame_x11_accept_touch(device_, window_id_, id_) != UFStatusSuccess)
1642+ LOG(Err) << "touch " << id_ << " failed to be accepted\n";
1643+
1644+ accepted_ = true;
1645+}
1646+
1647+Touch::~Touch() {
1648+ if (!accepted_) {
1649+ LOG(Dbg) << "rejecting touch " << id_ << "\n";
1650+ if (frame_x11_reject_touch(device_, window_id_, id_) != UFStatusSuccess)
1651+ LOG(Err) << "touch " << id_ << " failed to be rejected\n";
1652+ }
1653+}
1654+
1655+} // namespace grail
1656+} // namespace utouch
1657
1658=== added file 'src/v3/touch.h'
1659--- src/v3/touch.h 1970-01-01 00:00:00 +0000
1660+++ src/v3/touch.h 2012-03-27 17:29:32 +0000
1661@@ -0,0 +1,64 @@
1662+/*****************************************************************************
1663+ *
1664+ * grail - Gesture Recognition And Instantiation Library
1665+ *
1666+ * Copyright (C) 2012 Canonical Ltd.
1667+ *
1668+ * This library is free software: you can redistribute it and/or modify it
1669+ * under the terms of the GNU Lesser General Public License version 3
1670+ * as published by the Free Software Foundation.
1671+ *
1672+ * This library is distributed in the hope that it will be useful, but
1673+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1674+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1675+ * PURPOSE. See the GNU Lesser General Public License for more details.
1676+ *
1677+ * You should have received a copy of the GNU Lesser General Public License
1678+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
1679+ *
1680+ ****************************************************************************/
1681+
1682+#ifndef UTOUCH_GRAIL_TOUCH_H_
1683+#define UTOUCH_GRAIL_TOUCH_H_
1684+
1685+#include <utouch/frame.h>
1686+
1687+namespace utouch {
1688+namespace grail {
1689+
1690+class Touch {
1691+ public:
1692+ Touch(UFTouch touch, UFDevice device, UFWindowId window_id);
1693+ ~Touch();
1694+
1695+ void Update(UFTouch touch);
1696+ void Accept();
1697+
1698+ UFTouchId id() const { return id_; }
1699+ uint64_t start_time() const { return start_time_; }
1700+ bool accepted() const { return accepted_; }
1701+ bool pending_end() const { return pending_end_; }
1702+ void set_pending_end(bool pending_end) { pending_end_ = pending_end; }
1703+ bool owned() const { return owned_; }
1704+ void set_owned(bool owned) { owned_ = owned; }
1705+ bool ended() const { return ended_; }
1706+ void set_ended(bool ended) { ended_ = ended; }
1707+
1708+ Touch(const Touch&) = delete;
1709+ Touch& operator=(const Touch&) = delete;
1710+
1711+ private:
1712+ UFTouchId id_;
1713+ uint64_t start_time_;
1714+ UFDevice device_;
1715+ UFWindowId window_id_;
1716+ bool accepted_;
1717+ bool pending_end_;
1718+ bool owned_;
1719+ bool ended_;
1720+};
1721+
1722+} // namespace grail
1723+} // namespace utouch
1724+
1725+#endif // UTOUCH_GRAIL_TOUCH_H_

Subscribers

People subscribed via source and target branches