summaryrefslogtreecommitdiffstats
path: root/components/mus/gesture_manager.h
blob: 373e8f856740e42b47a41f5c3a6632233ee5b2b4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
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 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 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  // COMPONENTS_MUS_GESTURE_MANAGER_H_