Commit bc374788 authored by oshima's avatar oshima Committed by Commit bot

Allow Alt-Tab to move the focus to docked windows.

BUG=343237
TEST=WindowSelectorTest.BasicWithDocked, plus manual

Review URL: https://codereview.chromium.org/1059903002

Cr-Commit-Position: refs/heads/master@{#324155}
parent 1b5266d8
......@@ -653,9 +653,10 @@ TEST_F(AcceleratorControllerTest, CenterWindowAccelerator) {
// Add the window to docked container and try to center it.
window->SetBounds(gfx::Rect(0, 0, 20, 20));
aura::Window* docked_container = Shell::GetContainer(
window->GetRootWindow(), kShellWindowId_DockedContainer);
docked_container->AddChild(window.get());
const wm::WMEvent event(wm::WM_EVENT_DOCK);
wm::GetWindowState(window.get())->OnWMEvent(&event);
EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id());
gfx::Rect docked_bounds = window->GetBoundsInScreen();
GetController()->PerformActionIfEnabled(WINDOW_POSITION_CENTER);
// It should not get centered and should remain docked.
......
......@@ -12,6 +12,7 @@ namespace ash {
const int kSwitchableWindowContainerIds[] = {
kShellWindowId_DefaultContainer,
kShellWindowId_AlwaysOnTopContainer,
kShellWindowId_DockedContainer,
kShellWindowId_PanelContainer,
kShellWindowId_AppListContainer};
......
......@@ -16,8 +16,6 @@
#include "ash/shell.h"
#include "ash/shell_window_ids.h"
#include "ash/switchable_windows.h"
#include "ash/wm/overview/scoped_overview_animation_settings.h"
#include "ash/wm/overview/scoped_transform_overview_window.h"
#include "ash/wm/overview/window_grid.h"
#include "ash/wm/overview/window_selector_delegate.h"
#include "ash/wm/overview/window_selector_item.h"
......@@ -218,6 +216,17 @@ views::Widget* CreateTextFilter(views::TextfieldController* controller,
const int WindowSelector::kTextFilterBottomEdge =
kTextFilterDistanceFromTop + kTextFilterHeight;
// static
bool WindowSelector::IsSelectable(aura::Window* window) {
wm::WindowState* state = wm::GetWindowState(window);
if (state->GetStateType() == wm::WINDOW_STATE_TYPE_DOCKED ||
state->GetStateType() == wm::WINDOW_STATE_TYPE_DOCKED_MINIMIZED) {
return false;
}
return window->type() == ui::wm::WINDOW_TYPE_NORMAL ||
window->type() == ui::wm::WINDOW_TYPE_PANEL;
}
WindowSelector::WindowSelector(WindowSelectorDelegate* delegate)
: delegate_(delegate),
restore_focus_window_(aura::client::GetFocusClient(
......@@ -302,7 +311,6 @@ void WindowSelector::Init(const WindowList& windows) {
shell->GetScreen()->AddObserver(this);
shell->metrics()->RecordUserMetricsAction(UMA_WINDOW_OVERVIEW);
HideAndTrackNonOverviewWindows();
// Send an a11y alert.
shell->accessibility_delegate()->TriggerAccessibilityAlert(
ui::A11Y_ALERT_WINDOW_OVERVIEW_MODE_ENTERED);
......@@ -327,16 +335,6 @@ void WindowSelector::Shutdown() {
->layout_manager())->SetShowCalloutWidgets(true);
}
const aura::WindowTracker::Windows hidden_windows(hidden_windows_.windows());
for (aura::WindowTracker::Windows::const_iterator iter =
hidden_windows.begin(); iter != hidden_windows.end(); ++iter) {
ScopedOverviewAnimationSettings animation_settings(
OverviewAnimationType::OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS,
*iter);
(*iter)->layer()->SetOpacity(1);
(*iter)->Show();
}
size_t remaining_items = 0;
for (WindowGrid* window_grid : grid_list_) {
for (WindowSelectorItem* window_selector_item : window_grid->window_list())
......@@ -456,10 +454,8 @@ void WindowSelector::OnDisplayMetricsChanged(const gfx::Display& display,
}
void WindowSelector::OnWindowAdded(aura::Window* new_window) {
if (new_window->type() != ui::wm::WINDOW_TYPE_NORMAL &&
new_window->type() != ui::wm::WINDOW_TYPE_PANEL) {
if (!IsSelectable(new_window))
return;
}
for (size_t i = 0; i < kSwitchableWindowContainerIdsLength; ++i) {
if (new_window->parent()->id() == kSwitchableWindowContainerIds[i] &&
......@@ -556,42 +552,6 @@ void WindowSelector::PositionWindows(bool animate) {
}
}
void WindowSelector::HideAndTrackNonOverviewWindows() {
// Add the windows to hidden_windows first so that if any are destroyed
// while hiding them they are tracked.
for (ScopedVector<WindowGrid>::iterator grid_iter = grid_list_.begin();
grid_iter != grid_list_.end(); ++grid_iter) {
for (size_t i = 0; i < kSwitchableWindowContainerIdsLength; ++i) {
const aura::Window* container =
Shell::GetContainer((*grid_iter)->root_window(),
kSwitchableWindowContainerIds[i]);
for (aura::Window::Windows::const_iterator iter =
container->children().begin(); iter != container->children().end();
++iter) {
if (!(*iter)->IsVisible() || (*grid_iter)->Contains(*iter))
continue;
hidden_windows_.Add(*iter);
}
}
}
// Copy the window list as it can change during iteration.
const aura::WindowTracker::Windows hidden_windows(hidden_windows_.windows());
for (aura::WindowTracker::Windows::const_iterator iter =
hidden_windows.begin(); iter != hidden_windows.end(); ++iter) {
if (!hidden_windows_.Contains(*iter))
continue;
ScopedOverviewAnimationSettings animation_settings(
OverviewAnimationType::OVERVIEW_ANIMATION_HIDE_WINDOW,
*iter);
(*iter)->Hide();
// Hiding the window can result in it being destroyed.
if (!hidden_windows_.Contains(*iter))
continue;
(*iter)->layer()->SetOpacity(0);
}
}
void WindowSelector::ResetFocusRestoreWindow(bool focus) {
if (!restore_focus_window_)
return;
......
......@@ -56,6 +56,9 @@ class ASH_EXPORT WindowSelector
// the text filtering textfield.
static const int kTextFilterBottomEdge;
// Returns true if the window can be selected in overview mode.
static bool IsSelectable(aura::Window* window);
enum Direction {
LEFT,
UP,
......@@ -116,9 +119,6 @@ class ASH_EXPORT WindowSelector
// Position all of the windows in the overview.
void PositionWindows(bool animate);
// Hide and track all hidden windows not in the overview item list.
void HideAndTrackNonOverviewWindows();
// |focus|, restores focus to the stored window.
void ResetFocusRestoreWindow(bool focus);
......@@ -149,10 +149,6 @@ class ASH_EXPORT WindowSelector
// List of all the window overview grids, one for each root window.
ScopedVector<WindowGrid> grid_list_;
// Tracks windows which were hidden because they were not part of the
// overview.
aura::WindowTracker hidden_windows_;
// Tracks the index of the root window the selection widget is in.
size_t selected_grid_index_;
......
......@@ -46,8 +46,13 @@ void WindowSelectorController::ToggleOverview() {
if (!CanSelect())
return;
std::vector<aura::Window*> windows = ash::Shell::GetInstance()->
mru_window_tracker()->BuildMruWindowList();
aura::Window::Windows windows =
ash::Shell::GetInstance()->mru_window_tracker()->BuildMruWindowList();
auto end =
std::remove_if(windows.begin(), windows.end(),
std::not1(std::ptr_fun(&WindowSelector::IsSelectable)));
windows.resize(end - windows.begin());
// Don't enter overview mode with no windows.
if (windows.empty())
return;
......
......@@ -286,6 +286,7 @@ TEST_F(WindowSelectorTest, Basic) {
scoped_ptr<aura::Window> window2(CreateWindow(bounds));
scoped_ptr<aura::Window> panel1(CreatePanelWindow(bounds));
scoped_ptr<aura::Window> panel2(CreatePanelWindow(bounds));
EXPECT_TRUE(WindowsOverlapping(window1.get(), window2.get()));
EXPECT_TRUE(WindowsOverlapping(panel1.get(), panel2.get()));
wm::ActivateWindow(window2.get());
......@@ -313,6 +314,50 @@ TEST_F(WindowSelectorTest, Basic) {
EXPECT_FALSE(aura::client::GetCursorClient(root_window)->IsCursorLocked());
}
// Tests entering overview mode with docked windows
TEST_F(WindowSelectorTest, BasicWithDocked) {
// aura::Window* root_window = Shell::GetPrimaryRootWindow();
gfx::Rect bounds(300, 0, 200, 200);
scoped_ptr<aura::Window> window1(CreateWindow(bounds));
scoped_ptr<aura::Window> window2(CreateWindow(bounds));
scoped_ptr<aura::Window> docked1(CreateWindow(bounds));
scoped_ptr<aura::Window> docked2(CreateWindow(bounds));
wm::WMEvent dock_event(wm::WM_EVENT_DOCK);
wm::GetWindowState(docked1.get())->OnWMEvent(&dock_event);
wm::WindowState* docked_state2 = wm::GetWindowState(docked2.get());
docked_state2->OnWMEvent(&dock_event);
wm::WMEvent minimize_event(wm::WM_EVENT_MINIMIZE);
docked_state2->OnWMEvent(&minimize_event);
EXPECT_TRUE(WindowsOverlapping(window1.get(), window2.get()));
gfx::Rect docked_bounds = docked1->GetBoundsInScreen();
EXPECT_NE(bounds.ToString(), docked_bounds.ToString());
EXPECT_FALSE(WindowsOverlapping(window1.get(), docked1.get()));
EXPECT_FALSE(WindowsOverlapping(window1.get(), docked2.get()));
EXPECT_FALSE(docked2->IsVisible());
EXPECT_EQ(wm::WINDOW_STATE_TYPE_DOCKED,
wm::GetWindowState(docked1.get())->GetStateType());
EXPECT_EQ(wm::WINDOW_STATE_TYPE_DOCKED_MINIMIZED,
wm::GetWindowState(docked2.get())->GetStateType());
ToggleOverview();
EXPECT_FALSE(WindowsOverlapping(window1.get(), window2.get()));
// Docked windows stays the same.
EXPECT_EQ(docked_bounds.ToString(), docked1->GetBoundsInScreen().ToString());
EXPECT_FALSE(docked2->IsVisible());
// Docked window can still be activated, which will exit the overview mode.
ClickWindow(docked1.get());
EXPECT_TRUE(wm::IsActiveWindow(docked1.get()));
EXPECT_FALSE(
ash::Shell::GetInstance()->window_selector_controller()->IsSelecting());
}
// Tests selecting a window by tapping on it.
TEST_F(WindowSelectorTest, BasicGesture) {
gfx::Rect bounds(0, 0, 400, 400);
......@@ -710,29 +755,6 @@ TEST_F(WindowSelectorTest, QuickReentryRestoresInitialTransform) {
GetTransformedTargetBounds(window.get())));
}
// Tests that non-activatable windows are hidden when entering overview mode.
TEST_F(WindowSelectorTest, NonActivatableWindowsHidden) {
gfx::Rect bounds(0, 0, 400, 400);
scoped_ptr<aura::Window> window1(CreateWindow(bounds));
scoped_ptr<aura::Window> window2(CreateWindow(bounds));
scoped_ptr<aura::Window> non_activatable_window(
CreateNonActivatableWindow(Shell::GetPrimaryRootWindow()->bounds()));
EXPECT_TRUE(non_activatable_window->IsVisible());
ToggleOverview();
EXPECT_FALSE(non_activatable_window->IsVisible());
ToggleOverview();
EXPECT_TRUE(non_activatable_window->IsVisible());
// Test that a window behind the fullscreen non-activatable window can be
// clicked.
non_activatable_window->parent()->StackChildAtTop(
non_activatable_window.get());
ToggleOverview();
ClickWindow(window1.get());
EXPECT_FALSE(IsSelecting());
EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
}
// Tests that windows with modal child windows are transformed with the modal
// child even though not activatable themselves.
TEST_F(WindowSelectorTest, ModalChild) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment