summaryrefslogtreecommitdiffstats
path: root/ash/wm
diff options
context:
space:
mode:
authorflackr@chromium.org <flackr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-23 19:28:20 +0000
committerflackr@chromium.org <flackr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-23 19:28:20 +0000
commit8dd3d54c56b55a5c4fc076847494f00f91f23026 (patch)
tree039eaf16e73f6c25de5a48e9e2d92fb482c75a3d /ash/wm
parentf6a5261539900d7fb66c05623e091fad88c8b905 (diff)
downloadchromium_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.cc108
-rw-r--r--ash/wm/overview/window_selector.h5
-rw-r--r--ash/wm/overview/window_selector_unittest.cc67
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);