| Index: ash/wm/solo_window_tracker_unittest.cc
|
| diff --git a/ash/wm/solo_window_tracker_unittest.cc b/ash/wm/solo_window_tracker_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d134c4089ab6d129d6ae0a96553458c7d8c0ea21
|
| --- /dev/null
|
| +++ b/ash/wm/solo_window_tracker_unittest.cc
|
| @@ -0,0 +1,429 @@
|
| +// Copyright 2013 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/solo_window_tracker.h"
|
| +
|
| +#include "ash/ash_constants.h"
|
| +#include "ash/ash_switches.h"
|
| +#include "ash/root_window_controller.h"
|
| +#include "ash/screen_ash.h"
|
| +#include "ash/shell.h"
|
| +#include "ash/shell_window_ids.h"
|
| +#include "ash/test/ash_test_base.h"
|
| +#include "ash/wm/window_resizer.h"
|
| +#include "ash/wm/window_state.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "ui/aura/client/aura_constants.h"
|
| +#include "ui/aura/root_window.h"
|
| +#include "ui/aura/test/event_generator.h"
|
| +#include "ui/aura/window.h"
|
| +#include "ui/aura/window_observer.h"
|
| +#include "ui/base/hit_test.h"
|
| +#include "ui/gfx/screen.h"
|
| +
|
| +namespace ash {
|
| +
|
| +namespace {
|
| +
|
| +class WindowRepaintChecker : public aura::WindowObserver {
|
| + public:
|
| + explicit WindowRepaintChecker(aura::Window* window)
|
| + : window_(window),
|
| + is_paint_scheduled_(false) {
|
| + window_->AddObserver(this);
|
| + }
|
| +
|
| + virtual ~WindowRepaintChecker() {
|
| + if (window_)
|
| + window_->RemoveObserver(this);
|
| + }
|
| +
|
| + bool IsPaintScheduledAndReset() {
|
| + bool result = is_paint_scheduled_;
|
| + is_paint_scheduled_ = false;
|
| + return result;
|
| + }
|
| +
|
| + private:
|
| + // aura::WindowObserver overrides:
|
| + virtual void OnWindowPaintScheduled(aura::Window* window,
|
| + const gfx::Rect& region) OVERRIDE {
|
| + is_paint_scheduled_ = true;
|
| + }
|
| + virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {
|
| + DCHECK_EQ(window_, window);
|
| + window_ = NULL;
|
| + }
|
| +
|
| + aura::Window* window_;
|
| + bool is_paint_scheduled_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(WindowRepaintChecker);
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +class SoloWindowTrackerTest : public test::AshTestBase {
|
| + public:
|
| + SoloWindowTrackerTest() {
|
| + }
|
| + virtual ~SoloWindowTrackerTest() {
|
| + }
|
| +
|
| + // Helpers methods to create test windows in the primary root window.
|
| + aura::Window* CreateWindowInPrimary() {
|
| + aura::Window* window = new aura::Window(NULL);
|
| + window->SetType(ui::wm::WINDOW_TYPE_NORMAL);
|
| + window->Init(aura::WINDOW_LAYER_TEXTURED);
|
| + window->SetBounds(gfx::Rect(100, 100));
|
| + ParentWindowInPrimaryRootWindow(window);
|
| + return window;
|
| + }
|
| + aura::Window* CreateAlwaysOnTopWindowInPrimary() {
|
| + aura::Window* window = new aura::Window(NULL);
|
| + window->SetType(ui::wm::WINDOW_TYPE_NORMAL);
|
| + window->Init(aura::WINDOW_LAYER_TEXTURED);
|
| + window->SetBounds(gfx::Rect(100, 100));
|
| + window->SetProperty(aura::client::kAlwaysOnTopKey, true);
|
| + ParentWindowInPrimaryRootWindow(window);
|
| + return window;
|
| + }
|
| + aura::Window* CreatePanelWindowInPrimary() {
|
| + aura::Window* window = new aura::Window(NULL);
|
| + window->SetType(ui::wm::WINDOW_TYPE_PANEL);
|
| + window->Init(aura::WINDOW_LAYER_TEXTURED);
|
| + window->SetBounds(gfx::Rect(100, 100));
|
| + ParentWindowInPrimaryRootWindow(window);
|
| + return window;
|
| + }
|
| +
|
| + // Drag |window| to the dock.
|
| + void DockWindow(aura::Window* window) {
|
| + // Because the tests use windows without delegates,
|
| + // aura::test::EventGenerator cannot be used.
|
| + gfx::Point drag_to =
|
| + ash::ScreenAsh::GetDisplayBoundsInParent(window).top_right();
|
| + scoped_ptr<WindowResizer> resizer(CreateWindowResizer(
|
| + window,
|
| + window->bounds().origin(),
|
| + HTCAPTION,
|
| + aura::client::WINDOW_MOVE_SOURCE_MOUSE));
|
| + resizer->Drag(drag_to, 0);
|
| + resizer->CompleteDrag();
|
| + EXPECT_EQ(internal::kShellWindowId_DockedContainer,
|
| + window->parent()->id());
|
| + }
|
| +
|
| + // Drag |window| out of the dock.
|
| + void UndockWindow(aura::Window* window) {
|
| + gfx::Point drag_to =
|
| + ash::ScreenAsh::GetDisplayWorkAreaBoundsInParent(window).top_right() -
|
| + gfx::Vector2d(10, 0);
|
| + scoped_ptr<WindowResizer> resizer(CreateWindowResizer(
|
| + window,
|
| + window->bounds().origin(),
|
| + HTCAPTION,
|
| + aura::client::WINDOW_MOVE_SOURCE_MOUSE));
|
| + resizer->Drag(drag_to, 0);
|
| + resizer->CompleteDrag();
|
| + EXPECT_NE(internal::kShellWindowId_DockedContainer,
|
| + window->parent()->id());
|
| + }
|
| +
|
| + // Returns the primary display.
|
| + gfx::Display GetPrimaryDisplay() {
|
| + return ash::Shell::GetInstance()->GetScreen()->GetPrimaryDisplay();
|
| + }
|
| +
|
| + // Returns the secondary display.
|
| + gfx::Display GetSecondaryDisplay() {
|
| + return ScreenAsh::GetSecondaryDisplay();
|
| + }
|
| +
|
| + // Returns the window which uses the solo header, if any, on the primary
|
| + // display.
|
| + aura::Window* GetWindowWithSoloHeaderInPrimary() {
|
| + return GetWindowWithSoloHeader(Shell::GetPrimaryRootWindow());
|
| + }
|
| +
|
| + // Returns the window which uses the solo header, if any, in |root|.
|
| + aura::Window* GetWindowWithSoloHeader(aura::Window* root) {
|
| + SoloWindowTracker* solo_window_tracker =
|
| + internal::GetRootWindowController(root)->solo_window_tracker();
|
| + return solo_window_tracker ?
|
| + solo_window_tracker->GetWindowWithSoloHeader() : NULL;
|
| + }
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(SoloWindowTrackerTest);
|
| +};
|
| +
|
| +TEST_F(SoloWindowTrackerTest, Basic) {
|
| + scoped_ptr<aura::Window> w1(CreateWindowInPrimary());
|
| + w1->Show();
|
| +
|
| + // We only have one window, so it should use a solo header.
|
| + EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
|
| +
|
| + // Create a second window.
|
| + scoped_ptr<aura::Window> w2(CreateWindowInPrimary());
|
| + w2->Show();
|
| +
|
| + // Now there are two windows, so we should not use solo headers.
|
| + EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
|
| +
|
| + // Hide one window. Solo should be enabled.
|
| + w2->Hide();
|
| + EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
|
| +
|
| + // Show that window. Solo should be disabled.
|
| + w2->Show();
|
| + EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
|
| +
|
| + // Minimize the first window. Solo should be enabled.
|
| + wm::GetWindowState(w1.get())->Minimize();
|
| + EXPECT_EQ(w2.get(), GetWindowWithSoloHeaderInPrimary());
|
| +
|
| + // Close the minimized window.
|
| + w1.reset();
|
| + EXPECT_EQ(w2.get(), GetWindowWithSoloHeaderInPrimary());
|
| +
|
| + // Open an always-on-top window (which lives in a different container).
|
| + scoped_ptr<aura::Window> w3(CreateAlwaysOnTopWindowInPrimary());
|
| + w3->Show();
|
| + EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
|
| +
|
| + // Close the always-on-top window.
|
| + w3.reset();
|
| + EXPECT_EQ(w2.get(), GetWindowWithSoloHeaderInPrimary());
|
| +}
|
| +
|
| +// Test that docked windows never use the solo header and that the presence of a
|
| +// docked window prevents all other windows from the using the solo window
|
| +// header.
|
| +TEST_F(SoloWindowTrackerTest, DockedWindow) {
|
| + if (!switches::UseDockedWindows() || !SupportsHostWindowResize())
|
| + return;
|
| +
|
| + scoped_ptr<aura::Window> w1(CreateWindowInPrimary());
|
| + w1->Show();
|
| + EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
|
| +
|
| + DockWindow(w1.get());
|
| + EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
|
| +
|
| + UndockWindow(w1.get());
|
| + EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
|
| +
|
| + scoped_ptr<aura::Window> w2(CreateWindowInPrimary());
|
| + w2->Show();
|
| + EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
|
| +
|
| + DockWindow(w2.get());
|
| + EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
|
| +
|
| + wm::GetWindowState(w2.get())->Minimize();
|
| + EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
|
| +}
|
| +
|
| +// Panels should not "count" for computing solo window headers, and the panel
|
| +// itself should never use the solo header.
|
| +TEST_F(SoloWindowTrackerTest, Panel) {
|
| + scoped_ptr<aura::Window> w1(CreateWindowInPrimary());
|
| + w1->Show();
|
| +
|
| + // We only have one window, so it should use a solo header.
|
| + EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
|
| +
|
| + // Create a panel window.
|
| + scoped_ptr<aura::Window> w2(CreatePanelWindowInPrimary());
|
| + w2->Show();
|
| +
|
| + // Despite two windows, the first window should still be considered "solo"
|
| + // because panels aren't included in the computation.
|
| + EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
|
| +
|
| + // Even after closing the first window, the panel is still not considered
|
| + // solo.
|
| + w1.reset();
|
| + EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
|
| +}
|
| +
|
| +// Modal dialogs should not use solo headers.
|
| +TEST_F(SoloWindowTrackerTest, Modal) {
|
| + scoped_ptr<aura::Window> w1(CreateWindowInPrimary());
|
| + w1->Show();
|
| +
|
| + // We only have one window, so it should use a solo header.
|
| + EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
|
| +
|
| + // Create a fake modal window.
|
| + scoped_ptr<aura::Window> w2(CreateWindowInPrimary());
|
| + w2->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
|
| + w2->Show();
|
| +
|
| + // Despite two windows, the first window should still be considered "solo"
|
| + // because modal windows aren't included in the computation.
|
| + EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
|
| +}
|
| +
|
| +// Constrained windows should not use solo headers.
|
| +TEST_F(SoloWindowTrackerTest, Constrained) {
|
| + scoped_ptr<aura::Window> w1(CreateWindowInPrimary());
|
| + w1->Show();
|
| +
|
| + // We only have one window, so it should use a solo header.
|
| + EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
|
| +
|
| + // Create a fake constrained window.
|
| + scoped_ptr<aura::Window> w2(CreateWindowInPrimary());
|
| + w2->SetProperty(aura::client::kConstrainedWindowKey, true);
|
| + w2->Show();
|
| +
|
| + // Despite two windows, the first window should still be considered "solo"
|
| + // because constrained windows aren't included in the computation.
|
| + EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
|
| +}
|
| +
|
| +// Non-drawing windows should not affect the solo computation.
|
| +TEST_F(SoloWindowTrackerTest, NotDrawn) {
|
| + aura::Window* w = CreateWindowInPrimary();
|
| + w->Show();
|
| +
|
| + // We only have one window, so it should use a solo header.
|
| + EXPECT_EQ(w, GetWindowWithSoloHeaderInPrimary());
|
| +
|
| + // Create non-drawing window similar to DragDropTracker.
|
| + aura::Window* not_drawn = new aura::Window(NULL);
|
| + not_drawn->SetType(ui::wm::WINDOW_TYPE_NORMAL);
|
| + not_drawn->Init(aura::WINDOW_LAYER_NOT_DRAWN);
|
| + ParentWindowInPrimaryRootWindow(not_drawn);
|
| + not_drawn->Show();
|
| +
|
| + // Despite two windows, the first window should still be considered "solo"
|
| + // because non-drawing windows aren't included in the computation.
|
| + EXPECT_EQ(w, GetWindowWithSoloHeaderInPrimary());
|
| +}
|
| +
|
| +TEST_F(SoloWindowTrackerTest, MultiDisplay) {
|
| + if (!SupportsMultipleDisplays())
|
| + return;
|
| +
|
| + UpdateDisplay("1000x600,600x400");
|
| +
|
| + scoped_ptr<aura::Window> w1(CreateWindowInPrimary());
|
| + w1->SetBoundsInScreen(gfx::Rect(0, 0, 100, 100), GetPrimaryDisplay());
|
| + w1->Show();
|
| + WindowRepaintChecker checker1(w1.get());
|
| + scoped_ptr<aura::Window> w2(CreateWindowInPrimary());
|
| + w2->SetBoundsInScreen(gfx::Rect(0, 0, 100, 100), GetPrimaryDisplay());
|
| + w2->Show();
|
| + WindowRepaintChecker checker2(w2.get());
|
| +
|
| + // Now there are two windows in the same display, so we should not use solo
|
| + // headers.
|
| + EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
|
| + EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
|
| +
|
| + // Moves the second window to the secondary display. Both w1/w2 should be
|
| + // solo.
|
| + w2->SetBoundsInScreen(gfx::Rect(1200, 0, 100, 100),
|
| + ScreenAsh::GetSecondaryDisplay());
|
| + EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
|
| + EXPECT_EQ(w2.get(), GetWindowWithSoloHeader(w2->GetRootWindow()));
|
| + EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
|
| + EXPECT_TRUE(checker2.IsPaintScheduledAndReset());
|
| +
|
| + // Open two more windows in the primary display.
|
| + scoped_ptr<aura::Window> w3(CreateWindowInPrimary());
|
| + w3->SetBoundsInScreen(gfx::Rect(0, 0, 100, 100), GetPrimaryDisplay());
|
| + w3->Show();
|
| + scoped_ptr<aura::Window> w4(CreateWindowInPrimary());
|
| + w4->SetBoundsInScreen(gfx::Rect(0, 0, 100, 100), GetPrimaryDisplay());
|
| + w4->Show();
|
| +
|
| + // Because the primary display has three windows w1, w3, and w4, they
|
| + // shouldn't be solo. w2 should be solo.
|
| + EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
|
| + EXPECT_EQ(w2.get(), GetWindowWithSoloHeader(w2->GetRootWindow()));
|
| + EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
|
| +
|
| + // Move w4 to the secondary display. Now w2 shouldn't be solo anymore.
|
| + w4->SetBoundsInScreen(gfx::Rect(1200, 0, 100, 100), GetSecondaryDisplay());
|
| + EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
|
| + EXPECT_EQ(NULL, GetWindowWithSoloHeader(w2->GetRootWindow()));
|
| + EXPECT_TRUE(checker2.IsPaintScheduledAndReset());
|
| +
|
| + // Moves w3 to the secondary display too. Now w1 should be solo again.
|
| + w3->SetBoundsInScreen(gfx::Rect(1200, 0, 100, 100), GetSecondaryDisplay());
|
| + EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
|
| + EXPECT_EQ(NULL, GetWindowWithSoloHeader(w2->GetRootWindow()));
|
| + EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
|
| +
|
| + // Change w3's state to maximize. Doesn't affect w1.
|
| + wm::GetWindowState(w3.get())->Maximize();
|
| + EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
|
| + EXPECT_EQ(NULL, GetWindowWithSoloHeader(w2->GetRootWindow()));
|
| +
|
| + // Close w3 and w4.
|
| + w3.reset();
|
| + w4.reset();
|
| + EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
|
| + EXPECT_EQ(w2.get(), GetWindowWithSoloHeader(w2->GetRootWindow()));
|
| + EXPECT_TRUE(checker2.IsPaintScheduledAndReset());
|
| +
|
| + // Move w2 back to the primary display.
|
| + w2->SetBoundsInScreen(gfx::Rect(0, 0, 100, 100), GetPrimaryDisplay());
|
| + EXPECT_EQ(w1->GetRootWindow(), w2->GetRootWindow());
|
| + EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
|
| + EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
|
| + EXPECT_TRUE(checker2.IsPaintScheduledAndReset());
|
| +
|
| + // Close w2.
|
| + w2.reset();
|
| + EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
|
| + EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
|
| +}
|
| +
|
| +TEST_F(SoloWindowTrackerTest, ChildWindowVisibility) {
|
| + aura::Window* w = CreateWindowInPrimary();
|
| + w->Show();
|
| +
|
| + // We only have one window, so it should use a solo header.
|
| + EXPECT_EQ(w, GetWindowWithSoloHeaderInPrimary());
|
| +
|
| + // Create a child window. This should not affect the solo-ness of |w1|.
|
| + aura::Window* child = new aura::Window(NULL);
|
| + child->SetType(ui::wm::WINDOW_TYPE_CONTROL);
|
| + child->Init(aura::WINDOW_LAYER_TEXTURED);
|
| + child->SetBounds(gfx::Rect(100, 100));
|
| + w->AddChild(child);
|
| + child->Show();
|
| + EXPECT_EQ(w, GetWindowWithSoloHeaderInPrimary());
|
| +
|
| + // Changing the visibility of |child| should not affect the solo-ness of |w1|.
|
| + child->Hide();
|
| + EXPECT_EQ(w, GetWindowWithSoloHeaderInPrimary());
|
| +}
|
| +
|
| +TEST_F(SoloWindowTrackerTest, CreateAndDeleteSingleWindow) {
|
| + // Ensure that creating/deleting a window works well and doesn't cause
|
| + // crashes. See crbug.com/155634
|
| + scoped_ptr<aura::Window> w(CreateWindowInPrimary());
|
| + w->Show();
|
| +
|
| + // We only have one window, so it should use a solo header.
|
| + EXPECT_EQ(w.get(), GetWindowWithSoloHeaderInPrimary());
|
| +
|
| + // Close the window.
|
| + w.reset();
|
| + EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
|
| +
|
| + // Recreate another window again.
|
| + w.reset(CreateWindowInPrimary());
|
| + w->Show();
|
| + EXPECT_EQ(w.get(), GetWindowWithSoloHeaderInPrimary());
|
| +}
|
| +
|
| +} // namespace ash
|
|
|