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
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223

ash / wm / tablet_mode / tablet_mode_window_manager.h [blame]

// 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_TABLET_MODE_TABLET_MODE_WINDOW_MANAGER_H_
#define ASH_WM_TABLET_MODE_TABLET_MODE_WINDOW_MANAGER_H_

#include <stdint.h>

#include <map>
#include <unordered_set>
#include <utility>
#include <vector>

#include "ash/ash_export.h"
#include "ash/public/cpp/session/session_observer.h"
#include "ash/wm/mru_window_tracker.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/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "ui/aura/window_observer.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/display/display_observer.h"

namespace aura {
class Window;
}

namespace ash {
class TabletModeController;
class TabletModeMultitaskMenuController;
class TabletModeToggleFullscreenEventHandler;
class TabletModeWindowState;

// A window manager which - when created - will force all windows into maximized
// mode. Exception are panels and windows which cannot be maximized.
// Windows which cannot be maximized / resized are centered with a layer placed
// behind the window so that no other windows are visible and/or obscured.
// With the destruction of the manager all windows will be restored to their
// original state.
class ASH_EXPORT TabletModeWindowManager : public aura::WindowObserver,
                                           public display::DisplayObserver,
                                           public OverviewObserver,
                                           public SplitViewObserver,
                                           public SessionObserver {
 public:
  // There are two reasons that we would destroy `this`.
  enum class ShutdownReason {
    kSystemShutdown,
    kExitTabletUIMode,
  };

  // This should only be created or deleted by the creator
  // (TabletModeController).
  TabletModeWindowManager();

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

  ~TabletModeWindowManager() override;

  TabletModeMultitaskMenuController* tablet_mode_multitask_menu_controller() {
    return tablet_mode_multitask_menu_controller_.get();
  }

  void Init();

  // Stops tracking windows and returns them to their clamshell mode state. Work
  // is done here instead of the destructor because TabletModeController may
  // still need this object alive during shutdown.
  void Shutdown(ShutdownReason shutdown_reason);

  // True if |window| is in |window_state_map_|.
  bool IsTrackingWindow(aura::Window* window);

  // Returns the number of maximized & tracked windows by this manager.
  int GetNumberOfManagedWindows();

  // Adds a window which needs to be maximized. This is used by other window
  // managers for windows which needs to get tracked due to (upcoming) state
  // changes.
  // The call gets ignored if the window was already or should not be handled.
  void AddWindow(aura::Window* window);

  // Called from a window state object when it gets destroyed.
  void WindowStateDestroyed(aura::Window* window);

  // Tell all managing windows not to handle WM events.
  void SetIgnoreWmEventsForExit();

  // Stops animations on windows managed by this TabletModeWindowManager.
  void StopWindowAnimations();

  // OverviewObserver:
  void OnOverviewModeEndingAnimationComplete(bool canceled) override;

  // SplitViewObserver:
  void OnSplitViewStateChanged(SplitViewController::State previous_state,
                               SplitViewController::State state) override;

  // aura::WindowObserver:
  void OnWindowDestroying(aura::Window* window) override;
  void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override;
  void OnWindowPropertyChanged(aura::Window* window,
                               const void* key,
                               intptr_t old) override;
  void OnWindowBoundsChanged(aura::Window* window,
                             const gfx::Rect& old_bounds,
                             const gfx::Rect& new_bounds,
                             ui::PropertyChangeReason reason) override;
  void OnWindowVisibilityChanged(aura::Window* window, bool visible) override;

  // display::DisplayObserver:
  void OnDisplayAdded(const display::Display& display) override;
  void OnDisplaysRemoved(const display::Displays& removed_displays) override;

  // SessionObserver:
  void OnActiveUserSessionChanged(const AccountId& account_id) override;

 private:
  using WindowToState =
      std::map<aura::Window*, raw_ptr<TabletModeWindowState, CtnExperimental>>;
  using WindowAndStateTypeList =
      std::vector<std::pair<aura::Window*, chromeos::WindowStateType>>;

  // If |from_clamshell| is true, returns the bounds or state type that |window|
  // had before tablet mode started. If |from_clamshell| is false, returns the
  // current bounds or state type of |window|.
  gfx::Rect GetWindowBoundsInScreen(aura::Window* window,
                                    bool from_clamshell) const;
  chromeos::WindowStateType GetWindowStateType(aura::Window* window,
                                               bool from_clamshell) const;

  // Returns the windows that are going to be carried over to split view during
  // clamshell <-> tablet transition or multi-user switch transition.
  std::vector<std::pair<aura::Window*, chromeos::WindowStateType>>
  GetCarryOverWindowsInSplitView(bool clamshell_to_tablet) const;

  // Calculates the split view divider position that will best preserve the
  // bounds of the windows.
  int CalculateCarryOverDividerPosition(
      const WindowAndStateTypeList& windows_in_splitview,
      bool clamshell_to_tablet) const;

  // Maximizes all windows, except that snapped windows shall carry over to
  // split view as determined by GetCarryOverWindowsInSplitView().
  void ArrangeWindowsForTabletMode();

  // Reverts all windows to how they were arranged before tablet mode.
  // |windows_in_splitview| contains the windows that were in splitview before
  // entering clamshell mode, and if clamshell split view is enabled, these
  // windows will be carried over to clamshell split view. |was_in_overview|
  // indicates whether overview is active before entering clamshell mode.
  void ArrangeWindowsForClamshellMode(
      WindowAndStateTypeList windows_in_splitview,
      bool was_in_overview);

  // If the given window should be handled by us, this function will add it to
  // the list of known windows (remembering the initial show state).
  // Note: If the given window cannot be handled by us the function will return
  // immediately.
  void TrackWindow(aura::Window* window,
                   bool entering_tablet_mode = false,
                   bool snap = false,
                   bool animate_bounds_on_attach = true);

  // Removes a window from our tracking list. |was_in_overview| used when
  // |destroyed| is false to help handle leaving tablet mode. If the window is
  // going to be destroyed, do not restore its old previous window state object
  // as it will send unnecessary window state change event.
  void ForgetWindow(aura::Window* window,
                    bool destroyed,
                    bool was_in_overview = false);

  // Returns true when the given window should be modified in any way by us.
  bool ShouldHandleWindow(aura::Window* window);

  // Add window creation observers to track creation of new windows.
  void AddWindowCreationObservers();

  // Remove Window creation observers.
  void RemoveWindowCreationObservers();

  // Change the internal state (e.g. observers) when the display configuration
  // changes.
  void DisplayConfigurationChanged();

  // Returns true when the |window| is a container window.
  bool IsContainerWindow(aura::Window* window);

  // Every window which got touched by our window manager gets added here.
  WindowToState window_state_map_;

  // All container windows which have to be tracked.
  std::unordered_set<raw_ptr<aura::Window, CtnExperimental>>
      observed_container_windows_;

  // Windows added to the container, but not yet shown or tracked. They will be
  // attempted to be tracked when the window is shown.
  std::unordered_set<raw_ptr<aura::Window, CtnExperimental>> windows_to_track_;

  // All accounts that have been active at least once since tablet mode started.
  base::flat_set<AccountId> accounts_since_entering_tablet_;

  std::unique_ptr<TabletModeToggleFullscreenEventHandler> event_handler_;

  // Handles gestures that may show or hide the multitask menu.
  std::unique_ptr<TabletModeMultitaskMenuController>
      tablet_mode_multitask_menu_controller_;

  std::optional<display::ScopedDisplayObserver> display_observer_;

  // True when tablet mode is about to end.
  bool is_exiting_ = false;

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

}  // namespace ash

#endif  // ASH_WM_TABLET_MODE_TABLET_MODE_WINDOW_MANAGER_H_