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

ash / wm / window_cycle / window_cycle_list.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_WINDOW_CYCLE_WINDOW_CYCLE_LIST_H_
#define ASH_WM_WINDOW_CYCLE_WINDOW_CYCLE_LIST_H_

#include <memory>
#include <vector>

#include "ash/ash_export.h"
#include "ash/wm/window_cycle/window_cycle_controller.h"
#include "base/memory/raw_ptr.h"
#include "base/timer/timer.h"
#include "ui/aura/window_observer.h"
#include "ui/display/display_observer.h"
#include "ui/events/event.h"

namespace aura {
class ScopedWindowTargeter;
class Window;
}  // namespace aura

namespace views {
class Widget;
}  // namespace views

namespace ash {

class WindowCycleView;

using WindowCyclingDirection = WindowCycleController::WindowCyclingDirection;

// Tracks a set of Windows that can be stepped through. This class is used by
// the WindowCycleController.
class ASH_EXPORT WindowCycleList : public aura::WindowObserver,
                                   public display::DisplayObserver {
 public:
  using WindowList = std::vector<raw_ptr<aura::Window, VectorExperimental>>;

  WindowCycleList(const WindowList& windows, bool same_app_only);
  WindowCycleList(const WindowCycleList&) = delete;
  WindowCycleList& operator=(const WindowCycleList&) = delete;
  ~WindowCycleList() override;

  void set_user_did_accept(bool user_did_accept) {
    user_did_accept_ = user_did_accept;
  }

  bool same_app_only() const { return same_app_only_; }

  const WindowCycleView* cycle_view() const { return cycle_view_; }

  // Returns the |target_window_| from |cycle_view_|.
  aura::Window* GetTargetWindow();

  // Removes the existing windows and replaces them with |windows|. If
  // |windows| is empty, cancels cycling.
  void ReplaceWindows(const WindowList& windows);

  // Cycles to the next or previous window based on |direction| or to the
  // default position if |starting_alt_tab_or_switching_mode| is true.
  // This moves the focus ring and also scrolls the list.
  // If |starting_alt_tab_or_switching_mode| is true and |direction| is
  // forward, the focus ring moves to the first non-active window in MRU list:
  // the second window by default or the first window if it is not active.
  void Step(WindowCyclingDirection direction,
            bool starting_alt_tab_or_switching_mode);

  // Should be called when a user drags their finger on the touch screen.
  // Translates the mirror container by |delta_x|.
  void Drag(float delta_x);

  // Beings a fling with initial velocity of |velocity_x|.
  void StartFling(float velocity_x);

  // Moves the focus ring to the respective preview for |window|. Does not
  // scroll the window cycle list.
  void SetFocusedWindow(aura::Window* window);

  // Moves the focus to the tab slider or the window cycle list based on
  // |focus| value during keyboard navigation.
  void SetFocusTabSlider(bool focus);

  // Returns true if during keyboard navigation, alt-tab focuses the tab slider
  // instead of cycle window.
  bool IsTabSliderFocused() const;

  // Checks whether |event| occurs within the cycle view. Returns false if
  // |cycle_view_| does not exist.
  bool IsEventInCycleView(const ui::LocatedEvent* event) const;

  // Returns the window for the preview item located at |event|. Returns nullptr
  // if |event| not in cycle view or if |cycle_view_| does not exist.
  aura::Window* GetWindowAtPoint(const ui::LocatedEvent* event);

  // Returns whether or not the event is located in tab slider container.
  bool IsEventInTabSliderContainer(const ui::LocatedEvent* event) const;

  // Returns true if the window list overlay should be shown.
  bool ShouldShowUi() const;

  // Updates the tab slider mode UI when alt-tab mode in user prefs changes.
  void OnModePrefsChanged();

  static void SetDisableInitialDelayForTesting(bool disabled);

  const WindowList& windows_for_testing() const { return windows_; }

 private:
  friend class ModeSelectionWindowCycleControllerTest;
  friend class MultiUserWindowCycleControllerTest;
  friend class WindowCycleListTestApi;
  friend class WindowCycleControllerTest;

  // Returns true if the given `window` is in a snap group and we need to step
  // twice to get to the next window cycle item.
  bool ShouldDoubleCycleStep(aura::Window* window,
                             WindowCyclingDirection direction) const;

  // aura::WindowObserver:
  // There is a chance a window is destroyed, for example by JS code. We need to
  // take care of that even if it is not intended for the user to close a window
  // while window cycling.
  void OnWindowDestroying(aura::Window* window) override;

  // display::DisplayObserver:
  void OnDisplayMetricsChanged(const display::Display& display,
                               uint32_t changed_metrics) override;

  // Removes all windows from the window list. Also removes the windows from
  // |cycle_view_| if |cycle_view_| exists.
  void RemoveAllWindows();

  // Initializes and shows |cycle_view_|.
  void InitWindowCycleView();

  // Selects a window, which either activates it or expands it in the case of
  // PIP.
  void SelectWindow(aura::Window* window);

  // Scrolls windows by |offset|. Does not move the focus ring. If you want to
  // scroll the list and move the focus ring in one animation, call
  // SetFocusedWindow() before this.
  void Scroll(int offset);

  // Removes windows from `windows_` if they don't have the same app id as the
  // MRU window.
  void MakeSameAppOnly();

  // Returns the index for the window |offset| away from |current_index_|. Can
  // only be called if |windows_| is not empty. Also checks that the window for
  // the returned index exists.
  int GetOffsettedWindowIndex(int offset) const;

  // Returns the index for |window| in |windows_|. |window| must be in
  // |windows_|.
  int GetIndexOfWindow(aura::Window* window) const;

  // Returns the number of windows in the window cycle list for all desks.
  int GetNumberOfWindowsAllDesks() const;

  // Computes and reports the number of non-same-app windows skipped metric if
  // `same_app_only_`. This must be called from the destructor before the call
  // to `SelectWindow()` as it relies on the previous state of the MRU list.
  void MaybeReportNonSameAppSkippedWindows(aura::Window* target_window) const;

  // List of weak pointers to windows to use while cycling with the keyboard.
  // List is built when the user initiates the gesture (i.e. hits alt-tab the
  // first time) and is emptied when the gesture is complete (i.e. releases the
  // alt key).
  WindowList windows_;

  // Current position in the |windows_|. Can be used to query selection depth,
  // i.e., the position of an active window in a global MRU ordering.
  int current_index_ = 0;

  // True if the user accepted the window switch (as opposed to cancelling or
  // interrupting the interaction).
  bool user_did_accept_ = false;

  // True if one of the windows in the list has already been selected.
  bool window_selected_ = false;

  // True if we are only cycling through windows of the same app.
  const bool same_app_only_;

  // The top level View for the window cycle UI. May be null if the UI is not
  // showing.
  raw_ptr<WindowCycleView> cycle_view_ = nullptr;

  // The widget that hosts the window cycle UI.
  raw_ptr<views::Widget> cycle_ui_widget_ = nullptr;

  // The window list will dismiss if the display metrics change.
  display::ScopedDisplayObserver display_observer_{this};

  // A timer to delay showing the UI. Quick Alt+Tab should not flash a UI.
  base::OneShotTimer show_ui_timer_;

  // This is needed so that it won't leak keyboard events even if the widget is
  // not activatable.
  std::unique_ptr<aura::ScopedWindowTargeter> window_targeter_;

  // Tracks what window was active when starting to cycle and used to determine
  // if alt-tab should focus the first or the second window in the list.
  raw_ptr<aura::Window> active_window_before_window_cycle_ = nullptr;

  // The most recent direction `Step()` was called with.
  WindowCyclingDirection last_cycling_direction_;
};

}  // namespace ash

#endif  // ASH_WM_WINDOW_CYCLE_WINDOW_CYCLE_LIST_H_