// Copyright 2014 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_BACKDROP_CONTROLLER_H_
#define ASH_WM_WORKSPACE_BACKDROP_CONTROLLER_H_
#include <memory>
#include "ash/accessibility/accessibility_observer.h"
#include "ash/ash_export.h"
#include "ash/public/cpp/wallpaper/wallpaper_controller_observer.h"
#include "ash/public/cpp/window_backdrop.h"
#include "ash/public/cpp/window_properties.h"
#include "ash/wm/overview/overview_observer.h"
#include "ash/wm/splitview/split_view_controller.h"
#include "ash/wm/splitview/split_view_observer.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_multi_source_observation.h"
#include "ui/gfx/geometry/rect.h"
namespace aura {
class Window;
} // namespace aura
namespace views {
class Widget;
} // namespace views
namespace ui {
class EventHandler;
} // namespace ui
namespace ash {
// A backdrop which gets created for a container |window| and which gets
// stacked behind the top level, activatable window that meets the following
// criteria.
//
// 1) Has a aura::client::kHasBackdrop property = true.
// 2) Active ARC window when the spoken feedback is enabled.
// 3) In tablet mode:
// - Bottom-most snapped window in splitview,
// - Top-most activatable window if splitview is inactive.
class ASH_EXPORT BackdropController : public AccessibilityObserver,
public OverviewObserver,
public SplitViewObserver,
public WallpaperControllerObserver,
public WindowBackdrop::Observer {
public:
explicit BackdropController(aura::Window* container);
BackdropController(const BackdropController&) = delete;
BackdropController& operator=(const BackdropController&) = delete;
~BackdropController() override;
void OnWindowAddedToLayout(aura::Window* window);
void OnWindowRemovedFromLayout(aura::Window* window);
void OnChildWindowVisibilityChanged(aura::Window* window);
void OnWindowStackingChanged(aura::Window* window);
void OnPostWindowStateTypeChange(aura::Window* window);
void OnDisplayMetricsChanged();
void OnTabletModeChanged();
// Called when the desk content is changed in order to update the state of the
// backdrop even if overview mode is active.
void OnDeskContentChanged();
// Update the visibility of, and restack the backdrop relative to
// the other windows in the container.
void UpdateBackdrop();
// Pauses backdrop updates until the returned object goes out of scope.
base::ScopedClosureRunner PauseUpdates();
// Returns the current visible top level window in the container.
aura::Window* GetTopmostWindowWithBackdrop();
// Hides the backdrop window for taking the informed restore screenshot in
// order to not include it in the screenshot.
void HideOnTakingInformedRestoreScreenshot();
aura::Window* backdrop_window() { return backdrop_window_; }
aura::Window* window_having_backdrop() { return window_having_backdrop_; }
// OverviewObserver:
void OnOverviewModeStarting() override;
void OnOverviewModeEnding(OverviewSession* overview_session) override;
void OnOverviewModeEndingAnimationComplete(bool canceled) override;
// AccessibilityObserver:
void OnAccessibilityStatusChanged() override;
// SplitViewObserver:
void OnSplitViewStateChanged(SplitViewController::State previous_state,
SplitViewController::State state) override;
void OnSplitViewDividerPositionChanged() override;
// WallpaperControllerObserver:
void OnWallpaperPreviewStarted() override;
// WindowBackdrop::Observer:
void OnWindowBackdropPropertyChanged(aura::Window* window) override;
private:
class WindowAnimationWaiter;
friend class WorkspaceControllerTestApi;
// Reenables updates previously pause by calling PauseUpdates().
void RestoreUpdates();
void UpdateBackdropInternal();
void EnsureBackdropWidget();
void UpdateAccessibilityMode();
void Layout();
bool WindowShouldHaveBackdrop(aura::Window* window);
// Show the backdrop window if the |window_having_backdrop_| is not animating,
// otherwise it will wait for that animation to finish. If it can show the
// backdrop, it will update its bounds and stacking order before its shown.
void Show();
// Hide the backdrop window. If |destroy| is true, the backdrop widget will be
// destroyed, otherwise it'll be just hidden.
void Hide(bool destroy, bool animate = true);
// Returns true if the backdrop window should be fullscreen. It should not be
// fullscreen only if 1) split view is active and 2) there is only one snapped
// window and 3) the snapped window is the topmost window which should have
// the backdrop.
bool BackdropShouldFullscreen();
// Gets the bounds for the backdrop window if it should not be fullscreen.
// It's the case for splitview mode, if there is only one snapped window, the
// backdrop should not cover the non-snapped side of the screen, thus the
// backdrop bounds should be the bounds of the snapped window.
gfx::Rect GetBackdropBounds();
// If |window_having_backdrop_| is animating such that we shouldn't update the
// backdrop until that animation is complete, starts observing this animation
// (if not already done) and returns true. Returns false otherwise.
bool MaybeWaitForWindowAnimation();
// Updates the layout of the backdrop if one exists and is visible.
void MaybeUpdateLayout();
// Returns true if changes to |window| may require updating the backdrop
// visibility and availability.
bool DoesWindowCauseBackdropUpdates(aura::Window* window) const;
raw_ptr<aura::Window> root_window_;
// The backdrop which covers the rest of the screen.
std::unique_ptr<views::Widget> backdrop_;
// aura::Window for |backdrop_|.
raw_ptr<aura::Window, DanglingUntriaged> backdrop_window_ = nullptr;
// The window for which a backdrop has been installed.
raw_ptr<aura::Window, DanglingUntriaged> window_having_backdrop_ = nullptr;
// The container of the window that should have a backdrop.
raw_ptr<aura::Window> container_;
// If |window_having_backdrop_| is animating while we're trying to show the
// backdrop, we postpone showing it until the animation completes.
std::unique_ptr<WindowAnimationWaiter> window_animation_waiter_;
// Event hanlder used to implement actions for accessibility.
std::unique_ptr<ui::EventHandler> backdrop_event_handler_;
raw_ptr<ui::EventHandler, DanglingUntriaged> original_event_handler_ =
nullptr;
// If true, skip updating background. Used to avoid recursive update
// when updating the window stack, or delay hiding the backdrop
// in overview mode.
bool pause_update_ = false;
// If true, we're inside the stack of `Hide()`. This is used to avoid
// recursively calling `Hide()` which may lead to destroying the backdrop
// widget while it's still being hidden. https://crbug.com/1368587.
bool is_hiding_backdrop_ = false;
base::ScopedMultiSourceObservation<WindowBackdrop, WindowBackdrop::Observer>
window_backdrop_observations_{this};
base::WeakPtrFactory<BackdropController> weak_ptr_factory_{this};
};
} // namespace ash
#endif // ASH_WM_WORKSPACE_BACKDROP_CONTROLLER_H_