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
ash / wm / workspace / multi_window_resize_controller.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_MULTI_WINDOW_RESIZE_CONTROLLER_H_
#define ASH_WM_WORKSPACE_MULTI_WINDOW_RESIZE_CONTROLLER_H_
#include <memory>
#include <vector>
#include "ash/ash_export.h"
#include "ash/wm/overview/overview_observer.h"
#include "ash/wm/window_state.h"
#include "ash/wm/window_state_observer.h"
#include "base/memory/raw_ptr.h"
#include "base/scoped_multi_source_observation.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "ui/aura/window_observer.h"
#include "ui/views/mouse_watcher.h"
namespace aura {
class Window;
} // namespace aura
namespace gfx {
class PointF;
class Rect;
} // namespace gfx
namespace views {
class Widget;
} // namespace views
namespace ash {
class MultiWindowResizeControllerTest;
class WorkspaceWindowResizer;
// MultiWindowResizeController is responsible for determining and showing a
// widget that allows resizing multiple windows at the same time.
// MultiWindowResizeController is driven by WorkspaceEventHandler.
class ASH_EXPORT MultiWindowResizeController
: public views::MouseWatcherListener,
public aura::WindowObserver,
public WindowStateObserver,
public OverviewObserver {
public:
// Delay before showing the `resize_widget_`.
static constexpr base::TimeDelta kShowDelay = base::Milliseconds(400);
MultiWindowResizeController();
MultiWindowResizeController(const MultiWindowResizeController&) = delete;
MultiWindowResizeController& operator=(const MultiWindowResizeController&) =
delete;
~MultiWindowResizeController() override;
// If necessary, shows the resize widget. |window| is the window the mouse
// is over, |component| the edge and |point| the location of the mouse.
void Show(aura::Window* window, int component, const gfx::Point& point);
// MouseWatcherListener:
void MouseMovedOutOfHost() override;
// WindowObserver:
void OnWindowPropertyChanged(aura::Window* window,
const void* key,
intptr_t old) override;
void OnWindowVisibilityChanged(aura::Window* window, bool visible) override;
void OnWindowDestroying(aura::Window* window) override;
// WindowStateObserver:
void OnPostWindowStateTypeChange(WindowState* window_state,
chromeos::WindowStateType old_type) override;
// OverviewObserver:
void OnOverviewModeStarting() override;
void OnOverviewModeEndingAnimationComplete(bool canceled) override;
private:
friend class MultiWindowResizeControllerTest;
friend class SnapGroupTest;
class ResizeMouseWatcherHost;
class ResizeView;
// Two directions resizes happen in.
enum class Direction {
kTopBottom,
kLeftRight,
};
// Used to track the two resizable windows and direction.
struct ResizeWindows {
ResizeWindows();
ResizeWindows(const ResizeWindows& other);
~ResizeWindows();
// Returns true if |other| equals this ResizeWindows. This does *not*
// consider the windows in |other_windows|.
bool Equals(const ResizeWindows& other) const;
// Returns true if this ResizeWindows is valid.
bool is_valid() const { return window1 && window2; }
// The left/top window to resize.
raw_ptr<aura::Window> window1 = nullptr;
// Other window to resize.
raw_ptr<aura::Window> window2 = nullptr;
// Direction
Direction direction;
// Windows after |window2| that are to be resized. Determined at the time
// the resize starts.
std::vector<raw_ptr<aura::Window, VectorExperimental>> other_windows;
};
void CreateMouseWatcher();
// Returns a ResizeWindows based on the specified arguments. Use is_valid()
// to test if the return value is a valid multi window resize location.
ResizeWindows DetermineWindows(aura::Window* window,
int window_component,
const gfx::Point& point) const;
// Variant of DetermineWindows() that uses the current location of the mouse
// to determine the resize windows.
ResizeWindows DetermineWindowsFromScreenPoint(aura::Window* window) const;
// Finds a window by edge (one of the constants HitTestCompat.
aura::Window* FindWindowByEdge(aura::Window* window_to_ignore,
int edge_want,
int x_in_parent,
int y_in_parent) const;
// Returns the first window touching `window`.
aura::Window* FindWindowTouching(aura::Window* window,
Direction direction) const;
// Places any windows touching `start` into `others`.
void FindWindowsTouching(
aura::Window* start,
Direction direction,
std::vector<raw_ptr<aura::Window, VectorExperimental>>* others) const;
// Starts/Stops observing `window`.
void StartObserving(aura::Window* window);
void StopObserving(aura::Window* window);
// Check if we're observing `window`.
bool IsObserving(aura::Window* window) const;
// Shows the resizer if the mouse is still at a valid location. This is called
// from the `show_timer_`.
void ShowIfValidMouseLocation();
// Shows the `resize_widget_` immediately.
void ShowNow();
// Returns true if the `resize_widget_` is showing.
bool IsShowing() const;
// Hides the `resize_widget_` if it gets created.
void Hide();
// Resets the window resizer and hides the widget.
void ResetResizer();
// Initiates a resize.
void StartResize(const gfx::PointF& location_in_screen);
// Resizes to the new location.
void Resize(const gfx::PointF& location_in_screen, int event_flags);
// Completes the resize.
void CompleteResize();
// Cancels the resize.
void CancelResize();
// Returns the bounds for the resize widget.
gfx::Rect CalculateResizeWidgetBounds(
const gfx::PointF& location_in_parent) const;
// Returns true if `location_in_screen` is over the resize widget.
bool IsOverResizeWidget(const gfx::Point& location_in_screen) const;
// Returns true if `location_in_screen` is over the resize windows
// (or the resize widget itself).
bool IsOverWindows(const gfx::Point& location_in_screen) const;
// Returns true if |location_in_screen| is over |component| in |window|.
bool IsOverComponent(aura::Window* window,
const gfx::Point& location_in_screen,
int component) const;
// Windows and direction to resize.
ResizeWindows windows_;
// Timer used before showing.
base::OneShotTimer show_timer_;
std::unique_ptr<views::Widget> resize_widget_;
// If non-null we're in a resize loop.
std::unique_ptr<WorkspaceWindowResizer> window_resizer_;
// Mouse coordinate passed to Show() in container's coodinates.
gfx::Point show_location_in_parent_;
// Bounds the resize widget was last shown at in screen coordinates.
gfx::Rect resize_widget_show_bounds_in_screen_;
// Used to detect whether the mouse is over the windows. While
// |resize_widget_| is non-NULL (ie the widget is showing) we ignore calls
// to Show().
std::unique_ptr<views::MouseWatcher> mouse_watcher_;
base::ScopedMultiSourceObservation<aura::Window, aura::WindowObserver>
window_observations_{this};
base::ScopedMultiSourceObservation<WindowState, WindowStateObserver>
window_state_observations_{this};
};
} // namespace ash
#endif // ASH_WM_WORKSPACE_MULTI_WINDOW_RESIZE_CONTROLLER_H_