blob: e0c903376ec13919e32fbd1eea222293b9b6501e [file] [log] [blame]
// 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/workspace/snap_sizer.h"
#include "ash/ash_switches.h"
#include "ash/screen_ash.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "ash/wm/window_state.h"
#include "ash/wm/window_util.h"
#include "base/command_line.h"
#include "ui/aura/root_window.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/window.h"
#include "ui/gfx/screen.h"
namespace ash {
typedef test::AshTestBase SnapSizerTest;
using internal::SnapSizer;
// Test that a window gets properly snapped to the display's edges in a
// multi monitor environment.
TEST_F(SnapSizerTest, MultipleDisplays) {
if (!SupportsMultipleDisplays())
return;
UpdateDisplay("0+0-500x400, 0+500-600x400");
const gfx::Rect kPrimaryDisplayWorkAreaBounds =
ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
const gfx::Rect kSecondaryDisplayWorkAreaBounds =
ScreenAsh::GetSecondaryDisplay().work_area();
scoped_ptr<aura::Window> window(
CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
SnapSizer::SnapWindow(window.get(), SnapSizer::LEFT_EDGE);
gfx::Rect expected = gfx::Rect(
kPrimaryDisplayWorkAreaBounds.x(),
kPrimaryDisplayWorkAreaBounds.y(),
window->bounds().width(), // No expectation for the width.
kPrimaryDisplayWorkAreaBounds.height());
EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
SnapSizer::SnapWindow(window.get(), SnapSizer::RIGHT_EDGE);
// The width should not change when a window switches from being snapped to
// the left edge to being snapped to the right edge.
expected.set_x(kPrimaryDisplayWorkAreaBounds.right() - expected.width());
EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
// Move the window to the secondary display.
window->SetBoundsInScreen(gfx::Rect(600, 0, 100, 100),
ScreenAsh::GetSecondaryDisplay());
SnapSizer::SnapWindow(window.get(), SnapSizer::RIGHT_EDGE);
expected = gfx::Rect(
kSecondaryDisplayWorkAreaBounds.right() - window->bounds().width(),
kSecondaryDisplayWorkAreaBounds.y(),
window->bounds().width(), // No expectation for the width.
kSecondaryDisplayWorkAreaBounds.height());
EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
SnapSizer::SnapWindow(window.get(), SnapSizer::LEFT_EDGE);
// The width should not change when a window switches from being snapped to
// the right edge to being snapped to the left edge.
expected.set_x(kSecondaryDisplayWorkAreaBounds.x());
EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
}
// Test how the minimum and maximum size specified by the aura::WindowDelegate
// affect snapping.
TEST_F(SnapSizerTest, MinimumSize) {
if (!SupportsHostWindowResize())
return;
UpdateDisplay("0+0-600x800");
const gfx::Rect kWorkAreaBounds =
ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
aura::test::TestWindowDelegate delegate;
scoped_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
&delegate, -1, gfx::Rect(0, 100, kWorkAreaBounds.width() - 1, 100)));
// It should be possible to snap a window with a minimum size.
delegate.set_minimum_size(gfx::Size(kWorkAreaBounds.width() - 1, 0));
wm::WindowState* window_state = wm::GetWindowState(window.get());
EXPECT_TRUE(window_state->CanSnap());
SnapSizer::SnapWindow(window.get(), SnapSizer::RIGHT_EDGE);
gfx::Rect expected = gfx::Rect(kWorkAreaBounds.x() + 1,
kWorkAreaBounds.y(),
kWorkAreaBounds.width() - 1,
kWorkAreaBounds.height());
EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
// It should not be possible to snap a window with a maximum size.
delegate.set_minimum_size(gfx::Size());
delegate.set_maximum_size(gfx::Size(kWorkAreaBounds.width() - 1, INT_MAX));
EXPECT_FALSE(window_state->CanSnap());
}
// Test that repeadedly calling SnapSizer::SnapWindow() steps through the ideal
// widths in descending order as well as 90% and 50% of the work area's width.
TEST_F(SnapSizerTest, StepThroughSizes) {
if (!SupportsHostWindowResize())
return;
UpdateDisplay("0+0-1024x800");
const gfx::Rect kWorkAreaBounds =
ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
scoped_ptr<aura::Window> window(
CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
// Make sure that the work area is the size we expect it to be.
EXPECT_GT(kWorkAreaBounds.width() * 0.9, 768);
// The first width should be 1024 * 0.9 because the larger ideal widths
// (1280, 1024) > 1024 * 0.9.
SnapSizer::SnapWindow(window.get(), SnapSizer::LEFT_EDGE);
gfx::Rect expected = gfx::Rect(kWorkAreaBounds.x(),
kWorkAreaBounds.y(),
kWorkAreaBounds.width() * 0.9,
kWorkAreaBounds.height());
EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
SnapSizer::SnapWindow(window.get(), SnapSizer::LEFT_EDGE);
expected.set_width(768);
EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
SnapSizer::SnapWindow(window.get(), SnapSizer::LEFT_EDGE);
expected.set_width(640);
EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
SnapSizer::SnapWindow(window.get(), SnapSizer::LEFT_EDGE);
expected.set_width(kWorkAreaBounds.width() * 0.5);
EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
// Wrap around.
SnapSizer::SnapWindow(window.get(), SnapSizer::LEFT_EDGE);
expected.set_width(kWorkAreaBounds.width() * 0.9);
EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
}
// Tests the SnapSizer's target bounds when resizing is disabled.
TEST_F(SnapSizerTest, Default) {
if (!SupportsHostWindowResize())
return;
scoped_ptr<aura::Window> window(
CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
SnapSizer sizer(window.get(), gfx::Point(), SnapSizer::LEFT_EDGE,
SnapSizer::OTHER_INPUT);
// For small workspace widths, we should snap to 90% of the workspace width
// because it is the largest width the window can snap to.
UpdateDisplay("0+0-800x600");
sizer.SelectDefaultSizeAndDisableResize();
gfx::Rect work_area =
ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
gfx::Rect expected(work_area);
expected.set_width(work_area.width() * 0.9);
EXPECT_EQ(expected.ToString(),
ScreenAsh::ConvertRectToScreen(window->parent(),
sizer.target_bounds()).ToString());
// If the largest width the window can snap to is between 1024 and 1280, we
// should snap to 1024.
UpdateDisplay("0+0-1280x800");
sizer.SelectDefaultSizeAndDisableResize();
sizer.SnapWindowToTargetBounds();
EXPECT_EQ(1024, window->bounds().width());
// We should snap to a width of 50% of the work area it is the largest width
// the window can snap to.
UpdateDisplay("0+0-2560x1080");
work_area = ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
sizer.SelectDefaultSizeAndDisableResize();
sizer.SnapWindowToTargetBounds();
EXPECT_EQ(work_area.width() / 2, window->bounds().width());
}
// Test that the window only snaps to 50% of the work area width when using the
// alternate caption button style.
TEST_F(SnapSizerTest, AlternateFrameCaptionButtonStyle) {
if (!SupportsHostWindowResize())
return;
CommandLine::ForCurrentProcess()->AppendSwitch(
ash::switches::kAshEnableAlternateFrameCaptionButtonStyle);
ASSERT_TRUE(ash::switches::UseAlternateFrameCaptionButtonStyle());
UpdateDisplay("0+0-800x600");
const gfx::Rect kWorkAreaBounds =
ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
scoped_ptr<aura::Window> window(
CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
SnapSizer::SnapWindow(window.get(), SnapSizer::LEFT_EDGE);
gfx::Rect expected = gfx::Rect(kWorkAreaBounds.x(),
kWorkAreaBounds.y(),
kWorkAreaBounds.width() / 2,
kWorkAreaBounds.height());
EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
// Because a window can only be snapped to one size when using the alternate
// caption button style, a second call to SnapSizer::SnapWindow() should have
// no effect.
SnapSizer::SnapWindow(window.get(), SnapSizer::LEFT_EDGE);
EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
// It should still be possible to switch a window from being snapped to the
// left edge to being snapped to the right edge.
SnapSizer::SnapWindow(window.get(), SnapSizer::RIGHT_EDGE);
expected.set_x(kWorkAreaBounds.right() - expected.width());
EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
// If resizing is disabled, the window should be snapped to 50% too.
SnapSizer sizer(window.get(), gfx::Point(), SnapSizer::RIGHT_EDGE,
SnapSizer::OTHER_INPUT);
sizer.SelectDefaultSizeAndDisableResize();
sizer.SnapWindowToTargetBounds();
EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
}
// Test that snapping left/right preserves the restore bounds.
TEST_F(SnapSizerTest, RestoreBounds) {
scoped_ptr<aura::Window> window(
CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
wm::WindowState* window_state = wm::GetWindowState(window.get());
EXPECT_TRUE(window_state->IsNormalShowState());
// 1) Start with restored window with restore bounds set.
gfx::Rect restore_bounds = window->GetBoundsInScreen();
restore_bounds.set_width(restore_bounds.width() + 1);
window_state->SetRestoreBoundsInScreen(restore_bounds);
SnapSizer::SnapWindow(window.get(), SnapSizer::LEFT_EDGE);
SnapSizer::SnapWindow(window.get(), SnapSizer::RIGHT_EDGE);
EXPECT_NE(restore_bounds.ToString(), window->GetBoundsInScreen().ToString());
EXPECT_EQ(restore_bounds.ToString(),
window_state->GetRestoreBoundsInScreen().ToString());
window_state->Restore();
EXPECT_EQ(restore_bounds.ToString(), window->GetBoundsInScreen().ToString());
// 2) Start with restored bounds set as a result of maximizing the window.
window_state->Maximize();
gfx::Rect maximized_bounds = window->GetBoundsInScreen();
EXPECT_NE(maximized_bounds.ToString(), restore_bounds.ToString());
EXPECT_EQ(restore_bounds.ToString(),
window_state->GetRestoreBoundsInScreen().ToString());
SnapSizer::SnapWindow(window.get(), SnapSizer::LEFT_EDGE);
EXPECT_NE(restore_bounds.ToString(), window->GetBoundsInScreen().ToString());
EXPECT_NE(maximized_bounds.ToString(),
window->GetBoundsInScreen().ToString());
EXPECT_EQ(restore_bounds.ToString(),
window_state->GetRestoreBoundsInScreen().ToString());
window_state->Restore();
EXPECT_EQ(restore_bounds.ToString(), window->GetBoundsInScreen().ToString());
}
// Test that maximizing an auto managed window, then snapping it puts the window
// at the snapped bounds and not at the auto-managed (centered) bounds.
TEST_F(SnapSizerTest, AutoManaged) {
scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
wm::WindowState* window_state = wm::GetWindowState(window.get());
window_state->set_window_position_managed(true);
window->Hide();
window->SetBounds(gfx::Rect(100, 100, 100, 100));
window->Show();
window_state->Maximize();
SnapSizer::SnapWindow(window.get(), SnapSizer::RIGHT_EDGE);
const gfx::Rect kWorkAreaBounds =
ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
gfx::Rect expected_snapped_bounds(
kWorkAreaBounds.right() - window->bounds().width(),
kWorkAreaBounds.y(),
window->bounds().width(), // No expectation for the width.
kWorkAreaBounds.height());
EXPECT_EQ(expected_snapped_bounds.ToString(),
window->GetBoundsInScreen().ToString());
// The window should still be auto managed despite being right maximized.
EXPECT_TRUE(wm::GetWindowState(window.get())->window_position_managed());
}
} // namespace ash