Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(888)

Unified Diff: ash/wm/overview/window_overview.cc

Issue 251103005: Added arrow key navigation to Overview Mode (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase with latest changes, test stub (don't look into that yet!) Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ash/wm/overview/window_overview.cc
diff --git a/ash/wm/overview/window_overview.cc b/ash/wm/overview/window_overview.cc
index ec5efc76a6bc8036a206850c48ed95be0ac1607e..d3fc5521ee3e274b707b0704c75b0fbc43f03e71 100644
--- a/ash/wm/overview/window_overview.cc
+++ b/ash/wm/overview/window_overview.cc
@@ -5,6 +5,7 @@
#include "ash/wm/overview/window_overview.h"
#include <algorithm>
+#include <functional>
#include "ash/metrics/user_metrics_recorder.h"
#include "ash/screen_util.h"
@@ -123,10 +124,11 @@ WindowOverview::WindowOverview(WindowSelector* window_selector,
aura::Window* single_root_window)
: window_selector_(window_selector),
windows_(windows),
- selection_index_(0),
+ selected_window_(NULL),
single_root_window_(single_root_window),
overview_start_time_(base::Time::Now()),
cursor_client_(NULL) {
+ main_grid_.root_window = secondary_grid_.root_window = NULL;
tdanderson 2014/04/29 14:46:27 Initialize on two lines instead of one.
Nina 2014/04/29 18:31:40 Done.
Shell* shell = Shell::GetInstance();
shell->OnOverviewModeStarting();
for (WindowSelectorItemList::iterator iter = windows_->begin();
@@ -177,36 +179,27 @@ WindowOverview::~WindowOverview() {
}
void WindowOverview::SetSelection(size_t index) {
- gfx::Rect target_bounds(GetSelectionBounds(index));
+ MoveSelectionWidget((*windows_)[index], NULL);
+}
+
+void WindowOverview::MoveSelectionWidget(WindowSelectorItem* target,
+ gfx::Vector2d* fade_out_direction) {
+ gfx::Rect target_bounds(GetSelectionBounds(target));
+ aura::Window* root_window = target->GetRootWindow();
+ if (selection_widget_ && root_window !=
+ selection_widget_->GetNativeWindow()->GetRootWindow())
+ selection_widget_.reset();
if (selection_widget_) {
// If the selection widget is already active, determine the animation to
// use to animate the widget to the new bounds.
- int change = static_cast<int>(index) - static_cast<int>(selection_index_);
- int windows = static_cast<int>(windows_->size());
- // If moving from the first to the last or last to the first index,
- // convert the delta to be +/- 1.
- if (windows > 2 && abs(change) == windows - 1) {
- if (change < 0)
- change += windows;
- else
- change -= windows;
- }
- if (selection_index_ < windows_->size() &&
- (*windows_)[selection_index_]->target_bounds().y() !=
- (*windows_)[index]->target_bounds().y() &&
- abs(change) == 1) {
- // The selection has changed forward or backwards by one with a change
- // in the height of the target. In this case create a new selection widget
- // to fade in on the new position and animate and fade out the old one.
- gfx::Display dst_display = gfx::Screen::GetScreenFor(
- selection_widget_->GetNativeWindow())->GetDisplayMatching(
- target_bounds);
- gfx::Vector2d fade_out_direction(
- change * ((*windows_)[selection_index_]->target_bounds().width() +
- 2 * kWindowMargin), 0);
- aura::Window* old_selection = selection_widget_->GetNativeWindow();
+ gfx::Display dst_display = gfx::Screen::GetScreenFor(
+ selection_widget_->GetNativeWindow())->GetDisplayMatching(
+ target_bounds);
+ aura::Window* old_selection = selection_widget_->GetNativeWindow();
+ // If a fade out direction is specified, animate the widget accordingly.
+ if (fade_out_direction) {
tdanderson 2014/04/29 14:46:27 Is this check needed? Under which circumstances wo
Nina 2014/04/29 18:31:40 Yes, in alt-tabbing mode (through SetSelection)
// CleanupWidgetAfterAnimationObserver will delete itself (and the
// widget) when the animation is complete.
new CleanupWidgetAfterAnimationObserver(selection_widget_.Pass());
@@ -218,13 +211,13 @@ void WindowOverview::SetSelection(size_t index) {
animation_settings.SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
old_selection->SetBoundsInScreen(
- GetSelectionBounds(selection_index_) + fade_out_direction,
+ GetSelectionBounds(selected_window_) + (*fade_out_direction),
dst_display);
old_selection->Hide();
old_selection->layer()->SetOpacity(0);
- InitializeSelectionWidget();
+ InitializeSelectionWidget(root_window);
selection_widget_->GetNativeWindow()->SetBoundsInScreen(
- target_bounds - fade_out_direction, dst_display);
+ target_bounds - (*fade_out_direction), dst_display);
// New selection widget starts with 0 opacity and fades in.
selection_widget_->GetNativeWindow()->layer()->SetOpacity(0);
}
@@ -238,10 +231,12 @@ void WindowOverview::SetSelection(size_t index) {
selection_widget_->GetNativeWindow()->layer()->SetOpacity(
kWindowOverviewSelectionOpacity);
} else {
- InitializeSelectionWidget();
+ InitializeSelectionWidget(root_window);
selection_widget_->SetBounds(target_bounds);
}
- selection_index_ = index;
+ selected_window_ = target;
+ target->get_window_label()->GetContentsView()->
+ NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true);
}
void WindowOverview::OnWindowsChanged() {
@@ -259,8 +254,35 @@ void WindowOverview::OnKeyEvent(ui::KeyEvent* event) {
if (event->type() != ui::ET_KEY_PRESSED)
return;
- if (event->key_code() == ui::VKEY_ESCAPE)
- window_selector_->CancelSelection();
+ if (!event->IsAltDown() || event->key_code() == ui::VKEY_ESCAPE)
+ switch (event->key_code()) {
+ case ui::VKEY_ESCAPE:
+ event->StopPropagation();
+ window_selector_->CancelSelection();
+ break;
+ case ui::VKEY_RETURN:
+ event->StopPropagation();
+ window_selector_->SelectWindow(selected_window_->SelectionWindow());
+ break;
+ case ui::VKEY_RIGHT:
+ event->StopPropagation();
+ MoveSelector(WindowOverview::RIGHT);
+ break;
+ case ui::VKEY_LEFT:
+ event->StopPropagation();
+ MoveSelector(WindowOverview::LEFT);
+ break;
+ case ui::VKEY_UP:
+ event->StopPropagation();
+ MoveSelector(WindowOverview::UP);
+ break;
+ case ui::VKEY_DOWN:
+ event->StopPropagation();
+ MoveSelector(WindowOverview::DOWN);
+ default:
+ // Not a key we are interested in.
+ break;
+ }
}
void WindowOverview::OnMouseEvent(ui::MouseEvent* event) {
@@ -381,8 +403,11 @@ void WindowOverview::PositionWindows(bool animate) {
PositionWindowsOnRoot(single_root_window_, windows, animate);
} else {
aura::Window::Windows root_window_list = Shell::GetAllRootWindows();
+ secondary_grid_.windows = main_grid_.windows = 0;
tdanderson 2014/04/29 14:46:27 Two lines.
Nina 2014/04/29 18:31:40 Done.
for (size_t i = 0; i < root_window_list.size(); ++i)
PositionWindowsFromRoot(root_window_list[i], animate);
+ if (selection_widget_)
+ ResetSelectionWidget();
}
}
@@ -397,6 +422,34 @@ void WindowOverview::PositionWindowsFromRoot(aura::Window* root_window,
PositionWindowsOnRoot(root_window, windows, animate);
}
+void WindowOverview::ResetSelectionWidget() {
+ bool selected_window_removed = true;
+ for (size_t i = 0; i < windows_->size() && selected_window_removed; ++i) {
tdanderson 2014/04/29 14:46:27 No {} needed since the body of the for loop is a s
Nina 2014/04/29 18:31:40 Done.
+ selected_window_removed = !((windows_->get()[i]) == selected_window_);
+ }
+
+ if (!selected_window_removed) {
+ // If the currently selected window has not been destroyed, move the
+ // selection widget to its new position.
+ MoveSelectionWidget(selected_window_, NULL);
+ } else {
+ if (arrow_cursor_.x == 0 && arrow_cursor_.y == 0) {
+ // If in the top right position, determine whether we should move to the
+ // next display (RIGHT) since there are no windows on the current one, or
+ // select the closest remaining window (NONE).
+ if ((arrow_cursor_.primary_display && main_grid_.windows == 0) ||
+ (!arrow_cursor_.primary_display && secondary_grid_.windows == 0))
+ MoveSelector(WindowOverview::RIGHT);
+ else
+ MoveSelector(WindowOverview::NONE);
+ } else {
+ // The destroyed window had other windows behind it, move to the closest
+ // one.
+ MoveSelector(WindowOverview::LEFT);
+ }
+ }
+}
+
void WindowOverview::PositionWindowsOnRoot(
aura::Window* root_window,
const std::vector<WindowSelectorItem*>& windows,
@@ -404,6 +457,8 @@ void WindowOverview::PositionWindowsOnRoot(
if (windows.empty())
return;
+ WindowGrid grid;
tdanderson 2014/04/29 14:46:27 Declare this right before initialization (line 479
Nina 2014/04/29 18:31:40 Done.
+
gfx::Size window_size;
gfx::Rect total_bounds = ScreenUtil::ConvertRectToScreen(
root_window,
@@ -422,6 +477,12 @@ void WindowOverview::PositionWindowsOnRoot(
static_cast<int>(total_bounds.height() * kCardAspectRatio / rows)));
window_size.set_height(window_size.width() / kCardAspectRatio);
+ for (size_t i = 0; i < columns; ++i) {
+ std::vector<WindowSelectorItem*> inner_vector;
+ grid.window_matrix.push_back(inner_vector);
+ }
+ grid.windows = windows.size();
+
// Calculate the X and Y offsets necessary to center the grid.
int x_offset = total_bounds.x() + ((windows.size() >= columns ? 0 :
(columns - windows.size()) * window_size.width()) +
@@ -438,10 +499,27 @@ void WindowOverview::PositionWindowsOnRoot(
window_size.height());
target_bounds.Inset(kWindowMargin, kWindowMargin);
windows[i]->SetBounds(root_window, target_bounds, animate);
+ grid.window_matrix[column].push_back(windows[i]);
+ }
+
+ grid.root_window = root_window;
+ // Under certain circumstances it is possible that we have more columns than
+ // windows. In this case, trim down the number to simplify movement
+ // calculations.
+ if (columns > windows.size())
+ grid.columns = windows.size();
+ else
+ grid.columns = columns;
+ grid.rows = rows;
+
+ if (!main_grid_.root_window || main_grid_.root_window == grid.root_window) {
+ main_grid_ = grid;
+ } else {
+ secondary_grid_ = grid;
}
}
-void WindowOverview::InitializeSelectionWidget() {
+void WindowOverview::InitializeSelectionWidget(aura::Window* root_window) {
selection_widget_.reset(new views::Widget);
views::Widget::InitParams params;
params.type = views::Widget::InitParams::TYPE_POPUP;
@@ -451,7 +529,7 @@ void WindowOverview::InitializeSelectionWidget() {
params.opacity = views::Widget::InitParams::OPAQUE_WINDOW;
params.parent = Shell::GetContainer(single_root_window_
? single_root_window_
- : windows_->front()->GetRootWindow(),
+ : root_window,
kShellWindowId_DefaultContainer);
params.accept_events = false;
selection_widget_->set_focus_on_creation(false);
@@ -467,11 +545,141 @@ void WindowOverview::InitializeSelectionWidget() {
kWindowOverviewSelectionOpacity);
}
-gfx::Rect WindowOverview::GetSelectionBounds(size_t index) {
- gfx::Rect bounds((*windows_)[index]->bounds());
+void WindowOverview::MoveSelector(Direction direction) {
+ // If we don't have a selection, simply initialize the cursor on the first
+ // window on the primary monitor.
+ if (!selection_widget_) {
+ arrow_cursor_.x = 0;
+ arrow_cursor_.y = 0;
+ arrow_cursor_.primary_display = true;
+ }
+ // The following pointers simplify the movement logic.
+ WindowGrid* current_grid;
+ WindowGrid* other_grid;
+ if (arrow_cursor_.primary_display) {
+ current_grid = &main_grid_;
+ other_grid = &secondary_grid_;
+ } else {
+ current_grid = &secondary_grid_;
+ other_grid = &main_grid_;
+ }
+ if (other_grid->windows == 0)
+ other_grid = current_grid;
+
+ bool old_grid = arrow_cursor_.primary_display;
+
+ gfx::Vector2d fade_direction(0, 0);
+
+ if (selection_widget_) {
+ switch (direction) {
+ case WindowOverview::RIGHT:
+ fade_direction.set_x(1);
+ ++arrow_cursor_.x;
+ if (arrow_cursor_.x >= current_grid->columns ||
tdanderson 2014/04/29 14:46:27 Don't align your boolean operators in this way. Se
Nina 2014/04/29 18:31:40 Done.
+ (arrow_cursor_.y == current_grid->rows - 1 &&
+ current_grid->windows % current_grid->columns != 0 &&
+ arrow_cursor_.x >= current_grid->windows
+ % current_grid->columns)) {
+ arrow_cursor_.x = 0;
+ if (++arrow_cursor_.y >= current_grid->rows) {
+ arrow_cursor_.y = 0;
+ arrow_cursor_.primary_display = !arrow_cursor_.primary_display;
+ }
+ }
+ break;
+ case WindowOverview::LEFT:
+ fade_direction.set_x(-1);
+ if (arrow_cursor_.x == 0) {
+ if (arrow_cursor_.y == 0) {
+ if (other_grid->windows % other_grid->columns == 0)
+ arrow_cursor_.x = other_grid->columns - 1;
+ else
+ arrow_cursor_.x = other_grid->windows % other_grid->columns - 1;
+ arrow_cursor_.y = other_grid->rows - 1;
+ arrow_cursor_.primary_display = !arrow_cursor_.primary_display;
+ } else {
+ arrow_cursor_.x = current_grid->columns - 1;
+ --arrow_cursor_.y;
+ }
+ } else {
+ --arrow_cursor_.x;
+ }
+ break;
+ case WindowOverview::DOWN:
+ fade_direction.set_y(1);
+ ++arrow_cursor_.y;
+ if (arrow_cursor_.y >= current_grid->rows ||
+ (current_grid->windows % current_grid->columns != 0 &&
+ arrow_cursor_.y >= current_grid->rows - 1 &&
+ arrow_cursor_.x >= current_grid->windows % current_grid->columns)) {
+ arrow_cursor_.y = 0;
+ ++arrow_cursor_.x;
+ if (arrow_cursor_.x >= current_grid->columns) {
+ arrow_cursor_.x = 0;
+ arrow_cursor_.primary_display = !arrow_cursor_.primary_display;
+ }
+ }
+ break;
+ case WindowOverview::UP:
+ fade_direction.set_y(-1);
+ if (arrow_cursor_.y <= 0) {
+ if (arrow_cursor_.x <= 0) {
+ arrow_cursor_.x = other_grid->columns - 1;
+ if (other_grid->windows % other_grid->columns != 0 &&
+ arrow_cursor_.x >= other_grid->windows % other_grid->columns)
+ arrow_cursor_.y = other_grid->rows - 2;
+ else
+ arrow_cursor_.y = other_grid->rows - 1;
+ arrow_cursor_.primary_display = !arrow_cursor_.primary_display;
+ } else {
+ --arrow_cursor_.x;
+ if (current_grid->windows % current_grid->columns != 0 &&
+ arrow_cursor_.x >= current_grid->windows % current_grid->columns)
+ arrow_cursor_.y = current_grid->rows - 2;
+ else
+ arrow_cursor_.y = current_grid->rows - 1;
+ }
+ } else {
+ --arrow_cursor_.y;
+ }
+ break;
+ case WindowOverview::NONE:
+ break;
+ }
+ }
+
+ // If the movement indicates a change of grid but there are no windows there,
+ // force the movement to the same grid.
+ if (arrow_cursor_.primary_display != old_grid &&
+ (other_grid->windows == 0 || current_grid == other_grid))
+ arrow_cursor_.primary_display = !arrow_cursor_.primary_display;
+
+ if (arrow_cursor_.primary_display && main_grid_.windows == 0)
+ // This should only happen on a movement that tries to change the display
+ // right after closing the last window on the main display.
+ arrow_cursor_.primary_display = false;
+
+ if (selected_window_) {
+ fade_direction.set_x(
+ fade_direction.x() * GetSelectionBounds(selected_window_).width());
+ fade_direction.set_y(
+ fade_direction.y() * GetSelectionBounds(selected_window_).height());
+ }
+
+ if (arrow_cursor_.primary_display)
tdanderson 2014/04/29 14:46:27 Use {} here since the body of if/else exceeds one
Nina 2014/04/29 18:31:40 Done.
+ MoveSelectionWidget(main_grid_.
+ window_matrix[arrow_cursor_.x][arrow_cursor_.y],
+ &fade_direction);
+ else
+ MoveSelectionWidget(secondary_grid_.
+ window_matrix[arrow_cursor_.x][arrow_cursor_.y],
+ &fade_direction);
+}
+
+gfx::Rect WindowOverview::GetSelectionBounds(WindowSelectorItem* window) {
+ gfx::Rect bounds(window->bounds());
bounds.Inset(-kWindowOverviewSelectionPadding,
-kWindowOverviewSelectionPadding);
return bounds;
}
-
} // namespace ash

Powered by Google App Engine
This is Rietveld 408576698