| // 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 COMPONENTS_MUS_GESTURE_MANAGER_H_ |
| #define COMPONENTS_MUS_GESTURE_MANAGER_H_ |
| |
| #include <map> |
| #include <set> |
| |
| #include "base/memory/scoped_ptr.h" |
| #include "base/memory/scoped_vector.h" |
| |
| namespace mojo { |
| class Event; |
| } |
| |
| namespace mus { |
| |
| 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 mus |
| |
| #endif // COMPONENTS_MUS_GESTURE_MANAGER_H_ |