1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef UI_AURA_WINDOW_EVENT_DISPATCHER_H_
6#define UI_AURA_WINDOW_EVENT_DISPATCHER_H_
7
8#include <vector>
9
10#include "base/basictypes.h"
11#include "base/gtest_prod_util.h"
12#include "base/memory/ref_counted.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/memory/weak_ptr.h"
15#include "base/message_loop/message_loop.h"
16#include "base/scoped_observer.h"
17#include "ui/aura/aura_export.h"
18#include "ui/aura/client/capture_delegate.h"
19#include "ui/aura/env_observer.h"
20#include "ui/aura/window_observer.h"
21#include "ui/base/cursor/cursor.h"
22#include "ui/events/event_constants.h"
23#include "ui/events/event_processor.h"
24#include "ui/events/event_targeter.h"
25#include "ui/events/gestures/gesture_recognizer.h"
26#include "ui/events/gestures/gesture_types.h"
27#include "ui/gfx/native_widget_types.h"
28#include "ui/gfx/point.h"
29
30namespace gfx {
31class Size;
32class Transform;
33}
34
35namespace ui {
36class GestureEvent;
37class GestureRecognizer;
38class KeyEvent;
39class MouseEvent;
40class ScrollEvent;
41class TouchEvent;
42}
43
44namespace aura {
45class TestScreen;
46class WindowTargeter;
47class WindowTreeHost;
48
49namespace test {
50class WindowEventDispatcherTestApi;
51}
52
53// WindowEventDispatcher orchestrates event dispatch within a window tree
54// owned by WindowTreeHost. WTH also owns the WED.
55// TODO(beng): In progress, remove functionality not directly related to
56//             event dispatch.
57class AURA_EXPORT WindowEventDispatcher : public ui::EventProcessor,
58                                          public ui::GestureEventHelper,
59                                          public client::CaptureDelegate,
60                                          public WindowObserver,
61                                          public EnvObserver {
62 public:
63  explicit WindowEventDispatcher(WindowTreeHost* host);
64  virtual ~WindowEventDispatcher();
65
66  Window* mouse_pressed_handler() { return mouse_pressed_handler_; }
67  Window* mouse_moved_handler() { return mouse_moved_handler_; }
68
69  // Repost event for re-processing. Used when exiting context menus.
70  // We only support the ET_MOUSE_PRESSED and ET_GESTURE_TAP_DOWN event
71  // types (although the latter is currently a no-op).
72  void RepostEvent(const ui::LocatedEvent& event);
73
74  // Invoked when the mouse events get enabled or disabled.
75  void OnMouseEventsEnableStateChanged(bool enabled);
76
77  void DispatchCancelModeEvent();
78
79  // Dispatches a ui::ET_MOUSE_EXITED event at |point|.
80  // TODO(beng): needed only for WTH::OnCursorVisibilityChanged().
81  ui::EventDispatchDetails DispatchMouseExitAtPoint(
82      const gfx::Point& point) WARN_UNUSED_RESULT;
83
84  // Gesture Recognition -------------------------------------------------------
85
86  // When a touch event is dispatched to a Window, it may want to process the
87  // touch event asynchronously. In such cases, the window should consume the
88  // event during the event dispatch. Once the event is properly processed, the
89  // window should let the WindowEventDispatcher know about the result of the
90  // event processing, so that gesture events can be properly created and
91  // dispatched. |event|'s location should be in the dispatcher's coordinate
92  // space, in DIPs.
93  void ProcessedTouchEvent(ui::TouchEvent* event,
94                           Window* window,
95                           ui::EventResult result);
96
97  // These methods are used to defer the processing of mouse/touch events
98  // related to resize. A client (typically a RenderWidgetHostViewAura) can call
99  // HoldPointerMoves when an resize is initiated and then ReleasePointerMoves
100  // once the resize is completed.
101  //
102  // More than one hold can be invoked and each hold must be cancelled by a
103  // release before we resume normal operation.
104  void HoldPointerMoves();
105  void ReleasePointerMoves();
106
107  // Gets the last location seen in a mouse event in this root window's
108  // coordinates. This may return a point outside the root window's bounds.
109  gfx::Point GetLastMouseLocationInRoot() const;
110
111  void OnHostLostMouseGrab();
112  void OnCursorMovedToRootLocation(const gfx::Point& root_location);
113
114  // TODO(beng): This is only needed because this cleanup needs to happen after
115  //             all other observers are notified of OnWindowDestroying() but
116  //             before OnWindowDestroyed() is sent (i.e. while the window
117  //             hierarchy is still intact). This didn't seem worth adding a
118  //             generic notification for as only this class needs to implement
119  //             it. I would however like to find a way to do this via an
120  //             observer.
121  void OnPostNotifiedWindowDestroying(Window* window);
122
123 private:
124  FRIEND_TEST_ALL_PREFIXES(WindowEventDispatcherTest,
125                           KeepTranslatedEventInRoot);
126
127  friend class test::WindowEventDispatcherTestApi;
128  friend class Window;
129  friend class TestScreen;
130
131  // The parameter for OnWindowHidden() to specify why window is hidden.
132  enum WindowHiddenReason {
133    WINDOW_DESTROYED,  // Window is destroyed.
134    WINDOW_HIDDEN,     // Window is hidden.
135    WINDOW_MOVING,     // Window is temporarily marked as hidden due to move
136                       // across root windows.
137  };
138
139  Window* window();
140  const Window* window() const;
141
142  // Updates the event with the appropriate transform for the device scale
143  // factor. The WindowEventDispatcher dispatches events in the physical pixel
144  // coordinate. But the event processing from WindowEventDispatcher onwards
145  // happen in device-independent pixel coordinate. So it is necessary to update
146  // the event received from the host.
147  void TransformEventForDeviceScaleFactor(ui::LocatedEvent* event);
148
149  // Dispatches OnMouseExited to the |window| which is hiding if necessary.
150  void DispatchMouseExitToHidingWindow(Window* window);
151
152  // Dispatches the specified event type (intended for enter/exit) to the
153  // |mouse_moved_handler_|.
154  ui::EventDispatchDetails DispatchMouseEnterOrExit(
155      const ui::MouseEvent& event,
156      ui::EventType type) WARN_UNUSED_RESULT;
157  ui::EventDispatchDetails ProcessGestures(
158      ui::GestureRecognizer::Gestures* gestures) WARN_UNUSED_RESULT;
159
160  // Called when a window becomes invisible, either by being removed
161  // from root window hierarchy, via SetVisible(false) or being destroyed.
162  // |reason| specifies what triggered the hiding. Note that becoming invisible
163  // will cause a window to lose capture and some windows may destroy themselves
164  // on capture (like DragDropTracker).
165  void OnWindowHidden(Window* invisible, WindowHiddenReason reason);
166
167  // Returns a target window for the given gesture event.
168  Window* GetGestureTarget(ui::GestureEvent* event);
169
170  // Overridden from aura::client::CaptureDelegate:
171  virtual void UpdateCapture(Window* old_capture, Window* new_capture) OVERRIDE;
172  virtual void OnOtherRootGotCapture() OVERRIDE;
173  virtual void SetNativeCapture() OVERRIDE;
174  virtual void ReleaseNativeCapture() OVERRIDE;
175
176  // Overridden from ui::EventProcessor:
177  virtual ui::EventTarget* GetRootTarget() OVERRIDE;
178  virtual void PrepareEventForDispatch(ui::Event* event) OVERRIDE;
179
180  // Overridden from ui::EventDispatcherDelegate.
181  virtual bool CanDispatchToTarget(ui::EventTarget* target) OVERRIDE;
182  virtual ui::EventDispatchDetails PreDispatchEvent(ui::EventTarget* target,
183                                                    ui::Event* event) OVERRIDE;
184  virtual ui::EventDispatchDetails PostDispatchEvent(
185      ui::EventTarget* target, const ui::Event& event) OVERRIDE;
186
187  // Overridden from ui::GestureEventHelper.
188  virtual bool CanDispatchToConsumer(ui::GestureConsumer* consumer) OVERRIDE;
189  virtual void DispatchGestureEvent(ui::GestureEvent* event) OVERRIDE;
190  virtual void DispatchCancelTouchEvent(ui::TouchEvent* event) OVERRIDE;
191
192  // Overridden from WindowObserver:
193  virtual void OnWindowDestroying(Window* window) OVERRIDE;
194  virtual void OnWindowDestroyed(Window* window) OVERRIDE;
195  virtual void OnWindowAddedToRootWindow(Window* window) OVERRIDE;
196  virtual void OnWindowRemovingFromRootWindow(Window* window,
197                                              Window* new_root) OVERRIDE;
198  virtual void OnWindowVisibilityChanging(Window* window,
199                                          bool visible) OVERRIDE;
200  virtual void OnWindowVisibilityChanged(Window* window, bool visible) OVERRIDE;
201  virtual void OnWindowBoundsChanged(Window* window,
202                                     const gfx::Rect& old_bounds,
203                                     const gfx::Rect& new_bounds) OVERRIDE;
204  virtual void OnWindowTransforming(Window* window) OVERRIDE;
205  virtual void OnWindowTransformed(Window* window) OVERRIDE;
206
207  // Overridden from EnvObserver:
208  virtual void OnWindowInitialized(Window* window) OVERRIDE;
209
210  // We hold and aggregate mouse drags and touch moves as a way of throttling
211  // resizes when HoldMouseMoves() is called. The following methods are used to
212  // dispatch held and newly incoming mouse and touch events, typically when an
213  // event other than one of these needs dispatching or a matching
214  // ReleaseMouseMoves()/ReleaseTouchMoves() is called.  NOTE: because these
215  // methods dispatch events from WindowTreeHost the coordinates are in terms of
216  // the root.
217  ui::EventDispatchDetails DispatchHeldEvents() WARN_UNUSED_RESULT;
218
219  // Posts a task to send synthesized mouse move event if there is no a pending
220  // task.
221  void PostSynthesizeMouseMove();
222
223  // Creates and dispatches synthesized mouse move event using the current mouse
224  // location.
225  ui::EventDispatchDetails SynthesizeMouseMoveEvent() WARN_UNUSED_RESULT;
226
227  // Calls SynthesizeMouseMove() if |window| is currently visible and contains
228  // the mouse cursor.
229  void SynthesizeMouseMoveAfterChangeToWindow(Window* window);
230
231  void PreDispatchLocatedEvent(Window* target, ui::LocatedEvent* event);
232  void PreDispatchMouseEvent(Window* target, ui::MouseEvent* event);
233  void PreDispatchTouchEvent(Window* target, ui::TouchEvent* event);
234
235  WindowTreeHost* host_;
236
237  // Touch ids that are currently down.
238  uint32 touch_ids_down_;
239
240  Window* mouse_pressed_handler_;
241  Window* mouse_moved_handler_;
242  Window* event_dispatch_target_;
243  Window* old_dispatch_target_;
244
245  bool synthesize_mouse_move_;
246
247  // How many move holds are outstanding. We try to defer dispatching
248  // touch/mouse moves while the count is > 0.
249  int move_hold_count_;
250  // The location of |held_move_event_| is in |window_|'s coordinate.
251  scoped_ptr<ui::LocatedEvent> held_move_event_;
252
253  // Allowing for reposting of events. Used when exiting context menus.
254  scoped_ptr<ui::LocatedEvent> held_repostable_event_;
255
256  // Set when dispatching a held event.
257  bool dispatching_held_event_;
258
259  ScopedObserver<aura::Window, aura::WindowObserver> observer_manager_;
260
261  // Used to schedule reposting an event.
262  base::WeakPtrFactory<WindowEventDispatcher> repost_event_factory_;
263
264  // Used to schedule DispatchHeldEvents() when |move_hold_count_| goes to 0.
265  base::WeakPtrFactory<WindowEventDispatcher> held_event_factory_;
266
267  DISALLOW_COPY_AND_ASSIGN(WindowEventDispatcher);
268};
269
270}  // namespace aura
271
272#endif  // UI_AURA_WINDOW_EVENT_DISPATCHER_H_
273