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
|
// 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:
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;
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, ExperimentalAsh> 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::WeakPtrFactory<ScopedWindowTucker> weak_factory_{this};
};
} // namespace ash
#endif // ASH_WM_SCOPED_WINDOW_TUCKER_H_
|