blob: e98f8d6c24c213cf8b592e894105781da2e4fe94 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <vector>
#include "ash/ash_export.h"
#include "ash/public/cpp/split_view.h"
#include "ash/shell_observer.h"
#include "ash/wm/overview/scoped_overview_hide_windows.h"
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/time/time.h"
#include "ui/aura/window_observer.h"
#include "ui/display/display_observer.h"
#include "ui/events/event_handler.h"
#include "ui/wm/public/activation_change_observer.h"
namespace gfx {
class Point;
class PointF;
} // namespace gfx
namespace ui {
class KeyEvent;
class ScopedLayerAnimationSettings;
} // namespace ui
namespace views {
class Widget;
} // namespace views
namespace ash {
class OverviewDelegate;
class OverviewGrid;
class OverviewItem;
class OverviewWindowDragController;
class RoundedLabelWidget;
class SplitViewDragIndicators;
enum class IndicatorState;
// The Overview shows a grid of all of your windows, allowing to select
// one by clicking or tapping on it.
class ASH_EXPORT OverviewSession : public display::DisplayObserver,
public aura::WindowObserver,
public ui::EventHandler,
public ShellObserver,
public SplitViewObserver {
enum Direction { LEFT, UP, RIGHT, DOWN };
enum class OverviewTransition {
kEnter, // In the entering process of overview.
kInOverview, // Already in overview.
kExit // In the exiting process of overview.
// Enum describing the different ways overview can be entered or exited.
enum class EnterExitOverviewType {
// The default way, window(s) animate from their initial bounds to the grid
// bounds. Window(s) that are not visible to the user do not get animated.
// This should always be the type when in clamshell mode.
// When going to or from a state which all window(s) are minimized, slides
// the windows in or out. This will minimize windows on exit if needed, so
// that we do not need to add a delayed observer to handle minimizing the
// windows after overview exit animations are finished.
// Overview can be closed by swiping up from the shelf. In this mode, the
// call site will handle shifting the bounds of the windows, so overview
// code does not need to handle any animations. This is an exit only type.
// Overview can be opened by start dragging a window from top or be closed
// if the dragged window restores back to maximized/full-screened. On enter
// this mode is same as kNormal, except when all windows are minimized, the
// launcher does not animate in. On exit this mode is used to avoid the
// update bounds animation of the windows in overview grid on overview mode
// ended.
// Used only when it's desired to exit overview mode immediately without
// animations. This is used when performing the desk switch animation when
// the source desk is in overview mode, while the target desk is not.
// This should not be used for entering overview mode.
// Callback which fills out the passed settings object. Used by several
// functions so different callers can do similar animations with different
// settings.
using UpdateAnimationSettingsCallback =
base::RepeatingCallback<void(ui::ScopedLayerAnimationSettings* settings)>;
using WindowList = std::vector<aura::Window*>;
explicit OverviewSession(OverviewDelegate* delegate);
~OverviewSession() override;
// Initialize with the windows that can be selected.
void Init(const WindowList& windows, const WindowList& hide_windows);
// Perform cleanup that cannot be done in the destructor.
void Shutdown();
// Cancels window selection.
void CancelSelection();
// Called when the last overview item from a grid is deleted.
void OnGridEmpty(OverviewGrid* grid);
// Moves the current selection by |increment| items. Positive values of
// |increment| move the selection forward, negative values move it backward.
void IncrementSelection(int increment);
// Accepts current selection if any. Returns true if a selection was made,
// false otherwise.
bool AcceptSelection();
// Activates |item's| window.
void SelectWindow(OverviewItem* item);
// Updates overview bounds and hides the drop target when a preview area is
// shown. Updates the appearance of the drop target to visually indicate when
// |dragged_window| is being dragged over it.
void RearrangeDuringDrag(aura::Window* dragged_window,
const gfx::PointF& location_in_screen,
IndicatorState indicator_state);
// Called to show or hide the split view drag indicators. This will do
// nothing if split view is not enabled. |event_location| is used to reparent
// |split_view_drag_indicators_|'s widget, if necessary.
void SetSplitViewDragIndicatorsIndicatorState(
IndicatorState indicator_state,
const gfx::Point& event_location);
// Retrieves the window grid whose root window matches |root_window|. Returns
// nullptr if the window grid is not found.
OverviewGrid* GetGridWithRootWindow(aura::Window* root_window);
// Adds |window| at the specified |index| into the grid with the same root
// window. Does nothing if that grid does not exist in |grid_list_| or already
// contains |window|. If |reposition| is true, repositions all items in the
// target grid (unless it already contained |window|), except those in
// |ignored_items|. If |animate| is true, animates the repositioning.
// |animate| has no effect if |reposition| is false.
void AddItem(aura::Window* window,
bool reposition,
bool animate,
const base::flat_set<OverviewItem*>& ignored_items = {},
size_t index = 0);
// Similar to the above function, but adds the window at the end of the grid.
void AppendItem(aura::Window* window, bool reposition, bool animate);
// Removes |overview_item| from the corresponding grid. No items are
// repositioned.
void RemoveItem(OverviewItem* overview_item);
// Adds a drop target that visually appears to be revealed as |dragged_item|
// is dragged off of it.
void AddDropTargetForDraggingFromOverview(OverviewItem* dragged_item);
// Removes the drop target from the grid containing |dragged_item|.
void RemoveDropTargetForDraggingFromOverview(OverviewItem* dragged_item);
void InitiateDrag(OverviewItem* item, const gfx::PointF& location_in_screen);
void Drag(OverviewItem* item, const gfx::PointF& location_in_screen);
void CompleteDrag(OverviewItem* item, const gfx::PointF& location_in_screen);
void StartSplitViewDragMode(const gfx::PointF& location_in_screen);
void Fling(OverviewItem* item,
const gfx::PointF& location_in_screen,
float velocity_x,
float velocity_y);
void ActivateDraggedWindow();
void ResetDraggedWindowGesture();
// Called when a window (either it's browser window or an app window)
// start/continue/end being dragged in tablet mode.
// TODO(xdai): Currently it doesn't work for multi-display scenario.
void OnWindowDragStarted(aura::Window* dragged_window, bool animate);
void OnWindowDragContinued(aura::Window* dragged_window,
const gfx::PointF& location_in_screen,
IndicatorState indicator_state);
void OnWindowDragEnded(aura::Window* dragged_window,
const gfx::PointF& location_in_screen,
bool should_drop_window_into_overview,
bool snap);
// Positions all overview items except those in |ignored_items|.
void PositionWindows(bool animate,
const base::flat_set<OverviewItem*>& ignored_items = {});
// Returns true if |window| is currently showing in overview.
bool IsWindowInOverview(const aura::Window* window);
// Returns the overview item for |window|, or nullptr if |window| doesn't have
// a corresponding item in overview mode.
OverviewItem* GetOverviewItemForWindow(const aura::Window* window);
// Set the window grid that's displaying in |root_window| not animate when
// exiting overview mode, i.e., all window items in the grid will not animate
// when exiting overview mode. It may be called in two cases: 1) When a window
// gets snapped (either from overview or not) and thus cause the end of the
// overview mode, we should not do the exiting animation; 2) When a window
// is dragged around and when released, it causes the end of the overview
// mode, we also should not do the exiting animation.
void SetWindowListNotAnimatedWhenExiting(aura::Window* root_window);
// Shifts and fades the grid in |grid_list_| associated with |location|.
// Returns a ui::ScopedLayerAnimationSettings object for the caller to
// observe.
// TODO(sammiequon): Change |new_y| to use float.
int64_t display_id,
int new_y,
float opacity,
UpdateAnimationSettingsCallback callback);
// Updates all the overview items' mask and shadow.
void UpdateMaskAndShadow();
// Called when the overview mode starting animation completes.
void OnStartingAnimationComplete(bool canceled);
// Called when windows are being activated/deactivated during
// overview mode.
void OnWindowActivating(
::wm::ActivationChangeObserver::ActivationReason reason,
aura::Window* gained_active,
aura::Window* lost_active);
// Gets the window which keeps focus for the duration of overview mode.
aura::Window* GetOverviewFocusWindow();
// Suspends/Resumes window re-positiong in overview.
void SuspendReposition();
void ResumeReposition();
// Returns true if all its window grids don't have any window item.
bool IsEmpty() const;
// display::DisplayObserver:
void OnDisplayRemoved(const display::Display& display) override;
void OnDisplayMetricsChanged(const display::Display& display,
uint32_t metrics) override;
// aura::WindowObserver:
void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override;
void OnWindowDestroying(aura::Window* window) override;
// ShelObserver:
void OnShellDestroying() override;
// ui::EventHandler:
void OnKeyEvent(ui::KeyEvent* event) override;
// SplitViewObserver:
void OnSplitViewStateChanged(SplitViewState previous_state,
SplitViewState state) override;
void OnSplitViewDividerPositionChanged() override;
OverviewDelegate* delegate() { return delegate_; }
bool is_shutting_down() const { return is_shutting_down_; }
void set_is_shutting_down(bool is_shutting_down) {
is_shutting_down_ = is_shutting_down;
SplitViewDragIndicators* split_view_drag_indicators() {
return split_view_drag_indicators_.get();
EnterExitOverviewType enter_exit_overview_type() const {
return enter_exit_overview_type_;
void set_enter_exit_overview_type(EnterExitOverviewType val) {
enter_exit_overview_type_ = val;
OverviewWindowDragController* window_drag_controller() {
return window_drag_controller_.get();
const std::vector<std::unique_ptr<OverviewGrid>>& grid_list_for_testing()
const {
return grid_list_;
size_t num_items_for_testing() const { return num_items_; }
RoundedLabelWidget* no_windows_widget_for_testing() {
return no_windows_widget_.get();
friend class OverviewSessionTest;
// Retrieves the window grid containing |item|.
OverviewGrid* GetGridWithOverviewItem(OverviewItem* item);
// |focus|, restores focus to the stored window.
void ResetFocusRestoreWindow(bool focus);
// Helper function that moves the selection widget to |direction| on the
// corresponding window grid.
void Move(Direction direction, bool animate);
// Removes all observers that were registered during construction and/or
// initialization.
void RemoveAllObservers();
// Called when the display area for the overview window grids changed.
void OnDisplayBoundsChanged();
void MaybeCreateAndPositionNoWindowsWidget();
// Tracks observed windows.
base::flat_set<aura::Window*> observed_windows_;
// Weak pointer to the overview delegate which will be called when a selection
// is made.
OverviewDelegate* delegate_;
// A weak pointer to the window which was focused on beginning window
// selection. If window selection is canceled the focus should be restored to
// this window.
aura::Window* restore_focus_window_ = nullptr;
// A hidden window that receives focus while in overview mode. It is needed
// because accessibility needs something focused for it to work and we cannot
// use one of the overview windows otherwise ::wm::ActivateWindow will not
// work.
// TODO(sammiequon): Investigate if we can focus the |selection_widget_| in
// OverviewGrid when it is created, or if we can focus a widget from the
// virtual desks UI when that is complete, or we may be able to add some
// mechanism to trigger accessibility events without a focused window.
std::unique_ptr<views::Widget> overview_focus_widget_;
// A widget that is shown if we entered overview without any windows opened.
std::unique_ptr<RoundedLabelWidget> no_windows_widget_;
// True when performing operations that may cause window activations. This is
// used to prevent handling the resulting expected activation. This is
// initially true until this is initialized.
bool ignore_activations_ = true;
// True when overview mode is exiting.
bool is_shutting_down_ = false;
// List of all the window overview grids, one for each root window.
std::vector<std::unique_ptr<OverviewGrid>> grid_list_;
// The owner of the widget which displays splitview related information in
// overview mode. This will be nullptr if split view is not enabled.
std::unique_ptr<SplitViewDragIndicators> split_view_drag_indicators_;
// Tracks the index of the root window the selection widget is in.
size_t selected_grid_index_ = 0;
// The following variables are used for metric collection purposes. All of
// them refer to this particular overview session and are not cumulative:
// The time when overview was started.
base::Time overview_start_time_;
// The number of arrow key presses.
size_t num_key_presses_ = 0;
// The number of items in the overview.
size_t num_items_ = 0;
// Stores the overview enter/exit type. See the enum declaration for
// information on how these types affect overview mode.
EnterExitOverviewType enter_exit_overview_type_ =
// The selected item when exiting overview mode. nullptr if no window
// selected.
OverviewItem* selected_item_ = nullptr;
// The drag controller for a window in the overview mode.
std::unique_ptr<OverviewWindowDragController> window_drag_controller_;
std::unique_ptr<ScopedOverviewHideWindows> hide_overview_windows_;
} // namespace ash