chromium/ash/wm/overview/overview_item.h

// Copyright 2013 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_OVERVIEW_OVERVIEW_ITEM_H_
#define ASH_WM_OVERVIEW_OVERVIEW_ITEM_H_

#include <memory>

#include "ash/ash_export.h"
#include "ash/wm/overview/event_handler_delegate.h"
#include "ash/wm/overview/overview_item_base.h"
#include "ash/wm/overview/scoped_overview_transform_window.h"
#include "ash/wm/window_state_observer.h"
#include "base/cancelable_callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "ui/aura/scoped_window_event_targeting_blocker.h"
#include "ui/aura/window_observer.h"
#include "ui/aura/window_occlusion_tracker.h"
#include "ui/wm/core/scoped_animation_disabler.h"

namespace aura {
class Window;
}  // namespace aura

namespace gfx {
class Rect;
class RectF;
}  // namespace gfx

namespace ash {
class DragWindowController;
class OverviewGrid;
class OverviewItemView;
class OverviewSession;

// This class implements `OverviewItemBase` and represents a single window in
// overview mode. It handles placing the window in the correct bounds given by
// `OverviewGrid`, and owns a widget which contains an item's overview specific
// ui (title, icon, close button, etc.).
class ASH_EXPORT OverviewItem : public OverviewItemBase,
                                public aura::WindowObserver,
                                public WindowStateObserver {
 public:
  // Defines an interface for the deletage to `OverviewItem`, which will be
  // notified on the observed window represented by the overview item being
  // destroyed.
  class WindowDestructionDelegate {
   public:
    // Called when the observed window represented by the `overview_item` is
    // being destroyed. `reposition` is true if the overview item needs to be
    // repositioned and the grid bounds need to be updated.
    virtual void OnOverviewItemWindowDestroying(OverviewItem* overview_item,
                                                bool reposition) = 0;

   protected:
    virtual ~WindowDestructionDelegate() = default;
  };

  OverviewItem(aura::Window* window,
               OverviewSession* overview_session,
               OverviewGrid* overview_grid,
               WindowDestructionDelegate* destruction_delegate,
               EventHandlerDelegate* event_handler_delegate,
               bool eligible_for_shadow_config);

  OverviewItem(const OverviewItem&) = delete;
  OverviewItem& operator=(const OverviewItem&) = delete;

  ~OverviewItem() override;

  OverviewItemView* overview_item_view() { return overview_item_view_; }

  void set_eligible_for_shadow_config(bool eligible_for_shadow_config) {
    eligible_for_shadow_config_ = eligible_for_shadow_config;
  }

  // Closes window hosted by `this`.
  void CloseWindow();

  // Handles events forwarded from the contents view.
  void OnFocusedViewActivated();
  void OnFocusedViewClosed();

  // If the window item represents a minimized window, update its contents view.
  void UpdateItemContentViewForMinimizedWindow();

  // Updates the rounded corners on `this` only.
  void UpdateRoundedCorners();

  // Returns the `kTopViewInset` of the `transform_window_`.
  int GetTopInset() const;

  OverviewAnimationType GetExitOverviewAnimationType() const;
  OverviewAnimationType GetExitTransformAnimationType() const;

  // OverviewItemBase:
  void SetOpacity(float opacity) override;
  aura::Window::Windows GetWindowsForHomeGesture() override;
  void HideForSavedDeskLibrary(bool animate) override;
  void RevertHideForSavedDeskLibrary(bool animate) override;
  void UpdateMirrorsForDragging(bool is_touch_dragging) override;
  void DestroyMirrorsForDragging() override;
  aura::Window* GetWindow() override;
  std::vector<raw_ptr<aura::Window, VectorExperimental>> GetWindows() override;
  bool HasVisibleOnAllDesksWindow() override;
  bool Contains(const aura::Window* target) const override;
  OverviewItem* GetLeafItemForWindow(aura::Window* window) override;
  void RestoreWindow(bool reset_transform, bool animate) override;
  void SetBounds(const gfx::RectF& target_bounds,
                 OverviewAnimationType animation_type) override;
  gfx::Transform ComputeTargetTransform(
      const gfx::RectF& target_bounds) override;
  float GetItemScale(int height) override;
  void ScaleUpSelectedItem(OverviewAnimationType animation_type) override;
  void EnsureVisible() override;
  gfx::RectF GetWindowsUnionScreenBounds() const override;
  gfx::RectF GetTargetBoundsWithInsets() const override;
  gfx::RectF GetTransformedBounds() const override;
  std::vector<views::Widget*> GetFocusableWidgets() override;
  views::View* GetBackDropView() const override;
  bool ShouldHaveShadow() const override;
  void UpdateRoundedCornersAndShadow() override;
  float GetOpacity() const override;
  void PrepareForOverview() override;
  void SetShouldUseSpawnAnimation(bool value) override;
  void OnStartingAnimationComplete() override;
  void Restack() override;
  void StartDrag() override;
  void OnOverviewItemDragStarted() override;
  void OnOverviewItemDragEnded(bool snap) override;
  void OnOverviewItemContinuousScroll(const gfx::Transform& target_transform,
                                      float scroll_ratio) override;
  void UpdateCannotSnapWarningVisibility(bool animate) override;
  void HideCannotSnapWarning(bool animate) override;
  void OnMovingItemToAnotherDesk() override;
  void Shutdown() override;
  void AnimateAndCloseItem(bool up) override;
  void StopWidgetAnimation() override;
  OverviewItemFillMode GetOverviewItemFillMode() const override;
  void UpdateOverviewItemFillMode() override;
  const gfx::RoundedCornersF GetRoundedCorners() const override;

  // aura::WindowObserver:
  void OnWindowPropertyChanged(aura::Window* window,
                               const void* key,
                               intptr_t old) override;
  void OnWindowParentChanged(aura::Window* window,
                             aura::Window* parent) override;
  void OnWindowBoundsChanged(aura::Window* window,
                             const gfx::Rect& old_bounds,
                             const gfx::Rect& new_bounds,
                             ui::PropertyChangeReason reason) override;
  void OnWindowStackingChanged(aura::Window* window) override;
  void OnWindowDestroying(aura::Window* window) override;

  // WindowStateObserver:
  void OnPreWindowStateTypeChange(WindowState* window_state,
                                  chromeos::WindowStateType old_type) override;
  void OnPostWindowStateTypeChange(WindowState* window_state,
                                   chromeos::WindowStateType old_type) override;

  DragWindowController* window_mirror_for_dragging_for_testing() {
    return window_mirror_for_dragging_.get();
  }

 private:
  friend class OverviewTestBase;
  friend class ScopedOverviewTransformWindow;
  FRIEND_TEST_ALL_PREFIXES(OverviewSessionTest, DraggingOnMultipleDisplay);
  FRIEND_TEST_ALL_PREFIXES(SplitViewOverviewSessionTest, Clipping);

  // Creates `item_widget_` with `OverviewItemView` as its contents view.
  // `event_handler_delegate` specifies the concrete delegate to handle events,
  // which is `this` by default or the given `event_handler_delegate` if it's
  // not nullptr.
  void CreateItemWidget(EventHandlerDelegate* event_handler_delegate);

  // Functions to be called back when their associated animations complete.
  void OnWindowCloseAnimationCompleted();
  void OnItemSpawnedAnimationCompleted();
  void OnItemBoundsAnimationStarted();
  void OnItemBoundsAnimationEnded();

  // Returns the target that the window of `this` should be stacked below,
  // returns `nullptr` if no stacking is needed.
  aura::Window* GetStackBelowTarget() const;

  // Performs the spawn-item-in-overview animation (which is a fade-in plus
  // scale-up animation), on the given |window|. |target_transform| is the final
  // transform that should be applied to |window| at the end of the animation.
  // |window| is either the real window associated with this item (from
  // GetWindow()), or the `item_widget_->GetNativeWindow()` if the associated
  // window is minimized.
  void PerformItemSpawnedAnimation(aura::Window* window,
                                   const gfx::Transform& target_transform);

  // Sets the bounds of this overview item to |target_bounds| in |root_window_|.
  // The bounds change will be animated as specified by |animation_type|.
  // |is_first_update| is true when we set this item's bounds for the first
  // time.
  void SetItemBounds(const gfx::RectF& target_bounds,
                     OverviewAnimationType animation_type,
                     bool is_first_update);

  // Updates the `item_widget`'s bounds. Any change in bounds will be animated
  // from the current bounds to the new bounds as per the `animation_type`.
  void UpdateHeaderLayout(OverviewAnimationType animation_type);

  // Animates opacity of the |transform_window_| and its caption to |opacity|
  // using |animation_type|.
  void AnimateOpacity(float opacity, OverviewAnimationType animation_type);

  // Returns the type of animation to use for an item that manages a minimized
  // window.
  OverviewAnimationType GetExitOverviewAnimationTypeForMinimizedWindow(
      OverviewEnterExitType type);

  void CloseButtonPressed();

  // The root window this item is being displayed on.
  raw_ptr<aura::Window> root_window_;

  // The contained Window's wrapper.
  ScopedOverviewTransformWindow transform_window_;

  // The delegate to handle window destruction which is `OverviewGrid` for
  // single item or `OverviewGroupItem` for group item.
  const raw_ptr<WindowDestructionDelegate> window_destruction_delegate_;

  // True if running SetItemBounds. This prevents recursive calls resulting from
  // the bounds update when calling ::wm::RecreateWindowLayers to copy
  // a window layer for display on another monitor.
  bool in_bounds_update_ = false;

  // If true, `shadow_` is eligible to be created, false otherwise. The shadow
  // should not be created if `this` is hosted by an `OverviewGroupItem`
  // together with another `OverviewItem` (the group-level shadow will be
  // installed instead). However if a window inside an `OverviewGroupItem` is
  // destroyed, `eligible_for_shadow_config_` is set to true to ensure the
  // shadow bounds get updated correctly.
  bool eligible_for_shadow_config_;

  // The view associated with |item_widget_|. Contains a title, close button and
  // maybe a backdrop. Forwards certain events to |this|.
  raw_ptr<OverviewItemView, DanglingUntriaged> overview_item_view_ = nullptr;

  // Responsible for mirrors that look like the window on all displays during
  // dragging.
  // TODO(sammiequon): We need two, one for the `item_widget_` and one for the
  // source window (if not minimized). If DragWindowController supports multiple
  // windows in the future, combine these.
  std::unique_ptr<DragWindowController> window_mirror_for_dragging_;

  // Disable animations on the contained window while it is being managed by the
  // overview item.
  wm::ScopedAnimationDisabler animation_disabler_;

  // Force `OverviewItem` to be visible while overview is in progress. This is
  // to ensure that overview items are properly marked as visible during all
  // parts of their animation (e.g. overview enter). This is only required
  // if those item's windows won't have snapshots.
  std::optional<aura::WindowOcclusionTracker::ScopedForceVisible>
      scoped_force_visible_;

  base::WeakPtrFactory<OverviewItem> weak_ptr_factory_{this};
};

}  // namespace ash

#endif  // ASH_WM_OVERVIEW_OVERVIEW_ITEM_H_