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
ash / wm / scoped_window_tucker.h [blame]
// Copyright 2023 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_SCOPED_WINDOW_TUCKER_H_
#define ASH_WM_SCOPED_WINDOW_TUCKER_H_
#include <memory>
#include "ash/wm/mru_window_tracker.h"
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/overview/overview_observer.h"
#include "ash/wm/window_state.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "ui/aura/scoped_window_event_targeting_blocker.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/widget/unique_widget_ptr.h"
#include "ui/wm/public/activation_change_observer.h"
namespace ash {
constexpr char kTuckUserAction[] = "FloatWindowTucked";
constexpr char kUntuckUserAction[] = "FloatWindowUntucked";
// Scoped class which makes modifications while a window is tucked. It owns a
// tuck handle widget that will bring the hidden window back onscreen. Users of
// the class need to ensure that window outlives instance of this class.
class ScopedWindowTucker : public wm::ActivationChangeObserver,
public OverviewObserver,
public aura::WindowObserver {
public:
static constexpr int kTuckHandleWidth = 20;
static constexpr int kTuckHandleHeight = 92;
class Delegate {
public:
Delegate();
virtual ~Delegate();
// Paint the tuck handle.
virtual void PaintTuckHandle(gfx::Canvas* canvas, int width, bool left) = 0;
// Returns `kContainerIdsToMove` for the parent of the handle widget.
virtual int ParentContainerId() const = 0;
// Updates the position of the window.
virtual void UpdateWindowPosition(aura::Window* window, bool left) = 0;
// Destroys `this_`, which will untuck `window_` and set the window bounds
// back onscreen.
virtual void UntuckWindow(aura::Window* window) = 0;
// Hides the window after the tuck animation is finished. This is so it will
// behave similarly to a minimized window in overview.
virtual void OnAnimateTuckEnded(aura::Window* window) = 0;
// Returns proper bounds for tuck handle.
virtual gfx::Rect GetTuckHandleBounds(
bool left,
const gfx::Rect& window_bounds) const = 0;
base::WeakPtr<Delegate> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
private:
base::WeakPtrFactory<Delegate> weak_ptr_factory_{this};
};
// Represents a tuck handle that untucks floated / PiP windows from offscreen.
class TuckHandleView : public views::Button,
public views::ViewTargeterDelegate {
public:
TuckHandleView(base::WeakPtr<Delegate> delegate,
base::RepeatingClosure callback,
bool left);
TuckHandleView(const TuckHandleView&) = delete;
TuckHandleView& operator=(const TuckHandleView&) = delete;
~TuckHandleView() override;
// views::Button:
void OnThemeChanged() override;
void PaintButtonContents(gfx::Canvas* canvas) override;
void OnGestureEvent(ui::GestureEvent* event) override;
// views::ViewTargeterDelegate:
bool DoesIntersectRect(const views::View* target,
const gfx::Rect& rect) const override;
private:
// The delegate held by `ScopedWindowTucker`.
base::WeakPtr<Delegate> scoped_window_tucker_delegate_;
// Whether the tuck handle is on the left or right edge of the screen. A
// left tuck handle will have the chevron arrow pointing right and vice
// versa.
const bool left_;
};
// Creates an instance for `window` where `left` is the side of the screen
// that the tuck handle is on.
explicit ScopedWindowTucker(std::unique_ptr<Delegate> delegate,
aura::Window* window,
bool left);
ScopedWindowTucker(const ScopedWindowTucker&) = delete;
ScopedWindowTucker& operator=(const ScopedWindowTucker&) = delete;
~ScopedWindowTucker() override;
// Returns the target window the resizer was created for.
aura::Window* window() { return window_; }
// Returns the tuck handle widget that this tucker manages.
views::Widget* tuck_handle_widget() { return tuck_handle_widget_.get(); }
// Returns true if the window is tucked to the left of the screen edge.
bool left() const { return left_; }
// Starts the tucking animation.
void AnimateTuck();
// Starts the untucking animation. Runs `callback` when the animation
// is completed.
void AnimateUntuck(base::OnceClosure callback);
// Runs `delegate`'s `UntuckWindow()`.
void UntuckWindow();
// Runs `delegate`'s `OnAnimateTuckEnded()`.
void OnAnimateTuckEnded();
// wm::ActivationChangeObserver:
void OnWindowActivated(ActivationReason reason,
aura::Window* gained_active,
aura::Window* lost_active) override;
// OverviewObserver:
void OnOverviewModeStarting() override;
void OnOverviewModeEndingAnimationComplete(bool canceled) override;
// aura::WindowObserver:
void OnWindowBoundsChanged(aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds,
ui::PropertyChangeReason reason) override;
private:
// Initializes the tuck handle widget.
void InitializeTuckHandleWidget();
// Slides the tuck handle offscreen and onscreen when entering and exiting
// overview mode respectively.
void OnOverviewModeChanged(bool in_overview);
std::unique_ptr<Delegate> delegate_;
// The window that is being tucked. Will be tucked and untucked by the tuck
// handle.
raw_ptr<aura::Window> window_;
// True if the window is tucked to the left screen edge, false otherwise.
bool left_ = false;
// Blocks events from hitting the window while `this` is alive.
aura::ScopedWindowEventTargetingBlocker event_blocker_;
views::UniqueWidgetPtr tuck_handle_widget_ =
std::make_unique<views::Widget>();
base::ScopedObservation<OverviewController, OverviewObserver>
overview_observer_{this};
base::ScopedObservation<aura::Window, aura::WindowObserver>
window_observation_{this};
base::WeakPtrFactory<ScopedWindowTucker> weak_factory_{this};
};
} // namespace ash
#endif // ASH_WM_SCOPED_WINDOW_TUCKER_H_