chromium/ash/wm/multi_display/persistent_window_controller.h

// Copyright 2018 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_MULTI_DISPLAY_PERSISTENT_WINDOW_CONTROLLER_H_
#define ASH_WM_MULTI_DISPLAY_PERSISTENT_WINDOW_CONTROLLER_H_

#include <unordered_map>

#include "ash/ash_export.h"
#include "ash/public/cpp/session/session_observer.h"
#include "base/containers/flat_map.h"
#include "base/functional/callback.h"
#include "base/scoped_observation.h"
#include "ui/aura/window_observer.h"
#include "ui/display/display_observer.h"
#include "ui/display/manager/display_manager.h"
#include "ui/display/manager/display_manager_observer.h"
#include "ui/gfx/geometry/rect.h"

namespace aura {
class Window;
}  // namespace aura

namespace ash {

// Observes display changes and saves/restores window bounds persistently in
// multi-displays scenario. It will observe and restore window bounds
// persistently on screen rotation as well.
class ASH_EXPORT PersistentWindowController
    : public display::DisplayObserver,
      public SessionObserver,
      public display::DisplayManagerObserver {
 public:
  // This class is used to track a list of windows with their restore bounds in
  // parent. The restore bounds in parent will be empty if it does not exist.
  // When a window is destroyed, it is removed from the list.
  class WindowTracker : public aura::WindowObserver {
   public:
    WindowTracker();

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

    ~WindowTracker() override;

    const base::flat_map<aura::Window*, gfx::Rect>& window_restore_bounds_map()
        const {
      return window_restore_bounds_map_;
    }

    // Adds {window, restore_bounds_in_parent} as a pair to the map. If the
    // `window` is already tracked, it will do nothing.
    void Add(aura::Window* window, const gfx::Rect& restore_bounds_in_parent);

    void RemoveAll();

    // Removes `window` from the map of windows with restore bounds.
    void Remove(aura::Window* window);

    // aura::WindowObserver:
    void OnWindowDestroying(aura::Window* window) override;

   private:
    base::flat_map<aura::Window*, gfx::Rect> window_restore_bounds_map_;
  };

  // Public so it can be used by unit tests.
  constexpr static char kNumOfWindowsRestoredOnDisplayAdded[] =
      "Ash.PersistentWindow.NumOfWindowsRestoredOnDisplayAdded";
  constexpr static char kNumOfWindowsRestoredOnScreenRotation[] =
      "Ash.PersistentWindow.NumOfWindowsRestoredOnScreenRotation";

  PersistentWindowController();
  PersistentWindowController(const PersistentWindowController&) = delete;
  PersistentWindowController& operator=(const PersistentWindowController&) =
      delete;
  ~PersistentWindowController() override;

 private:
  // display::DisplayObserver:
  void OnDisplayAdded(const display::Display& new_display) override;
  void OnWillRemoveDisplays(const display::Displays& removed_displays) override;
  void OnDisplayMetricsChanged(const display::Display& display,
                               uint32_t changed_metrics) override;

  // display::DisplayManagerObserver:
  void OnWillProcessDisplayChanges() override;
  void OnDidProcessDisplayChanges(
      const DisplayConfigurationChange& configuration_change) override;

  // SessionObserver:
  void OnFirstSessionStarted() override;

  // Called when restoring persistent window placement on display added.
  void MaybeRestorePersistentWindowBoundsOnDisplayAdded();

  // Called when restoring persistent window placement on screen rotation.
  void MaybeRestorePersistentWindowBoundsOnScreenRotation();

  // Callback binded on display added and run on display changes are processed.
  base::OnceClosure display_added_restore_callback_;

  // Callback binded on display rotation happens and run on display changes are
  // processed.
  base::OnceClosure screen_rotation_restore_callback_;

  // Temporary storage that stores windows that may need persistent info
  // stored on display removal. Cleared when display changes are processed.
  WindowTracker need_persistent_info_windows_;

  // Tracking the screen orientation of each display before screen rotation
  // take effect. Key is the display id, value is true if the display is in
  // the landscape orientation, otherwise false. This is used to help restore
  // windows' bounds on screen rotation. It is needed since the target rotation
  // already changed even inside OnWillProcessDisplayChanges, which means the
  // screen orientation checked there will be the updated orientation when
  // screen rotation happens. So we get the initial screen orientation
  // OnFirstSessionStarted and store the updated ones inside
  // OnDidProcessDisplayChanges.
  std::unordered_map<int64_t, bool> is_landscape_orientation_map_;

  // Register for DisplayObserver callbacks.
  display::ScopedDisplayObserver display_observer_{this};

  // Register for display configuration changes.
  base::ScopedObservation<display::DisplayManager,
                          display::DisplayManagerObserver>
      display_manager_observation_{this};
};

}  // namespace ash

#endif  // ASH_WM_MULTI_DISPLAY_PERSISTENT_WINDOW_CONTROLLER_H_