diff options
Diffstat (limited to 'chromium/ash/wm/workspace/workspace_layout_manager_unittest.cc')
-rw-r--r-- | chromium/ash/wm/workspace/workspace_layout_manager_unittest.cc | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/chromium/ash/wm/workspace/workspace_layout_manager_unittest.cc b/chromium/ash/wm/workspace/workspace_layout_manager_unittest.cc new file mode 100644 index 00000000000..3dce5b015c9 --- /dev/null +++ b/chromium/ash/wm/workspace/workspace_layout_manager_unittest.cc @@ -0,0 +1,362 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/wm/workspace/workspace_layout_manager.h" + +#include "ash/root_window_controller.h" +#include "ash/screen_ash.h" +#include "ash/shelf/shelf_layout_manager.h" +#include "ash/shelf/shelf_widget.h" +#include "ash/shell.h" +#include "ash/test/ash_test_base.h" +#include "ash/wm/property_util.h" +#include "ash/wm/window_util.h" +#include "ui/aura/client/aura_constants.h" +#include "ui/aura/root_window.h" +#include "ui/aura/test/test_windows.h" +#include "ui/aura/window.h" +#include "ui/gfx/insets.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" + +namespace ash { +namespace { + +class MaximizeDelegateView : public views::WidgetDelegateView { + public: + MaximizeDelegateView(const gfx::Rect& initial_bounds) + : initial_bounds_(initial_bounds) { + } + virtual ~MaximizeDelegateView() {} + + virtual bool GetSavedWindowPlacement( + gfx::Rect* bounds, + ui::WindowShowState* show_state) const OVERRIDE { + *bounds = initial_bounds_; + *show_state = ui::SHOW_STATE_MAXIMIZED; + return true; + } + + private: + const gfx::Rect initial_bounds_; + + DISALLOW_COPY_AND_ASSIGN(MaximizeDelegateView); +}; + +} // namespace + +typedef test::AshTestBase WorkspaceLayoutManagerTest; + +// Verifies that a window containing a restore coordinate will be restored to +// to the size prior to minimize, keeping the restore rectangle in tact (if +// there is one). +TEST_F(WorkspaceLayoutManagerTest, RestoreFromMinimizeKeepsRestore) { + scoped_ptr<aura::Window> window( + CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 3, 4))); + gfx::Rect bounds(10, 15, 25, 35); + window->SetBounds(bounds); + // This will not be used for un-minimizing window. + SetRestoreBoundsInScreen(window.get(), gfx::Rect(0, 0, 100, 100)); + wm::MinimizeWindow(window.get()); + wm::RestoreWindow(window.get()); + EXPECT_EQ("0,0 100x100", GetRestoreBoundsInScreen(window.get())->ToString()); + EXPECT_EQ("10,15 25x35", window.get()->bounds().ToString()); + + if (!SupportsMultipleDisplays()) + return; + + UpdateDisplay("400x300,500x400"); + window->SetBoundsInScreen(gfx::Rect(600, 0, 100, 100), + ScreenAsh::GetSecondaryDisplay()); + EXPECT_EQ(Shell::GetAllRootWindows()[1], window->GetRootWindow()); + wm::MinimizeWindow(window.get()); + // This will not be used for un-minimizing window. + SetRestoreBoundsInScreen(window.get(), gfx::Rect(0, 0, 100, 100)); + wm::RestoreWindow(window.get()); + EXPECT_EQ("600,0 100x100", window->GetBoundsInScreen().ToString()); + + // Make sure the unminimized window moves inside the display when + // 2nd display is disconnected. + wm::MinimizeWindow(window.get()); + UpdateDisplay("400x300"); + wm::RestoreWindow(window.get()); + EXPECT_EQ(Shell::GetPrimaryRootWindow(), window->GetRootWindow()); + EXPECT_TRUE( + Shell::GetPrimaryRootWindow()->bounds().Intersects(window->bounds())); +} + +TEST_F(WorkspaceLayoutManagerTest, KeepRestoredWindowInDisplay) { + if (!SupportsHostWindowResize()) + return; + scoped_ptr<aura::Window> window( + CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 30, 40))); + // Maximized -> Normal transition. + wm::MaximizeWindow(window.get()); + SetRestoreBoundsInScreen(window.get(), gfx::Rect(-100, -100, 30, 40)); + wm::RestoreWindow(window.get()); + EXPECT_TRUE( + Shell::GetPrimaryRootWindow()->bounds().Intersects(window->bounds())); + EXPECT_EQ("-20,-30 30x40", window->bounds().ToString()); + + // Minimized -> Normal transition. + window->SetBounds(gfx::Rect(-100, -100, 30, 40)); + wm::MinimizeWindow(window.get()); + EXPECT_FALSE( + Shell::GetPrimaryRootWindow()->bounds().Intersects(window->bounds())); + EXPECT_EQ("-100,-100 30x40", window->bounds().ToString()); + window->Show(); + EXPECT_TRUE( + Shell::GetPrimaryRootWindow()->bounds().Intersects(window->bounds())); + EXPECT_EQ("-20,-30 30x40", window->bounds().ToString()); + + // Fullscreen -> Normal transition. + window->SetBounds(gfx::Rect(0, 0, 30, 40)); // reset bounds. + ASSERT_EQ("0,0 30x40", window->bounds().ToString()); + window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN); + EXPECT_EQ(window->bounds(), window->GetRootWindow()->bounds()); + SetRestoreBoundsInScreen(window.get(), gfx::Rect(-100, -100, 30, 40)); + wm::RestoreWindow(window.get()); + EXPECT_TRUE( + Shell::GetPrimaryRootWindow()->bounds().Intersects(window->bounds())); + EXPECT_EQ("-20,-30 30x40", window->bounds().ToString()); +} + +TEST_F(WorkspaceLayoutManagerTest, MaximizeInDisplayToBeRestored) { + if (!SupportsMultipleDisplays()) + return; + UpdateDisplay("300x400,400x500"); + + Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); + + scoped_ptr<aura::Window> window( + CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 30, 40))); + EXPECT_EQ(root_windows[0], window->GetRootWindow()); + + SetRestoreBoundsInScreen(window.get(), gfx::Rect(400, 0, 30, 40)); + // Maximize the window in 2nd display as the restore bounds + // is inside 2nd display. + wm::MaximizeWindow(window.get()); + EXPECT_EQ(root_windows[1], window->GetRootWindow()); + EXPECT_EQ("300,0 400x452", window->GetBoundsInScreen().ToString()); + + wm::RestoreWindow(window.get()); + EXPECT_EQ(root_windows[1], window->GetRootWindow()); + EXPECT_EQ("400,0 30x40", window->GetBoundsInScreen().ToString()); + + // If the restore bounds intersects with the current display, + // don't move. + SetRestoreBoundsInScreen(window.get(), gfx::Rect(280, 0, 30, 40)); + wm::MaximizeWindow(window.get()); + EXPECT_EQ(root_windows[1], window->GetRootWindow()); + EXPECT_EQ("300,0 400x452", window->GetBoundsInScreen().ToString()); + + wm::RestoreWindow(window.get()); + EXPECT_EQ(root_windows[1], window->GetRootWindow()); + EXPECT_EQ("280,0 30x40", window->GetBoundsInScreen().ToString()); + + // Restoring widget state. + scoped_ptr<views::Widget> w1(new views::Widget); + views::Widget::InitParams params; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.delegate = new MaximizeDelegateView(gfx::Rect(400, 0, 30, 40)); + params.context = root_windows[0]; + w1->Init(params); + w1->Show(); + EXPECT_TRUE(w1->IsMaximized()); + EXPECT_EQ(root_windows[1], w1->GetNativeView()->GetRootWindow()); + EXPECT_EQ("300,0 400x452", w1->GetWindowBoundsInScreen().ToString()); + w1->Restore(); + EXPECT_EQ(root_windows[1], w1->GetNativeView()->GetRootWindow()); + EXPECT_EQ("400,0 30x40", w1->GetWindowBoundsInScreen().ToString()); +} + +TEST_F(WorkspaceLayoutManagerTest, FullscreenInDisplayToBeRestored) { + if (!SupportsMultipleDisplays()) + return; + UpdateDisplay("300x400,400x500"); + + Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); + + scoped_ptr<aura::Window> window( + CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 30, 40))); + EXPECT_EQ(root_windows[0], window->GetRootWindow()); + + SetRestoreBoundsInScreen(window.get(), gfx::Rect(400, 0, 30, 40)); + // Maximize the window in 2nd display as the restore bounds + // is inside 2nd display. + window->SetProperty(aura::client::kShowStateKey, + ui::SHOW_STATE_FULLSCREEN); + EXPECT_EQ(root_windows[1], window->GetRootWindow()); + EXPECT_EQ("300,0 400x500", window->GetBoundsInScreen().ToString()); + + wm::RestoreWindow(window.get()); + EXPECT_EQ(root_windows[1], window->GetRootWindow()); + EXPECT_EQ("400,0 30x40", window->GetBoundsInScreen().ToString()); + + // If the restore bounds intersects with the current display, + // don't move. + SetRestoreBoundsInScreen(window.get(), gfx::Rect(280, 0, 30, 40)); + window->SetProperty(aura::client::kShowStateKey, + ui::SHOW_STATE_FULLSCREEN); + EXPECT_EQ(root_windows[1], window->GetRootWindow()); + EXPECT_EQ("300,0 400x500", window->GetBoundsInScreen().ToString()); + + wm::RestoreWindow(window.get()); + EXPECT_EQ(root_windows[1], window->GetRootWindow()); + EXPECT_EQ("280,0 30x40", window->GetBoundsInScreen().ToString()); +} + +// WindowObserver implementation used by DontClobberRestoreBoundsWindowObserver. +// This code mirrors what BrowserFrameAura does. In particular when this code +// sees the window was maximized it changes the bounds of a secondary +// window. The secondary window mirrors the status window. +class DontClobberRestoreBoundsWindowObserver : public aura::WindowObserver { + public: + DontClobberRestoreBoundsWindowObserver() : window_(NULL) {} + + void set_window(aura::Window* window) { window_ = window; } + + virtual void OnWindowPropertyChanged(aura::Window* window, + const void* key, + intptr_t old) OVERRIDE { + if (!window_) + return; + + if (wm::IsWindowMaximized(window)) { + aura::Window* w = window_; + window_ = NULL; + + gfx::Rect shelf_bounds(Shell::GetPrimaryRootWindowController()-> + GetShelfLayoutManager()->GetIdealBounds()); + const gfx::Rect& window_bounds(w->bounds()); + w->SetBounds(gfx::Rect(window_bounds.x(), shelf_bounds.y() - 1, + window_bounds.width(), window_bounds.height())); + } + } + + private: + aura::Window* window_; + + DISALLOW_COPY_AND_ASSIGN(DontClobberRestoreBoundsWindowObserver); +}; + +// Creates a window, maximized the window and from within the maximized +// notification sets the bounds of a window to overlap the shelf. Verifies this +// doesn't effect the restore bounds. +TEST_F(WorkspaceLayoutManagerTest, DontClobberRestoreBounds) { + DontClobberRestoreBoundsWindowObserver window_observer; + scoped_ptr<aura::Window> window(new aura::Window(NULL)); + window->SetType(aura::client::WINDOW_TYPE_NORMAL); + window->Init(ui::LAYER_TEXTURED); + window->SetBounds(gfx::Rect(10, 20, 30, 40)); + // NOTE: for this test to exercise the failure the observer needs to be added + // before the parent set. This mimics what BrowserFrameAura does. + window->AddObserver(&window_observer); + SetDefaultParentByPrimaryRootWindow(window.get()); + window->Show(); + wm::ActivateWindow(window.get()); + + scoped_ptr<aura::Window> window2( + CreateTestWindowInShellWithBounds(gfx::Rect(12, 20, 30, 40))); + window->AddTransientChild(window2.get()); + window2->Show(); + + window_observer.set_window(window2.get()); + wm::MaximizeWindow(window.get()); + EXPECT_EQ("10,20 30x40", GetRestoreBoundsInScreen(window.get())->ToString()); + window->RemoveObserver(&window_observer); +} + +// Verifies when a window is maximized all descendant windows have a size. +TEST_F(WorkspaceLayoutManagerTest, ChildBoundsResetOnMaximize) { + scoped_ptr<aura::Window> window( + CreateTestWindowInShellWithBounds(gfx::Rect(10, 20, 30, 40))); + window->Show(); + wm::ActivateWindow(window.get()); + scoped_ptr<aura::Window> child_window( + aura::test::CreateTestWindowWithBounds(gfx::Rect(5, 6, 7, 8), + window.get())); + child_window->Show(); + wm::MaximizeWindow(window.get()); + EXPECT_EQ("5,6 7x8", child_window->bounds().ToString()); +} + +TEST_F(WorkspaceLayoutManagerTest, WindowShouldBeOnScreenWhenAdded) { + // Normal window bounds shouldn't be changed. + gfx::Rect window_bounds(100, 100, 200, 200); + scoped_ptr<aura::Window> window( + CreateTestWindowInShellWithBounds(window_bounds)); + EXPECT_EQ(window_bounds, window->bounds()); + + // If the window is out of the workspace, it would be moved on screen. + gfx::Rect root_window_bounds = + Shell::GetInstance()->GetPrimaryRootWindow()->bounds(); + window_bounds.Offset(root_window_bounds.width(), root_window_bounds.height()); + ASSERT_FALSE(window_bounds.Intersects(root_window_bounds)); + scoped_ptr<aura::Window> out_window( + CreateTestWindowInShellWithBounds(window_bounds)); + EXPECT_EQ(window_bounds.size(), out_window->bounds().size()); + gfx::Rect bounds = out_window->bounds(); + bounds.Intersect(root_window_bounds); + + // 30% of the window edge must be visible. + EXPECT_GT(bounds.width(), out_window->bounds().width() * 0.29); + EXPECT_GT(bounds.height(), out_window->bounds().height() * 0.29); + + // Make sure we always make more than 1/3 of the window edge visible even + // if the initial bounds intersects with display. + window_bounds.SetRect(-150, -150, 200, 200); + bounds = window_bounds; + bounds.Intersect(root_window_bounds); + + // Make sure that the initial bounds' visible area is less than 26% + // so that the auto adjustment logic kicks in. + ASSERT_LT(bounds.width(), out_window->bounds().width() * 0.26); + ASSERT_LT(bounds.height(), out_window->bounds().height() * 0.26); + ASSERT_TRUE(window_bounds.Intersects(root_window_bounds)); + + scoped_ptr<aura::Window> partially_out_window( + CreateTestWindowInShellWithBounds(window_bounds)); + EXPECT_EQ(window_bounds.size(), partially_out_window->bounds().size()); + bounds = partially_out_window->bounds(); + bounds.Intersect(root_window_bounds); + EXPECT_GT(bounds.width(), out_window->bounds().width() * 0.29); + EXPECT_GT(bounds.height(), out_window->bounds().height() * 0.29); + + // Make sure the window whose 30% width/height is bigger than display + // will be placed correctly. + window_bounds.SetRect(-1900, -1900, 3000, 3000); + scoped_ptr<aura::Window> window_bigger_than_display( + CreateTestWindowInShellWithBounds(window_bounds)); + EXPECT_GE(root_window_bounds.width(), + window_bigger_than_display->bounds().width()); + EXPECT_GE(root_window_bounds.height(), + window_bigger_than_display->bounds().height()); + + bounds = window_bigger_than_display->bounds(); + bounds.Intersect(root_window_bounds); + EXPECT_GT(bounds.width(), out_window->bounds().width() * 0.29); + EXPECT_GT(bounds.height(), out_window->bounds().height() * 0.29); +} + +// Verifies the size of a window is enforced to be smaller than the work area. +TEST_F(WorkspaceLayoutManagerTest, SizeToWorkArea) { + // Normal window bounds shouldn't be changed. + gfx::Size work_area( + Shell::GetScreen()->GetPrimaryDisplay().work_area().size()); + const gfx::Rect window_bounds( + 100, 101, work_area.width() + 1, work_area.height() + 2); + scoped_ptr<aura::Window> window( + CreateTestWindowInShellWithBounds(window_bounds)); + EXPECT_EQ(gfx::Rect(gfx::Point(100, 101), work_area).ToString(), + window->bounds().ToString()); + + // Directly setting the bounds triggers a slightly different code path. Verify + // that too. + window->SetBounds(window_bounds); + EXPECT_EQ(gfx::Rect(gfx::Point(100, 101), work_area).ToString(), + window->bounds().ToString()); +} + +} // namespace ash |