diff options
author | flackr@chromium.org <flackr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-23 19:28:20 +0000 |
---|---|---|
committer | flackr@chromium.org <flackr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-23 19:28:20 +0000 |
commit | 8dd3d54c56b55a5c4fc076847494f00f91f23026 (patch) | |
tree | 039eaf16e73f6c25de5a48e9e2d92fb482c75a3d /ash/wm | |
parent | f6a5261539900d7fb66c05623e091fad88c8b905 (diff) | |
download | chromium_src-8dd3d54c56b55a5c4fc076847494f00f91f23026.zip chromium_src-8dd3d54c56b55a5c4fc076847494f00f91f23026.tar.gz chromium_src-8dd3d54c56b55a5c4fc076847494f00f91f23026.tar.bz2 |
Restore the stacking order of a window after cycling past it.
BUG=310268
TEST=WindowSelectorTest.CyclePreservesStackingOrder, WindowSelectorTest.CyclePreservesMinimization
Review URL: https://codereview.chromium.org/36003002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@230489 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash/wm')
-rw-r--r-- | ash/wm/overview/window_selector.cc | 108 | ||||
-rw-r--r-- | ash/wm/overview/window_selector.h | 5 | ||||
-rw-r--r-- | ash/wm/overview/window_selector_unittest.cc | 67 |
3 files changed, 175 insertions, 5 deletions
diff --git a/ash/wm/overview/window_selector.cc b/ash/wm/overview/window_selector.cc index a5973ca..47d3c49 100644 --- a/ash/wm/overview/window_selector.cc +++ b/ash/wm/overview/window_selector.cc @@ -21,6 +21,7 @@ #include "ui/aura/client/focus_client.h" #include "ui/aura/root_window.h" #include "ui/aura/window.h" +#include "ui/aura/window_observer.h" #include "ui/events/event.h" #include "ui/events/event_handler.h" @@ -105,8 +106,105 @@ void UpdateShelfVisibility() { } } +// Returns the window immediately below |window| in the current container. +aura::Window* GetWindowBelow(aura::Window* window) { + aura::Window* parent = window->parent(); + if (!parent) + return NULL; + aura::Window* below = NULL; + for (aura::Window::Windows::const_iterator iter = parent->children().begin(); + iter != parent->children().end(); ++iter) { + if (*iter == window) + return below; + below = *iter; + } + NOTREACHED(); + return NULL; +} + } // namespace +// This class restores and moves a window to the front of the stacking order for +// the duration of the class's scope. +class ScopedShowWindow : public aura::WindowObserver { + public: + ScopedShowWindow(); + virtual ~ScopedShowWindow(); + + // Show |window| at the top of the stacking order. + void Show(aura::Window* window); + + // Cancel restoring the window on going out of scope. + void CancelRestore(); + + aura::Window* window() { return window_; } + + // aura::WindowObserver: + virtual void OnWillRemoveWindow(aura::Window* window) OVERRIDE; + + private: + // The window being shown. + aura::Window* window_; + + // The window immediately below where window_ belongs. + aura::Window* stack_window_above_; + + // If true, minimize window_ on going out of scope. + bool minimized_; + + DISALLOW_COPY_AND_ASSIGN(ScopedShowWindow); +}; + +ScopedShowWindow::ScopedShowWindow() + : window_(NULL), + stack_window_above_(NULL), + minimized_(false) { +} + +void ScopedShowWindow::Show(aura::Window* window) { + DCHECK(!window_); + window_ = window; + stack_window_above_ = GetWindowBelow(window); + minimized_ = wm::GetWindowState(window)->IsMinimized(); + window_->Show(); + window_->SetTransform(gfx::Transform()); + window_->parent()->AddObserver(this); + window_->parent()->StackChildAtTop(window_); +} + +ScopedShowWindow::~ScopedShowWindow() { + if (window_) { + window_->parent()->RemoveObserver(this); + + // Restore window's stacking position. + if (stack_window_above_) + window_->parent()->StackChildAbove(window_, stack_window_above_); + else + window_->parent()->StackChildAtBottom(window_); + + // Restore minimized state. + if (minimized_) + wm::GetWindowState(window_)->Minimize(); + } +} + +void ScopedShowWindow::CancelRestore() { + if (!window_) + return; + window_->parent()->RemoveObserver(this); + window_ = stack_window_above_ = NULL; +} + +void ScopedShowWindow::OnWillRemoveWindow(aura::Window* window) { + if (window == window_) { + CancelRestore(); + } else if (window == stack_window_above_) { + // If the window this window was above is removed, use the next window down + // as the restore marker. + stack_window_above_ = GetWindowBelow(stack_window_above_); + } +} + WindowSelector::WindowSelector(const WindowList& windows, WindowSelector::Mode mode, WindowSelectorDelegate* delegate) @@ -206,11 +304,8 @@ void WindowSelector::Step(WindowSelector::Direction direction) { if (window_overview_) { window_overview_->SetSelection(selected_window_); } else { - aura::Window* current_window = - windows_[selected_window_]->SelectionWindow(); - current_window->Show(); - current_window->SetTransform(gfx::Transform()); - current_window->parent()->StackChildAtTop(current_window); + showing_window_.reset(new ScopedShowWindow); + showing_window_->Show(windows_[selected_window_]->SelectionWindow()); start_overview_timer_.Reset(); } } @@ -221,6 +316,8 @@ void WindowSelector::SelectWindow() { } void WindowSelector::SelectWindow(aura::Window* window) { + if (showing_window_ && showing_window_->window() == window) + showing_window_->CancelRestore(); ScopedVector<WindowSelectorItem>::iterator iter = std::find_if(windows_.begin(), windows_.end(), WindowSelectorItemComparator(window)); @@ -326,6 +423,7 @@ void WindowSelector::OnAttemptToReactivateWindow(aura::Window* request_active, } void WindowSelector::StartOverview() { + showing_window_.reset(); DCHECK(!window_overview_); window_overview_.reset(new WindowOverview(this, &windows_, mode_ == CYCLE ? windows_[selected_window_]->GetRootWindow() : NULL)); diff --git a/ash/wm/overview/window_selector.h b/ash/wm/overview/window_selector.h index b962ff33..2f178b6 100644 --- a/ash/wm/overview/window_selector.h +++ b/ash/wm/overview/window_selector.h @@ -30,6 +30,7 @@ namespace internal { class WindowSelectorTest; } +class ScopedShowWindow; class WindowOverview; class WindowSelectorDelegate; class WindowSelectorItem; @@ -112,6 +113,10 @@ class ASH_EXPORT WindowSelector // cycling. scoped_ptr<ui::EventHandler> event_handler_; + // The currently selected window being shown (temporarily brought to the front + // of the stacking order and made visible). + scoped_ptr<ScopedShowWindow> showing_window_; + base::DelayTimer<WindowSelector> start_overview_timer_; scoped_ptr<WindowOverview> window_overview_; diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc index a2bd8ea..888f2a2 100644 --- a/ash/wm/overview/window_selector_unittest.cc +++ b/ash/wm/overview/window_selector_unittest.cc @@ -47,6 +47,20 @@ class NonActivatableActivationDelegate } }; +bool IsWindowAbove(aura::Window* w1, aura::Window* w2) { + aura::Window* parent = w1->parent(); + DCHECK_EQ(parent, w2->parent()); + for (aura::Window::Windows::const_iterator iter = parent->children().begin(); + iter != parent->children().end(); ++iter) { + if (*iter == w1) + return false; + if (*iter == w2) + return true; + } + NOTREACHED(); + return false; +} + } // namespace class WindowSelectorTest : public test::AshTestBase { @@ -309,6 +323,59 @@ TEST_F(WindowSelectorTest, BasicCycle) { EXPECT_TRUE(wm::IsActiveWindow(window3.get())); } +// Tests that cycling through windows preserves the window stacking order. +TEST_F(WindowSelectorTest, CyclePreservesStackingOrder) { + 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> window3(CreateWindow(bounds)); + wm::ActivateWindow(window3.get()); + wm::ActivateWindow(window2.get()); + wm::ActivateWindow(window1.get()); + // Window order from top to bottom is 1, 2, 3. + EXPECT_TRUE(IsWindowAbove(window1.get(), window2.get())); + EXPECT_TRUE(IsWindowAbove(window2.get(), window3.get())); + + // On window 2. + Cycle(WindowSelector::FORWARD); + EXPECT_TRUE(IsWindowAbove(window2.get(), window1.get())); + EXPECT_TRUE(IsWindowAbove(window1.get(), window3.get())); + + // On window 3. + Cycle(WindowSelector::FORWARD); + EXPECT_TRUE(IsWindowAbove(window3.get(), window1.get())); + EXPECT_TRUE(IsWindowAbove(window1.get(), window2.get())); + + // Back on window 1. + Cycle(WindowSelector::FORWARD); + EXPECT_TRUE(IsWindowAbove(window1.get(), window2.get())); + EXPECT_TRUE(IsWindowAbove(window2.get(), window3.get())); + StopCycling(); +} + +// Tests that cycling through windows shows and minimizes windows as they +// are passed. +TEST_F(WindowSelectorTest, CyclePreservesMinimization) { + gfx::Rect bounds(0, 0, 400, 400); + scoped_ptr<aura::Window> window1(CreateWindow(bounds)); + scoped_ptr<aura::Window> window2(CreateWindow(bounds)); + wm::ActivateWindow(window2.get()); + wm::GetWindowState(window2.get())->Minimize(); + wm::ActivateWindow(window1.get()); + EXPECT_TRUE(wm::IsWindowMinimized(window2.get())); + + // On window 2. + Cycle(WindowSelector::FORWARD); + EXPECT_FALSE(wm::IsWindowMinimized(window2.get())); + + // Back on window 1. + Cycle(WindowSelector::FORWARD); + EXPECT_TRUE(wm::IsWindowMinimized(window2.get())); + + StopCycling(); + EXPECT_TRUE(wm::IsWindowMinimized(window2.get())); +} + // Tests beginning cycling while in overview mode. TEST_F(WindowSelectorTest, OverviewTransitionToCycle) { gfx::Rect bounds(0, 0, 400, 400); |