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
ash / wm / workspace / workspace_window_resizer.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_WORKSPACE_WORKSPACE_WINDOW_RESIZER_H_
#define ASH_WM_WORKSPACE_WORKSPACE_WINDOW_RESIZER_H_
#include <stdint.h>
#include <memory>
#include <vector>
#include "ash/wm/window_resizer.h"
#include "ash/wm/workspace/magnetism_matcher.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "ui/aura/window_tracker.h"
#include "ui/compositor/presentation_time_recorder.h"
#include "ui/display/display.h"
#include "ui/gfx/geometry/point_f.h"
namespace ash {
class WindowSplitter;
class PhantomWindowController;
class WindowSize;
class WindowState;
// WindowResizer implementation for workspaces. This enforces that windows are
// not allowed to vertically move or resize outside of the work area. As windows
// are moved outside the work area they are shrunk. We remember the height of
// the window before it was moved so that if the window is again moved up we
// attempt to restore the old height.
class ASH_EXPORT WorkspaceWindowResizer : public WindowResizer {
public:
// Possible states the window can end up in after a drag is complete.
enum class SnapType { kPrimary, kSecondary, kMaximize, kNone };
// Min height we'll force on screen when dragging the caption.
// TODO: this should come from a property on the window.
static constexpr int kMinOnscreenHeight = 32;
~WorkspaceWindowResizer() override;
static std::unique_ptr<WorkspaceWindowResizer> Create(
WindowState* window_state,
const std::vector<raw_ptr<aura::Window, VectorExperimental>>&
attached_windows);
// WindowResizer:
void Drag(const gfx::PointF& location_in_parent, int event_flags) override;
void CompleteDrag() override;
void RevertDrag() override;
void FlingOrSwipe(ui::GestureEvent* event) override;
private:
friend class WorkspaceWindowResizerTest;
friend class WorkspaceWindowResizerTestApi;
FRIEND_TEST_ALL_PREFIXES(HapticsUtilTest, HapticFeedbackForNormalWindowSnap);
WorkspaceWindowResizer(
WindowState* window_state,
const std::vector<raw_ptr<aura::Window, VectorExperimental>>&
attached_windows);
WorkspaceWindowResizer(const WorkspaceWindowResizer&) = delete;
WorkspaceWindowResizer& operator=(const WorkspaceWindowResizer&) = delete;
// Lays out the attached windows. |bounds| is the bounds of the main window.
void LayoutAttachedWindows(gfx::Rect* bounds);
// Calculates the new sizes of the attached windows, given that the main
// window has been resized (along the primary axis) by |delta|.
// |available_size| is the maximum length of the space that the attached
// windows are allowed to occupy (ie: the distance between the right/bottom
// edge of the primary window and the right/bottom of the desktop area).
// Populates |sizes| with the desired sizes of the attached windows, and
// returns the number of pixels that couldn't be allocated to the attached
// windows (due to min/max size constraints).
// Note the return value can be positive or negative, a negative value
// indicating that that many pixels couldn't be removed from the attached
// windows.
int CalculateAttachedSizes(int delta,
int available_size,
std::vector<int>* sizes) const;
// Divides |amount| evenly between |sizes|. If |amount| is negative it
// indicates how many pixels |sizes| should be shrunk by.
// Returns how many pixels failed to be allocated/removed from |sizes|.
int GrowFairly(int amount, std::vector<WindowSize>* sizes) const;
// Calculate the ratio of pixels that each WindowSize in |sizes| should
// receive when growing or shrinking.
void CalculateGrowthRatios(const std::vector<WindowSize*>& sizes,
std::vector<float>* out_ratios) const;
// Adds a WindowSize to |sizes| for each attached window.
void CreateBucketsForAttached(std::vector<WindowSize>* sizes) const;
// If possible snaps the window to a neary window in |display|. Updates
// |bounds| if there was a close enough window. |display| should be the
// display containing the last event location.
void MagneticallySnapToOtherWindows(const display::Display& display,
gfx::Rect* bounds);
// If possible snaps the resize to a neary window in |display|. Updates
// |bounds| if there was a close enough window. |display| should be the
// display containing the last event location.
void MagneticallySnapResizeToOtherWindows(const display::Display& display,
gfx::Rect* bounds);
// Finds the neareset window in |display| to magentically snap to. Updates
// |magnetism_window_| and |magnetism_edge_| appropriately. |edges| is a
// bitmask of the MagnetismEdges to match again. Returns true if a match is
// found.
bool UpdateMagnetismWindow(const display::Display& display,
const gfx::Rect& bounds,
uint32_t edges);
// Adjusts the bounds of the window: magnetically snapping, ensuring the
// window has enough on screen... |snap_size| is the distance from an edge of
// the work area before the window is snapped. A value of 0 results in no
// snapping.
void AdjustBoundsForMainWindow(int snap_size, gfx::Rect* bounds);
// Stick the window bounds to the work area during a move.
bool StickToWorkAreaOnMove(const gfx::Rect& work_area,
int sticky_size,
gfx::Rect* bounds) const;
// Stick the window bounds to the work area during a resize.
void StickToWorkAreaOnResize(const gfx::Rect& work_area,
int sticky_size,
gfx::Rect* bounds) const;
// Returns a coordinate along the primary axis. Used to share code for
// left/right multi window resize and top/bottom resize.
int PrimaryAxisSize(const gfx::Size& size) const;
int PrimaryAxisCoordinate(int x, int y) const;
// From a given snap |type| and the current |display|, returns true if the
// snap is snap top or maximize. This function is used to decide if we need
// to show the phantom window for top snap or maximize or not.
bool IsSnapTopOrMaximize(SnapType type,
const display::Display& display) const;
// Updates the bounds of the phantom window where the snap bounds are
// calculated from GetSnappedWindowBounds() given a |target_snap_type| and
// maximize bounds is from the current |display|'s full work area.
void UpdateSnapPhantomWindow(const SnapType target_snap_type,
const display::Display& display);
// Restacks the windows z-order position so that one of the windows is at the
// top of the z-order, and the rest directly underneath it.
void RestackWindows();
// Returns the edge to which the window should be snapped to if the user does
// no more dragging. kSnapNone is returned if the window should not be
// snapped, whether it has not been dragged to the correct region, or the
// window does not allow for snapping.
SnapType GetSnapType(const display::Display& display,
const gfx::PointF& location_in_screen) const;
// Returns true if |window| bounds are valid bounds for a snap state and snap
// ratio in |window_state_|.
bool AreBoundsValidSnappedBounds(aura::Window* window) const;
// Sets |window|'s state type to |new_state_type|. Called after the drag has
// been completed for fling/swipe gestures.
void SetWindowStateTypeFromGesture(aura::Window* window,
chromeos::WindowStateType new_state_type);
// Start/End drag for attached windows if there is any.
void StartDragForAttachedWindows();
void EndDragForAttachedWindows(bool revert_drag);
WindowState* window_state() { return window_state_; }
const WindowState* window_state() const { return window_state_; }
// Returns the currently used instance for test.
static WorkspaceWindowResizer* GetInstanceForTest();
const std::vector<raw_ptr<aura::Window, VectorExperimental>>
attached_windows_;
bool did_lock_cursor_ = false;
// Set to true once Drag() is invoked and the bounds of the window change.
bool did_move_or_resize_ = false;
// Tracks whether a window can be maximized depending on distance dragged.
// Set to true when Drag() has a vertical move more than
// kSnapTriggerVerticalMoveThreshold.
bool can_snap_to_maximize_ = false;
// True if the window initially had |bounds_changed_by_user_| set in state.
const bool initial_bounds_changed_by_user_;
// The initial size of each of the windows in |attached_windows_| along the
// primary axis.
std::vector<int> initial_size_;
// Sum of the minimum sizes of the attached windows.
int total_min_ = 0;
// Sum of the sizes in |initial_size_|.
int total_initial_size_ = 0;
// Gives a previews of where the the window will end up. Only used if there
// is a grid and the caption is being dragged.
std::unique_ptr<PhantomWindowController> snap_phantom_window_controller_;
// The edge to which the window should be snapped to at the end of the drag.
SnapType snap_type_ = SnapType::kNone;
// Timer for dwell time countdown.
base::OneShotTimer dwell_countdown_timer_;
// The location for drag maximize in screen.
std::optional<gfx::PointF> dwell_location_in_screen_;
// The latest location passed to `Drag()` in screen coordinates.
gfx::PointF last_location_in_screen_;
// Window the drag has magnetically attached to.
raw_ptr<aura::Window> magnetism_window_ = nullptr;
// Used to verify |magnetism_window_| is still valid.
aura::WindowTracker window_tracker_;
// If |magnetism_window_| is non-NULL this indicates how the two windows
// should attach.
MatchedEdge magnetism_edge_;
// The window bounds when the drag was started. When a window is minimized,
// maximized or snapped via a swipe/fling gesture, the restore bounds should
// be set to the bounds of the window when the drag was started. If the window
// started with restore bounds (snapped/maximized), those will be used
// instead.
gfx::Rect restore_bounds_for_gesture_;
// Presentation time recorder for tab dragging in clamshell mode.
std::unique_ptr<ui::PresentationTimeRecorder> tab_dragging_recorder_;
// Optional window splitter for tiling groups.
std::unique_ptr<WindowSplitter> window_splitter_;
// Used to determine if this has been deleted during a drag such as when a tab
// gets dragged into another browser window.
base::WeakPtrFactory<WorkspaceWindowResizer> weak_ptr_factory_{this};
};
} // namespace ash
#endif // ASH_WM_WORKSPACE_WORKSPACE_WINDOW_RESIZER_H_