Merge lp:~chasedouglas/grail/touch-states into lp:grail
- touch-states
- Merge into trunk
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 |
Related bugs: |
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.
Commit message
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.
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
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:
> 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?
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::DeleteTou
}
Touch {
~Touch() {
emit destroyed(id);
}
}
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.
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
AtomicRecognize
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.
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-
- 107 - you could take the opportunity and fix that comment. It reffers to accepted stuff instead of unaccepted.
- 125 - trailing whitespace
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
Looks good, apart from the small issues mentioned in previous commits
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
Chase Douglas (chasedouglas) wrote : | # |
All the comments should be addressed by the prerequisite branch and changes in this branch.
Daniel d'Andrada (dandrader) wrote : | # |
Looking good!
I would leave commit 218 out but that's up to you
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
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_ |
* some changes merely fix indentation. That pollutes the commit diff and bzr history. :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.
* 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: