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 |