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
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
ash / wm / overview / overview_window_drag_controller.h [blame]
// Copyright 2017 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_OVERVIEW_OVERVIEW_WINDOW_DRAG_CONTROLLER_H_
#define ASH_WM_OVERVIEW_OVERVIEW_WINDOW_DRAG_CONTROLLER_H_
#include <memory>
#include "ash/ash_export.h"
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/splitview/split_view_types.h"
#include "base/containers/flat_map.h"
#include "base/memory/raw_ptr.h"
#include "base/timer/timer.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/size_f.h"
namespace aura {
class Window;
} // namespace aura
namespace ui {
class PresentationTimeRecorder;
} // namespace ui
namespace ash {
class OverviewGrid;
class OverviewItemBase;
class OverviewSession;
class SplitViewController;
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
// Workflows of dragging windows from overview (not from the top or shelf).
enum class OverviewDragAction {
kToGridSameDisplayClamshellMouse = 0,
kToGridSameDisplayClamshellTouch = 1,
kToDeskSameDisplayClamshellMouse = 2,
kToDeskSameDisplayClamshellTouch = 3,
kToSnapSameDisplayClamshellMouse = 4,
kToSnapSameDisplayClamshellTouch = 5,
kSwipeToCloseSuccessfulClamshellTouch = 6,
kSwipeToCloseCanceledClamshellTouch = 7,
kFlingToCloseClamshellTouch = 8,
kToGridOtherDisplayClamshellMouse = 9,
kToDeskOtherDisplayClamshellMouse = 10,
kToSnapOtherDisplayClamshellMouse = 11,
kToGridSameDisplayTabletTouch = 12,
kToDeskSameDisplayTabletTouch = 13,
kToSnapSameDisplayTabletTouch = 14,
kSwipeToCloseSuccessfulTabletTouch = 15,
kSwipeToCloseCanceledTabletTouch = 16,
kFlingToCloseTabletTouch = 17,
kMaxValue = kFlingToCloseTabletTouch,
};
// The drag controller for an overview window item in overview mode. It updates
// the position of the corresponding window item using transform while dragging.
// It also updates the split view drag indicators, which handles showing
// indicators where to drag, and preview areas showing the bounds of the
// window about to be snapped.
class ASH_EXPORT OverviewWindowDragController {
public:
enum class DragBehavior {
// No drag has started.
kNoDrag,
// Drag has started, but it is undecided whether we want to drag to snap or
// drag to close yet.
kUndefined,
// On drag complete, the window will be snapped, if it meets requirements,
// or moved to another desk if dropped on one of the desks' mini_views. This
// mode is triggered if the the window is initially dragged horizontally
// more than vertically (more in X than Y), or if the window item in the
// overview grid was gesture long pressed.
kNormalDrag,
// On drag complete, the window will be closed, if it meets requirements.
// This mode is triggered when the window is initially dragged vertically
// more than horizontally (more in Y than in X).
kDragToClose,
};
enum class DragResult {
// The drag ended without ever being disambiguated between a normal drag and
// drag-to-close.
kNeverDisambiguated,
// The drag was considered as a normal drag, and then the window was dropped
// back into overview, in the same grid or another one.
kDropIntoOverview,
// The drag resulted in snapping the window.
kSnap,
// The drag resulted in moving the window to another desk.
kDragToDesk,
// The drag resulted in closing the window.
kSuccessfulDragToClose,
// The drag was considered as drag-to-close, but did not result in closing
// the window.
kCanceledDragToClose,
};
OverviewWindowDragController(OverviewSession* overview_session,
OverviewItemBase* item,
bool is_touch_dragging,
OverviewItemBase* event_source_item);
OverviewWindowDragController(const OverviewWindowDragController&) = delete;
OverviewWindowDragController& operator=(const OverviewWindowDragController&) =
delete;
~OverviewWindowDragController();
static base::AutoReset<bool> SkipNewDeskButtonScaleUpDurationForTesting();
OverviewItemBase* item() { return item_; }
bool is_touch_dragging() const { return is_touch_dragging_; }
void InitiateDrag(const gfx::PointF& location_in_screen);
void Drag(const gfx::PointF& location_in_screen);
DragResult CompleteDrag(const gfx::PointF& location_in_screen);
void StartNormalDragMode(const gfx::PointF& location_in_screen);
DragResult Fling(const gfx::PointF& location_in_screen,
float velocity_x,
float velocity_y);
void ActivateDraggedWindow();
// Called when a gesture event is reset or when the dragged window is being
// destroyed.
void ResetGesture();
// Resets |overview_session_| to nullptr. It's needed since we defer the
// deletion of OverviewWindowDragController in Overview destructor and
// we need to reset |overview_session_| to nullptr to avoid null pointer
// dereference.
void ResetOverviewSession();
DragBehavior current_drag_behavior_for_testing() const {
return current_drag_behavior_;
}
base::OneShotTimer* new_desk_button_scale_up_timer_for_test() {
return &new_desk_button_scale_up_timer_;
}
private:
enum NormalDragAction {
kToGrid = 0,
kToDesk = 1,
kToSnap = 2,
kNormalDragActionEnumSize = 3,
};
enum DragToCloseAction {
kSwipeToCloseSuccessful = 0,
kSwipeToCloseCanceled = 1,
kFlingToClose = 2,
kDragToCloseActionEnumSize = 3,
};
void StartDragToCloseMode();
// Methods to continue and complete the drag when the drag mode is
// kDragToClose.
void ContinueDragToClose(const gfx::PointF& location_in_screen);
DragResult CompleteDragToClose(const gfx::PointF& location_in_screen);
// Methods to continue and complete the drag when the drag mode is
// kNormalDrag.
void ContinueNormalDrag(const gfx::PointF& location_in_screen);
DragResult CompleteNormalDrag(const gfx::PointF& location_in_screen);
// Updates visuals for the user while dragging items around.
void UpdateDragIndicatorsAndOverviewGrid(
const gfx::PointF& location_in_screen);
aura::Window* GetRootWindowBeingDraggedIn() const;
SnapPosition GetSnapPosition(const gfx::PointF& location_in_screen) const;
// Snaps and activates the window. Uses the divider spawn animation (see
// |SplitViewController::SnapWindow|). Sets |item_| to null because the
// overview item is destroyed.
void SnapWindow(SplitViewController* split_view_controller,
SnapPosition snap_position);
// Returns the item's overview grid, or the grid in which the item is being
// dragged if the multi display overview and split view feature is enabled.
OverviewGrid* GetCurrentGrid() const;
// Records the histogram Ash.Overview.WindowDrag.Workflow.
void RecordNormalDrag(NormalDragAction action,
bool is_dragged_to_other_display) const;
void RecordDragToClose(DragToCloseAction action) const;
// Creates `float_drag_helper_` if needed. The helper will temporarily stack
// the float container under the active desk container, so that dragging
// regular windows appear above overview items of floated windows.
void MaybeCreateFloatDragHelper();
// Scale up the new desk button on the desks bar from expanded state to active
// state to make the new desk button a drop target for the window being
// dragged. It's triggered by `new_desk_button_scale_up_timer_`. Refer to
// `new_desk_button_scale_up_timer_` for more information.
void MaybeScaleUpNewDeskButton();
raw_ptr<OverviewSession> overview_session_;
// The drag target item in the overview mode.
raw_ptr<OverviewItemBase, DanglingUntriaged> item_ = nullptr;
// The source item of the drag event.
raw_ptr<OverviewItemBase, DanglingUntriaged> event_source_item_ = nullptr;
DragBehavior current_drag_behavior_ = DragBehavior::kNoDrag;
// The location of the initial mouse/touch/gesture event in screen.
gfx::PointF initial_event_location_;
// Stores the bounds of |item_| when a drag is started. Used to calculate the
// new bounds on a drag event.
gfx::PointF initial_centerpoint_;
// The original size of the dragged item after we scale it up when we start
// dragging it. The item is restored to this size once it no longer intersects
// with the OverviewDeskBarView.
gfx::SizeF original_scaled_size_;
// Track the per-overview-grid desks bar data used to perform the window
// sizing operations when it is moved towards or on the desks bar.
struct GridDesksBarData {
// The scaled-down size of the dragged item once the drag location is on the
// OverviewDeskBarView of the corresponding grid. We size the item down so
// that it fits inside the desks' preview view.
gfx::SizeF on_desks_bar_item_size;
// Cached values related to dragging items while the desks bar is shown.
// |desks_bar_bounds| is the bounds of the desks bar in screen coordinates.
// |shrink_bounds| is a rectangle around the desks bar which the items
// starts shrinking when the event location is contained. The item will
// shrink until it is contained in |desks_bar_bounds|, at which it has
// reached its minimum size and will no longer shrink.
// |shrink_region_distance| is a vector contained the distance from the
// origin of |desks_bar_bounds| to the origin of |shrink_bounds|. It's
// used to determine the size of the dragged item when it's within
// |shrink_bounds|.
gfx::RectF desks_bar_bounds;
gfx::RectF shrink_bounds;
gfx::Vector2dF shrink_region_distance;
};
base::flat_map<OverviewGrid*, GridDesksBarData> per_grid_desks_bar_data_;
const size_t display_count_;
// Indicates touch dragging, as opposed to mouse dragging. The drag-to-close
// mode is only allowed when |is_touch_dragging_| is true.
const bool is_touch_dragging_;
// True if the `item_` can be snapped by dragging.
const bool is_eligible_for_drag_to_snap_;
// True if the Virtual Desks bar is created and dragging to desks is enabled.
const bool virtual_desks_bar_enabled_;
// The opacity of |item_| changes if we are in drag to close mode. Store the
// original opacity of |item_| and restore it to the item when we leave drag
// to close mode.
float original_opacity_ = 1.f;
// Set to true once the bounds of |item_| change.
bool did_move_ = false;
// Records the presentation time of window drag operation in overview mode.
std::unique_ptr<ui::PresentationTimeRecorder> presentation_time_recorder_;
SnapPosition snap_position_ = SnapPosition::kNone;
std::optional<OverviewController::ScopedOcclusionPauser> occlusion_pauser_;
// A timer used to scale up the new desk button to make it a drop target for
// the window being dragged if the window is hovered on the button over a
// period of time.
base::OneShotTimer new_desk_button_scale_up_timer_;
};
} // namespace ash
#endif // ASH_WM_OVERVIEW_OVERVIEW_WINDOW_DRAG_CONTROLLER_H_