1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// found in the LICENSE file.
4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/wm/window_state.h"
6a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/screen_util.h"
8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/shell.h"
9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/test/ash_test_base.h"
10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/wm/window_state.h"
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/wm/wm_event.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/aura/client/aura_constants.h"
13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/aura/test/test_window_delegate.h"
14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/aura/window.h"
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace ash {
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace wm {
1823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)namespace {
1923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
2023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)class AlwaysMaximizeTestState : public WindowState::State {
2123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) public:
2223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  explicit AlwaysMaximizeTestState(WindowStateType initial_state_type)
2323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      : state_type_(initial_state_type) {}
2423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  virtual ~AlwaysMaximizeTestState() {}
2523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
2623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // WindowState::State overrides:
2723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  virtual void OnWMEvent(WindowState* window_state,
2823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                         const WMEvent* event) OVERRIDE {
2923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    // We don't do anything here.
3023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
3123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  virtual WindowStateType GetType() const OVERRIDE {
3223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return state_type_;
3323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
3423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  virtual void AttachState(
3523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      WindowState* window_state,
3623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      WindowState::State* previous_state) OVERRIDE {
3723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    // We always maximize.
3823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (state_type_ != WINDOW_STATE_TYPE_MAXIMIZED) {
3923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      window_state->Maximize();
4023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      state_type_ = WINDOW_STATE_TYPE_MAXIMIZED;
4123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
4223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
4323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  virtual void DetachState(WindowState* window_state) OVERRIDE {}
4423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
4523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) private:
4623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  WindowStateType state_type_;
4723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
4823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(AlwaysMaximizeTestState);
4923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)};
5023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
5123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}  // namespace
52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)typedef test::AshTestBase WindowStateTest;
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Test that a window gets properly snapped to the display's edges in a
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// multi monitor environment.
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TEST_F(WindowStateTest, SnapWindowBasic) {
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!SupportsMultipleDisplays())
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  UpdateDisplay("0+0-500x400, 0+500-600x400");
62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const gfx::Rect kPrimaryDisplayWorkAreaBounds =
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const gfx::Rect kSecondaryDisplayWorkAreaBounds =
65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ScreenUtil::GetSecondaryDisplay().work_area();
66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<aura::Window> window(
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
6923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  WindowState* window_state = GetWindowState(window.get());
7023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  const WMEvent snap_left(WM_EVENT_SNAP_LEFT);
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  window_state->OnWMEvent(&snap_left);
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  gfx::Rect expected = gfx::Rect(
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      kPrimaryDisplayWorkAreaBounds.x(),
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      kPrimaryDisplayWorkAreaBounds.y(),
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      kPrimaryDisplayWorkAreaBounds.width() / 2,
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      kPrimaryDisplayWorkAreaBounds.height());
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
7923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  const WMEvent snap_right(WM_EVENT_SNAP_RIGHT);
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  window_state->OnWMEvent(&snap_right);
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  expected.set_x(kPrimaryDisplayWorkAreaBounds.right() - expected.width());
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Move the window to the secondary display.
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  window->SetBoundsInScreen(gfx::Rect(600, 0, 100, 100),
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                            ScreenUtil::GetSecondaryDisplay());
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  window_state->OnWMEvent(&snap_right);
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  expected = gfx::Rect(
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      kSecondaryDisplayWorkAreaBounds.x() +
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          kSecondaryDisplayWorkAreaBounds.width() / 2,
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      kSecondaryDisplayWorkAreaBounds.y(),
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      kSecondaryDisplayWorkAreaBounds.width() / 2,
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      kSecondaryDisplayWorkAreaBounds.height());
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  window_state->OnWMEvent(&snap_left);
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  expected.set_x(kSecondaryDisplayWorkAreaBounds.x());
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Test how the minimum and maximum size specified by the aura::WindowDelegate
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// affect snapping.
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TEST_F(WindowStateTest, SnapWindowMinimumSize) {
105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!SupportsHostWindowResize())
106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  UpdateDisplay("0+0-600x900");
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const gfx::Rect kWorkAreaBounds =
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  aura::test::TestWindowDelegate delegate;
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      &delegate, -1, gfx::Rect(0, 100, kWorkAreaBounds.width() - 1, 100)));
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // It should be possible to snap a window with a minimum size.
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  delegate.set_minimum_size(gfx::Size(kWorkAreaBounds.width() - 1, 0));
11823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  WindowState* window_state = GetWindowState(window.get());
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_TRUE(window_state->CanSnap());
12023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  const WMEvent snap_right(WM_EVENT_SNAP_RIGHT);
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  window_state->OnWMEvent(&snap_right);
122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  gfx::Rect expected = gfx::Rect(kWorkAreaBounds.x() + 1,
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 kWorkAreaBounds.y(),
124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 kWorkAreaBounds.width() - 1,
125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 kWorkAreaBounds.height());
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // It should not be possible to snap a window with a maximum size, or if it
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // cannot be maximized.
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  delegate.set_maximum_size(gfx::Size(kWorkAreaBounds.width() - 1, 0));
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_FALSE(window_state->CanSnap());
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  delegate.set_maximum_size(gfx::Size(0, kWorkAreaBounds.height() - 1));
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_FALSE(window_state->CanSnap());
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  delegate.set_maximum_size(gfx::Size());
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  window->SetProperty(aura::client::kCanMaximizeKey, false);
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_FALSE(window_state->CanSnap());
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Test that the minimum size specified by aura::WindowDelegate gets respected.
1405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuTEST_F(WindowStateTest, TestRespectMinimumSize) {
1415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!SupportsHostWindowResize())
1425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return;
1435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  UpdateDisplay("0+0-1024x768");
1455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  aura::test::TestWindowDelegate delegate;
1475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  const gfx::Size minimum_size(gfx::Size(500, 300));
1485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  delegate.set_minimum_size(minimum_size);
1495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  scoped_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
1515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      &delegate, -1, gfx::Rect(0, 100, 100, 100)));
1525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Check that the window has the correct minimum size.
1545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  EXPECT_EQ(minimum_size.ToString(), window->bounds().size().ToString());
1555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Set the size to something bigger - that should work.
1575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  gfx::Rect bigger_bounds(700, 500, 700, 500);
1585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  window->SetBounds(bigger_bounds);
1595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  EXPECT_EQ(bigger_bounds.ToString(), window->bounds().ToString());
1605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Set the size to something smaller - that should only resize to the smallest
1625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // possible size.
1635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  gfx::Rect smaller_bounds(700, 500, 100, 100);
1645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  window->SetBounds(smaller_bounds);
1655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  EXPECT_EQ(minimum_size.ToString(), window->bounds().size().ToString());
1665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Test that the minimum window size specified by aura::WindowDelegate does not
1695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// exceed the screen size.
1705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuTEST_F(WindowStateTest, TestIgnoreTooBigMinimumSize) {
1715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!SupportsHostWindowResize())
1725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return;
1735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  UpdateDisplay("0+0-1024x768");
1755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  const gfx::Size work_area_size =
1765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      ash::Shell::GetScreen()->GetPrimaryDisplay().work_area().size();
1775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  const gfx::Size illegal_size(1280, 960);
1785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  const gfx::Rect illegal_bounds(gfx::Point(0, 0), illegal_size);
1795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  aura::test::TestWindowDelegate delegate;
1815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  const gfx::Size minimum_size(illegal_size);
1825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  delegate.set_minimum_size(minimum_size);
1835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // The creation should force the window to respect the screen size.
1855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  scoped_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
1865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      &delegate, -1, illegal_bounds));
1875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  EXPECT_EQ(work_area_size.ToString(), window->bounds().size().ToString());
1885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Trying to set the size to something bigger then the screen size should be
1905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // ignored.
1915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  window->SetBounds(illegal_bounds);
1925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  EXPECT_EQ(work_area_size.ToString(), window->bounds().size().ToString());
1935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Maximizing the window should not allow it to go bigger than that either.
1955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  WindowState* window_state = GetWindowState(window.get());
1965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  window_state->Maximize();
1975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  EXPECT_EQ(work_area_size.ToString(), window->bounds().size().ToString());
1985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Test that setting the bounds of a snapped window keeps its snapped.
201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TEST_F(WindowStateTest, SnapWindowSetBounds) {
202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!SupportsHostWindowResize())
203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  UpdateDisplay("0+0-900x600");
206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const gfx::Rect kWorkAreaBounds =
207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
208a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
209a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<aura::Window> window(
210a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
21123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  WindowState* window_state = GetWindowState(window.get());
21223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  const WMEvent snap_left(WM_EVENT_SNAP_LEFT);
213a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  window_state->OnWMEvent(&snap_left);
214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(WINDOW_STATE_TYPE_LEFT_SNAPPED, window_state->GetStateType());
215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  gfx::Rect expected = gfx::Rect(kWorkAreaBounds.x(),
216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 kWorkAreaBounds.y(),
217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 kWorkAreaBounds.width() / 2,
218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 kWorkAreaBounds.height());
219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Snapped windows can have any width.
222a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  expected.set_width(500);
223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  window->SetBounds(gfx::Rect(10, 10, 500, 300));
224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(WINDOW_STATE_TYPE_LEFT_SNAPPED, window_state->GetStateType());
226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Test that snapping left/right preserves the restore bounds.
229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TEST_F(WindowStateTest, RestoreBounds) {
230a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<aura::Window> window(
231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
23223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  WindowState* window_state = GetWindowState(window.get());
233a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
234a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_TRUE(window_state->IsNormalStateType());
235a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // 1) Start with restored window with restore bounds set.
237a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  gfx::Rect restore_bounds = window->GetBoundsInScreen();
238a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  restore_bounds.set_width(restore_bounds.width() + 1);
239a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  window_state->SetRestoreBoundsInScreen(restore_bounds);
24023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  const WMEvent snap_left(WM_EVENT_SNAP_LEFT);
241a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  window_state->OnWMEvent(&snap_left);
24223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  const WMEvent snap_right(WM_EVENT_SNAP_RIGHT);
243a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  window_state->OnWMEvent(&snap_right);
244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_NE(restore_bounds.ToString(), window->GetBoundsInScreen().ToString());
245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(restore_bounds.ToString(),
246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            window_state->GetRestoreBoundsInScreen().ToString());
247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  window_state->Restore();
248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(restore_bounds.ToString(), window->GetBoundsInScreen().ToString());
249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
250a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // 2) Start with restored bounds set as a result of maximizing the window.
251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  window_state->Maximize();
252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  gfx::Rect maximized_bounds = window->GetBoundsInScreen();
253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_NE(maximized_bounds.ToString(), restore_bounds.ToString());
254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(restore_bounds.ToString(),
255a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            window_state->GetRestoreBoundsInScreen().ToString());
256a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
257a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  window_state->OnWMEvent(&snap_left);
258a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_NE(restore_bounds.ToString(), window->GetBoundsInScreen().ToString());
259a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_NE(maximized_bounds.ToString(),
260a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            window->GetBoundsInScreen().ToString());
261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(restore_bounds.ToString(),
262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            window_state->GetRestoreBoundsInScreen().ToString());
263a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
264a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  window_state->Restore();
265a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(restore_bounds.ToString(), window->GetBoundsInScreen().ToString());
266a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
267a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
268a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Test that maximizing an auto managed window, then snapping it puts the window
269a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// at the snapped bounds and not at the auto-managed (centered) bounds.
270a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TEST_F(WindowStateTest, AutoManaged) {
271a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
27223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  WindowState* window_state = GetWindowState(window.get());
273a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  window_state->set_window_position_managed(true);
274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  window->Hide();
275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  window->SetBounds(gfx::Rect(100, 100, 100, 100));
276a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  window->Show();
277a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
278a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  window_state->Maximize();
27923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  const WMEvent snap_right(WM_EVENT_SNAP_RIGHT);
280a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  window_state->OnWMEvent(&snap_right);
281a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
282a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const gfx::Rect kWorkAreaBounds =
283a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
284a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  gfx::Rect expected_snapped_bounds(
285a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      kWorkAreaBounds.x() + kWorkAreaBounds.width() / 2,
286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      kWorkAreaBounds.y(),
287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      kWorkAreaBounds.width() / 2,
288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      kWorkAreaBounds.height());
289a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(expected_snapped_bounds.ToString(),
290a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            window->GetBoundsInScreen().ToString());
291a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
292a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // The window should still be auto managed despite being right maximized.
293a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_TRUE(window_state->window_position_managed());
294a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
295a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
29623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// Test that the replacement of a State object works as expected.
29723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)TEST_F(WindowStateTest, SimpleStateSwap) {
29823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
29923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  WindowState* window_state = GetWindowState(window.get());
30023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_FALSE(window_state->IsMaximized());
30123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  window_state->SetStateObject(
30223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      scoped_ptr<WindowState::State> (new AlwaysMaximizeTestState(
30323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          window_state->GetStateType())));
30423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_TRUE(window_state->IsMaximized());
30523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
30623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
30723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// Test that the replacement of a state object, following a restore with the
30823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// original one restores the window to its original state.
30923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)TEST_F(WindowStateTest, StateSwapRestore) {
31023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
31123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  WindowState* window_state = GetWindowState(window.get());
31223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_FALSE(window_state->IsMaximized());
31323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  scoped_ptr<WindowState::State> old(window_state->SetStateObject(
31423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      scoped_ptr<WindowState::State> (new AlwaysMaximizeTestState(
31523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          window_state->GetStateType()))).Pass());
31623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_TRUE(window_state->IsMaximized());
31723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  window_state->SetStateObject(old.Pass());
31823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_FALSE(window_state->IsMaximized());
31923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
32023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
3215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Tests that a window that had same bounds as the work area shrinks after the
3225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// window is maximized and then restored.
3235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)TEST_F(WindowStateTest, RestoredWindowBoundsShrink) {
3245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
3255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  WindowState* window_state = GetWindowState(window.get());
3265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_FALSE(window_state->IsMaximized());
3275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  gfx::Rect work_area =
3285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
3295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  window->SetBounds(work_area);
3315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  window_state->Maximize();
3325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_TRUE(window_state->IsMaximized());
3335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_EQ(work_area.ToString(), window->bounds().ToString());
3345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  window_state->Restore();
3365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_FALSE(window_state->IsMaximized());
3375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_NE(work_area.ToString(), window->bounds().ToString());
3385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_TRUE(work_area.Contains(window->bounds()));
3395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
34123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// TODO(skuhne): Add more unit test to verify the correctness for the restore
34223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// operation.
34323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
344a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace wm
345a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace ash
346