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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
ash / wm / toplevel_window_event_handler.h [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_WM_TOPLEVEL_WINDOW_EVENT_HANDLER_H_
#define ASH_WM_TOPLEVEL_WINDOW_EVENT_HANDLER_H_
#include <memory>
#include "ash/ash_export.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "ui/aura/window_observer.h"
#include "ui/aura/window_occlusion_tracker.h"
#include "ui/display/display_observer.h"
#include "ui/display/manager/display_manager_observer.h"
#include "ui/events/event_handler.h"
#include "ui/events/gestures/gesture_types.h"
#include "ui/wm/public/window_move_client.h"
namespace aura {
class Window;
} // namespace aura
namespace ui {
class KeyEvent;
class LocatedEvent;
class MouseEvent;
class GestureEvent;
} // namespace ui
namespace ash {
namespace mojom {
enum class WindowStateType;
}
// ToplevelWindowEventHandler handles dragging and resizing of top level
// windows.
class ASH_EXPORT ToplevelWindowEventHandler
: public display::DisplayManagerObserver,
public aura::WindowObserver,
public display::DisplayObserver,
public ui::EventHandler,
public wm::WindowMoveClient {
public:
// Describes what triggered ending the drag.
enum class DragResult {
// The drag successfully completed.
SUCCESS,
REVERT,
// The underlying window was destroyed while the drag is in process.
WINDOW_DESTROYED
};
using EndClosure = base::OnceCallback<void(DragResult)>;
ToplevelWindowEventHandler();
ToplevelWindowEventHandler(const ToplevelWindowEventHandler&) = delete;
ToplevelWindowEventHandler& operator=(const ToplevelWindowEventHandler&) =
delete;
~ToplevelWindowEventHandler() override;
// display::DisplayObserver:
void OnDisplayMetricsChanged(const display::Display& display,
uint32_t metrics) override;
// ui::EventHandler:
void OnKeyEvent(ui::KeyEvent* event) override;
void OnMouseEvent(ui::MouseEvent* event) override;
void OnGestureEvent(ui::GestureEvent* event) override;
// wm::WindowMoveClient:
wm::WindowMoveResult RunMoveLoop(aura::Window* source,
const gfx::Vector2d& drag_offset,
::wm::WindowMoveSource move_source) override;
void EndMoveLoop() override;
// Attempts to start a drag if one is not already in progress. Returns true if
// successful. |end_closure| is run when the drag completes, including if the
// drag is not started. If |update_gesture_target| is true, the gesture
// target is forcefully updated and gesture events are transferred to
// new target if any. If |grab_capture| is true, capture is set to |window|,
// if it is not set yet. In general, prefer the first version.
bool AttemptToStartDrag(aura::Window* window,
const gfx::PointF& point_in_parent,
int window_component,
ToplevelWindowEventHandler::EndClosure end_closure);
bool AttemptToStartDrag(aura::Window* window,
const gfx::PointF& point_in_parent,
int window_component,
::wm::WindowMoveSource source,
EndClosure end_closure,
bool update_gesture_target,
bool grab_capture = true);
// Attempts to start a pinch if one is not already in progress. Returns true
// if successful.
bool AttemptToStartPinch(aura::Window* window,
const gfx::PointF& point_in_parent,
int window_component,
bool update_gesture_target);
// If there is a drag in progress it is reverted, otherwise does nothing.
void RevertDrag();
// Returns the toplevel window that should be dragged for a gesture event that
// occurs in the HTCLIENT area of a window. Returns null if there shouldn't be
// special casing for this HTCLIENT area gesture. This is used to drag app
// windows which are fullscreened/maximized in tablet mode from the top of the
// screen, which don't have a window frame.
static aura::Window* GetTargetForClientAreaGesture(ui::GestureEvent* event,
aura::Window* target);
// Returns the window that is currently handling gesture events and its
// location.
aura::Window* gesture_target() { return gesture_target_; }
const gfx::PointF& event_location_in_gesture_target() {
return event_location_in_gesture_target_;
}
bool in_gesture_drag() { return in_gesture_drag_; }
// Returns true if there is a drag in progress.
bool is_drag_in_progress() const { return window_resizer_.get() != nullptr; }
bool in_pinch() const { return in_pinch_; }
void CompleteDragForTesting(DragResult result);
void ResetWindowResizerForTesting();
private:
class ScopedWindowResizer;
// Called from AttemptToStartDrag() to create the WindowResizer. This returns
// true on success, false if there is something preventing the resize from
// starting.
bool PrepareForDrag(aura::Window* window,
const gfx::PointF& point_in_parent,
int window_component,
::wm::WindowMoveSource source,
bool grab_capture);
// Called from `AttemptToStartPinch()` to create the WindowResizer. This also
// returns true on success and false if resize cannot be initiated.
bool PrepareForPinch(aura::Window* window,
const gfx::PointF& point_in_parent,
int window_component);
// Completes or reverts the drag if one is in progress. Returns true if a
// drag was completed or reverted.
bool CompleteDrag(DragResult result);
// Completes pinch but not drag. `CompleteDrag()` should be called even
// after `CompletePinch()` is called to handle revert, snap, etc.
bool CompletePinch();
void HandleMousePressed(aura::Window* target, ui::MouseEvent* event);
void HandleMouseReleased(aura::Window* target, ui::MouseEvent* event);
// Called during a drag to resize/position the window.
void HandleDrag(aura::Window* target, ui::LocatedEvent* event);
// Called during a pinch to resize/position the window.
void HandlePinch(aura::Window* target, ui::GestureEvent* event);
// Called during mouse moves to update window resize shadows.
void HandleMouseMoved(aura::Window* target, ui::LocatedEvent* event);
// Called for mouse exits to hide window resize shadows.
void HandleMouseExited(aura::Window* target, ui::LocatedEvent* event);
// Called when mouse capture is lost.
void HandleCaptureLost(ui::LocatedEvent* event);
// Handles the gesture fling or swipe event.
void HandleFlingOrSwipe(ui::GestureEvent* event);
// Invoked from ScopedWindowResizer if the window is destroyed.
void ResizerWindowDestroyed();
// display::DisplayManagerObserver:
void OnWillApplyDisplayChanges() override;
// aura::WindowObserver:
void OnWindowDestroying(aura::Window* window) override;
// Update the gesture target and event location.
void UpdateGestureTarget(aura::Window* window,
const gfx::PointF& location = gfx::PointF());
// The hittest result for the first finger at the time that it initially
// touched the screen. |first_finger_hittest_| is one of ui/base/hit_test.h
int first_finger_hittest_;
// The point for the first finger at the time that it initially touched the
// screen.
gfx::PointF first_finger_touch_point_;
// True while a drag from the caption area to move the floated window is in
// progress. If true, stops propagation to avoid showing the tab strip.
bool is_moving_floated_window_ = false;
// Is a window move/resize in progress because of gesture events?
bool in_gesture_drag_ = false;
// True if the bounds need to be reinitialized in the next gesture update.
// This is necessary because during the transition from pinch gesture to
// drag gesture the EventType::kGestureScrollBegin event is never called, and
// therefore `window_resizer_` must be initiated with the next
// EventType::kGestureScrollUpdate event.
bool requires_reinitialization_ = false;
raw_ptr<aura::Window> gesture_target_ = nullptr;
gfx::PointF event_location_in_gesture_target_;
// True if `this` is receiving pinch events. There is a delay from
// when `this` first receives a gesture begin event to when the client
// asks the gesture to be initiated, during which time the gesture type
// may have changed. To start the appropriate gesture, `this` keeps track
// of if the current gesture is a drag or a pinch.
bool in_pinch_ = false;
std::unique_ptr<ScopedWindowResizer> window_resizer_;
// We exclude dragged or resized windows from occluding things below them to
// prevent windows from being marked as occluded temporarily while another
// window is being, for example, dragged over them. This is particularly
// necessary for lacros where occlusion may cause the content to be evicted
// and replaced with a snapshot.
std::optional<aura::WindowOcclusionTracker::ScopedExclude> scoped_exclude_;
display::ScopedDisplayObserver display_observer_{this};
EndClosure end_closure_;
// Are we running a nested run loop from RunMoveLoop().
bool in_move_loop_ = false;
base::WeakPtrFactory<ToplevelWindowEventHandler> weak_factory_{this};
};
} // namespace ash
#endif // ASH_WM_TOPLEVEL_WINDOW_EVENT_HANDLER_H_