Index: mojo/services/view_manager/gesture_manager.h |
diff --git a/mojo/services/view_manager/gesture_manager.h b/mojo/services/view_manager/gesture_manager.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..666dfec605bba3e1f038305080653b6e32e0fadc |
--- /dev/null |
+++ b/mojo/services/view_manager/gesture_manager.h |
@@ -0,0 +1,188 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef SERVICES_VIEW_MANAGER_GESTURE_MANAGER_H_ |
+#define SERVICES_VIEW_MANAGER_GESTURE_MANAGER_H_ |
+ |
+#include <map> |
+#include <set> |
+ |
+#include "base/memory/scoped_ptr.h" |
+#include "base/memory/scoped_vector.h" |
+ |
+namespace mojo { |
+class Event; |
+} |
+ |
+namespace view_manager { |
+ |
+class GestureManagerDelegate; |
+class GestureManagerTest; |
+class ServerView; |
+ |
+struct GestureStateChange { |
+ GestureStateChange(); |
+ ~GestureStateChange(); |
+ |
+ uint32_t chosen_gesture; |
+ std::set<uint32_t> canceled_gestures; |
+}; |
+ |
+using ChangeMap = std::map<const ServerView*, GestureStateChange>; |
+ |
+// GestureManager handles incoming pointer events. It determines the set of |
+// views (at most one per connection) that are interested in the event and |
+// informs the delegate at the appropriate time. |
+// |
+// Each pointer may have any number of views associated with it, and each view |
+// may have any number of gestures associated with it. Gesture are identified |
+// the by the pair of the connection id of the view and the client supplied |
+// gesture. The same gesture may be used in multiple pointers (see example |
+// below). |
+// |
+// Gestures have the following states: |
+// . initial: Initial state for new gestures. From this state the gesture may |
+// become chosen or canceled. Once a gesture moves out of this state it can |
+// never go back. |
+// . chosen: the gesture has been chosen. From this state the gesture may be |
+// canceled. |
+// . canceled: the gesture has been canceled. |
+// Gestures are active as long as they are included in the set of |
+// |possible_gesture_ids|. Gestures can be removed at any time by removing the |
+// gesture from |possible_gesture_ids|. |
+// |
+// A particular pointer has two distinct states: |
+// . initial: none of the gestures associated with the pointer have been |
+// chosen. |
+// . chosen: when a gesture associated with the pointer has been chosen. |
+// Pointers are removed when a POINTER_UP or POINTER_CANCEL event is received. |
+// |
+// When a pointer is chosen all other gestures associated with the pointer are |
+// implicitly canceled. If the chosen gesture is canceled the pointer remains |
+// in the chosen state and no gestures can be chosen. |
+// |
+// Event propagation (ProcessEvent()) is handled in two distinct ways: |
+// . Until a gesture has been chosen for the pointer, views are notified in |
+// order (deepest first). The next view (ancestor) is notified once |
+// SetGestures() has been invoked for the previous (descendant) view. |
+// . Once a gesture has been chosen, then incoming events are immediately |
+// dispatched. |
+// |
+// The following example highlights various states and transitions: |
+// . A POINTER_DOWN event is received for the pointer p1. The views that |
+// contain the location of the event (starting with the deepest) are v1, v2, |
+// v3 and v4. Both v1 and v2 have the property kViewManagerKeyWantsTouchEvents |
+// set, so only v1 and v2 are considered. v1 is the deepest view, so the |
+// touch event is set to it and only it first. |
+// . v1 responds with possible gestures g1 and g2. v1 does not specify either |
+// of the gestures as chosen. |
+// . As the response from v1 has been received and there is no chosen gesture |
+// the POINTER_DOWN event is sent to v2. |
+// . v2 responds with gestures g3 and g4, neither of which are chosen. |
+// . A POINTER_MOVE for p1 is received. As no gestures have been chosen event |
+// of the POINTER_MOVE continues with v1 first. |
+// . v1 returns g1 and g2 as possible gestures and does not choose one. |
+// . The POINTER_MOVE is sent to v2. |
+// . v2 returns g3 and g4 as possible gestures and does not choose one. |
+// At this point p1 has the possible gestures g1, g2, g3, g4. Gestures g1 and |
+// g2 are associated with v1. Gestures g3 and g4 are associated with v2. |
+// . A POINTER_DOWN event is received for the pointer p2. v1 and v2 again |
+// contain the location of the pointer. v1 is handed the event first. |
+// . A POINTER_MOVE event is received for the pointer p2. As the response from |
+// v1 has not been received yet, the event is not sent yet (it is queued up). |
+// . v1 responds to the POINTER_DOWN for p2 with g1 and g2 and chooses g1. |
+// At this point g2, g3 and g4 are all canceled with g1 chosen. p2 is in the |
+// chosen state, as is p1 (p1 enters the chosen state as it contains the chosen |
+// gesture as well). |
+// . The POINTER_DOWN event for p2 is sent to v2. As p2 is in the chosen state |
+// the POINTER_MOVE event that was queued up is sent to both v1 and v2 at the |
+// same time (no waiting for response). |
+// |
+// TODO(sky): add some sort of timeout to deal with hung processes. |
+class GestureManager { |
+ public: |
+ using GestureAndConnectionId = uint64_t; |
+ |
+ static const uint32_t kInvalidGestureId; |
+ |
+ GestureManager(GestureManagerDelegate* delegate, const ServerView* root); |
+ ~GestureManager(); |
+ |
+ // Processes the current event. See GestureManager description for details. |
+ bool ProcessEvent(const mojo::Event& event); |
+ |
+ // Sets the gestures for the specified view and pointer. |
+ scoped_ptr<ChangeMap> SetGestures( |
+ const ServerView* view, |
+ int32_t pointer_id, |
+ uint32_t chosen_gesture_id, |
+ const std::set<uint32_t>& possible_gesture_ids, |
+ const std::set<uint32_t>& canceled_gesture_ids); |
+ |
+ private: |
+ friend class GestureManagerTest; |
+ |
+ class Gesture; |
+ class Pointer; |
+ struct PointerAndView; |
+ class ScheduledDeleteProcessor; |
+ |
+ // Returns the Pointer for |pointer_id|, or null if one doesn't exist. |
+ Pointer* GetPointerById(int32_t pointer_id); |
+ |
+ // Notification that |pointer| has no gestures. This deletes |pointer|. |
+ void PointerHasNoGestures(Pointer* pointer); |
+ |
+ // Returns the Gesture for the specified arguments, creating if necessary. |
+ Gesture* GetGesture(const ServerView* view, uint32_t gesture_id); |
+ |
+ // Called from Pointer when a gesture is associated with a pointer. |
+ void AttachGesture(Gesture* gesture, |
+ Pointer* pointer, |
+ const ServerView* view); |
+ |
+ // Called from Pointer when a gesture is no longer associated with a |
+ // pointer. |
+ void DetachGesture(Gesture* gesture, |
+ Pointer* pointer, |
+ const ServerView* view); |
+ |
+ // Cancels the supplied gesture (if it isn't canceled already). Notifies all |
+ // pointers containing |gesture| that |gesture| has been canceled. |
+ void CancelGesture(Gesture* gesture, |
+ Pointer* pointer, |
+ const ServerView* view); |
+ |
+ // Chooses the supplied gesture. Notifies all pointers containing |gesture| |
+ // that |gesture| has been chosen. |
+ void ChooseGesture(Gesture* gesture, |
+ Pointer* pointer, |
+ const ServerView* view); |
+ |
+ // Deletes |pointer| after processing the current event. We delay deletion |
+ // until after the event as immediate deletion can cause problems for Pointer |
+ // (this is because the same Pointer may be on multiple frames of the stack). |
+ void ScheduleDelete(Pointer* pointer); |
+ |
+ GestureManagerDelegate* delegate_; |
+ const ServerView* root_view_; |
+ |
+ // Map for looking up gestures. Gestures are identified by the pair of |
+ // connection id and supplied gesture id. |
+ std::map<GestureAndConnectionId, Gesture*> gesture_map_; |
+ |
+ ScopedVector<Pointer> active_pointers_; |
+ |
+ // See comment in ScheduleDelete() for details. |
+ ScopedVector<Pointer> pointers_to_delete_; |
+ |
+ // Accumulates changes as the result of SetGestures(). |
+ scoped_ptr<ChangeMap> current_change_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(GestureManager); |
+}; |
+ |
+} // namespace view_manager |
+ |
+#endif // SERVICES_VIEW_MANAGER_GESTURE_MANAGER_H_ |