// 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_VIEW_MANAGER_GESTURE_MANAGER_H_ #define COMPONENTS_VIEW_MANAGER_GESTURE_MANAGER_H_ #include #include #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 canceled_gestures; }; using ChangeMap = std::map; // 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 SetGestures( const ServerView* view, int32_t pointer_id, uint32_t chosen_gesture_id, const std::set& possible_gesture_ids, const std::set& 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 gesture_map_; ScopedVector active_pointers_; // See comment in ScheduleDelete() for details. ScopedVector pointers_to_delete_; // Accumulates changes as the result of SetGestures(). scoped_ptr current_change_; DISALLOW_COPY_AND_ASSIGN(GestureManager); }; } // namespace view_manager #endif // COMPONENTS_VIEW_MANAGER_GESTURE_MANAGER_H_