root_window_controller_unittest.cc revision b2df76ea8fec9e32f6f3718986dba0d95315b29c
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ash/root_window_controller.h"
6
7#include "ash/display/display_controller.h"
8#include "ash/session_state_delegate.h"
9#include "ash/shelf/shelf_layout_manager.h"
10#include "ash/shell.h"
11#include "ash/shell_window_ids.h"
12#include "ash/system/tray/system_tray_delegate.h"
13#include "ash/test/ash_test_base.h"
14#include "ash/wm/system_modal_container_layout_manager.h"
15#include "ash/wm/window_properties.h"
16#include "ash/wm/window_util.h"
17#include "ui/aura/client/focus_change_observer.h"
18#include "ui/aura/client/focus_client.h"
19#include "ui/aura/env.h"
20#include "ui/aura/root_window.h"
21#include "ui/aura/test/event_generator.h"
22#include "ui/aura/test/test_window_delegate.h"
23#include "ui/aura/test/test_windows.h"
24#include "ui/aura/window.h"
25#include "ui/aura/window_tracker.h"
26#include "ui/views/controls/menu/menu_controller.h"
27#include "ui/views/widget/widget.h"
28#include "ui/views/widget/widget_delegate.h"
29
30using aura::Window;
31using views::Widget;
32
33namespace ash {
34namespace {
35
36class TestDelegate : public views::WidgetDelegateView {
37 public:
38  explicit TestDelegate(bool system_modal) : system_modal_(system_modal) {}
39  virtual ~TestDelegate() {}
40
41  // Overridden from views::WidgetDelegate:
42  virtual views::View* GetContentsView() OVERRIDE {
43    return this;
44  }
45
46  virtual ui::ModalType GetModalType() const OVERRIDE {
47    return system_modal_ ? ui::MODAL_TYPE_SYSTEM : ui::MODAL_TYPE_NONE;
48  }
49
50 private:
51  bool system_modal_;
52  DISALLOW_COPY_AND_ASSIGN(TestDelegate);
53};
54
55class DeleteOnBlurDelegate : public aura::test::TestWindowDelegate,
56                             public aura::client::FocusChangeObserver {
57 public:
58  DeleteOnBlurDelegate() : window_(NULL) {}
59  virtual ~DeleteOnBlurDelegate() {}
60
61  void SetWindow(aura::Window* window) {
62    window_ = window;
63    aura::client::SetFocusChangeObserver(window_, this);
64  }
65
66 private:
67  // aura::test::TestWindowDelegate overrides:
68  virtual bool CanFocus() OVERRIDE {
69    return true;
70  }
71
72  // aura::client::FocusChangeObserver implementation:
73  virtual void OnWindowFocused(aura::Window* gained_focus,
74                               aura::Window* lost_focus) OVERRIDE {
75    if (window_ == lost_focus)
76      delete window_;
77  }
78
79  aura::Window* window_;
80
81  DISALLOW_COPY_AND_ASSIGN(DeleteOnBlurDelegate);
82};
83
84}  // namespace
85
86namespace test {
87
88class RootWindowControllerTest : public test::AshTestBase {
89 public:
90  views::Widget* CreateTestWidget(const gfx::Rect& bounds) {
91    views::Widget* widget = views::Widget::CreateWindowWithContextAndBounds(
92        NULL, CurrentContext(), bounds);
93    widget->Show();
94    return widget;
95  }
96
97  views::Widget* CreateModalWidget(const gfx::Rect& bounds) {
98    views::Widget* widget = views::Widget::CreateWindowWithContextAndBounds(
99        new TestDelegate(true), CurrentContext(), bounds);
100    widget->Show();
101    return widget;
102  }
103
104  views::Widget* CreateModalWidgetWithParent(const gfx::Rect& bounds,
105                                             gfx::NativeWindow parent) {
106    views::Widget* widget =
107        views::Widget::CreateWindowWithParentAndBounds(new TestDelegate(true),
108                                                       parent,
109                                                       bounds);
110    widget->Show();
111    return widget;
112  }
113
114  aura::Window* GetModalContainer(aura::RootWindow* root_window) {
115    return Shell::GetContainer(
116        root_window,
117        ash::internal::kShellWindowId_SystemModalContainer);
118  }
119};
120
121#if defined(OS_WIN)
122// Multiple displays are not supported on Windows Ash. http://crbug.com/165962
123#define MAYBE_MoveWindows_Basic DISABLED_MoveWindows_Basic
124#else
125#define MAYBE_MoveWindows_Basic MoveWindows_Basic
126#endif
127
128TEST_F(RootWindowControllerTest, MAYBE_MoveWindows_Basic) {
129  UpdateDisplay("600x600,500x500");
130  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
131  internal::RootWindowController* controller =
132      Shell::GetPrimaryRootWindowController();
133  internal::ShelfLayoutManager* shelf_layout_manager =
134      controller->GetShelfLayoutManager();
135  shelf_layout_manager->SetAutoHideBehavior(
136      ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
137
138  views::Widget* normal = CreateTestWidget(gfx::Rect(650, 10, 100, 100));
139  EXPECT_EQ(root_windows[1], normal->GetNativeView()->GetRootWindow());
140  EXPECT_EQ("650,10 100x100", normal->GetWindowBoundsInScreen().ToString());
141  EXPECT_EQ("50,10 100x100",
142            normal->GetNativeView()->GetBoundsInRootWindow().ToString());
143
144  views::Widget* maximized = CreateTestWidget(gfx::Rect(700, 10, 100, 100));
145  maximized->Maximize();
146  EXPECT_EQ(root_windows[1], maximized->GetNativeView()->GetRootWindow());
147  EXPECT_EQ("600,0 500x452", maximized->GetWindowBoundsInScreen().ToString());
148  EXPECT_EQ("0,0 500x452",
149            maximized->GetNativeView()->GetBoundsInRootWindow().ToString());
150
151  views::Widget* minimized = CreateTestWidget(gfx::Rect(800, 10, 100, 100));
152  minimized->Minimize();
153  EXPECT_EQ(root_windows[1], minimized->GetNativeView()->GetRootWindow());
154  EXPECT_EQ("800,10 100x100",
155            minimized->GetWindowBoundsInScreen().ToString());
156
157  views::Widget* fullscreen = CreateTestWidget(gfx::Rect(900, 10, 100, 100));
158  fullscreen->SetFullscreen(true);
159  EXPECT_EQ(root_windows[1], fullscreen->GetNativeView()->GetRootWindow());
160
161  EXPECT_EQ("600,0 500x500",
162            fullscreen->GetWindowBoundsInScreen().ToString());
163  EXPECT_EQ("0,0 500x500",
164            fullscreen->GetNativeView()->GetBoundsInRootWindow().ToString());
165
166  views::Widget* unparented_control = new Widget;
167  Widget::InitParams params;
168  params.bounds = gfx::Rect(650, 10, 100, 100);
169  params.context = CurrentContext();
170  params.type = Widget::InitParams::TYPE_CONTROL;
171  unparented_control->Init(params);
172  EXPECT_EQ(root_windows[1],
173            unparented_control->GetNativeView()->GetRootWindow());
174  EXPECT_EQ(internal::kShellWindowId_UnparentedControlContainer,
175            unparented_control->GetNativeView()->parent()->id());
176
177  aura::Window* panel = CreateTestWindowInShellWithDelegateAndType(
178      NULL, aura::client::WINDOW_TYPE_PANEL, 0, gfx::Rect(700, 100, 100, 100));
179  EXPECT_EQ(root_windows[1], panel->GetRootWindow());
180  EXPECT_EQ(internal::kShellWindowId_PanelContainer, panel->parent()->id());
181
182  // Make sure a window that will delete itself when losing focus
183  // will not crash.
184  aura::WindowTracker tracker;
185  DeleteOnBlurDelegate delete_on_blur_delegate;
186  aura::Window* d2 = CreateTestWindowInShellWithDelegate(
187      &delete_on_blur_delegate, 0, gfx::Rect(50, 50, 100, 100));
188  delete_on_blur_delegate.SetWindow(d2);
189  aura::client::GetFocusClient(root_windows[0])->FocusWindow(d2);
190  tracker.Add(d2);
191
192  UpdateDisplay("600x600");
193
194  // d2 must have been deleted.
195  EXPECT_FALSE(tracker.Contains(d2));
196
197  EXPECT_EQ(root_windows[0], normal->GetNativeView()->GetRootWindow());
198  EXPECT_EQ("50,10 100x100", normal->GetWindowBoundsInScreen().ToString());
199  EXPECT_EQ("50,10 100x100",
200            normal->GetNativeView()->GetBoundsInRootWindow().ToString());
201
202  // Maximized area on primary display has 3px (given as
203  // kAutoHideSize in shelf_layout_manager.cc) inset at the bottom.
204  EXPECT_EQ(root_windows[0], maximized->GetNativeView()->GetRootWindow());
205  EXPECT_EQ("0,0 600x597",
206            maximized->GetWindowBoundsInScreen().ToString());
207  EXPECT_EQ("0,0 600x597",
208            maximized->GetNativeView()->GetBoundsInRootWindow().ToString());
209
210  EXPECT_EQ(root_windows[0], minimized->GetNativeView()->GetRootWindow());
211  EXPECT_EQ("200,10 100x100",
212            minimized->GetWindowBoundsInScreen().ToString());
213
214  EXPECT_EQ(root_windows[0], fullscreen->GetNativeView()->GetRootWindow());
215  EXPECT_TRUE(fullscreen->IsFullscreen());
216  EXPECT_EQ("0,0 600x600",
217            fullscreen->GetWindowBoundsInScreen().ToString());
218  EXPECT_EQ("0,0 600x600",
219            fullscreen->GetNativeView()->GetBoundsInRootWindow().ToString());
220
221  // Test if the restore bounds are correctly updated.
222  wm::RestoreWindow(maximized->GetNativeView());
223  EXPECT_EQ("100,10 100x100", maximized->GetWindowBoundsInScreen().ToString());
224  EXPECT_EQ("100,10 100x100",
225            maximized->GetNativeView()->GetBoundsInRootWindow().ToString());
226
227  fullscreen->SetFullscreen(false);
228  EXPECT_EQ("300,10 100x100",
229            fullscreen->GetWindowBoundsInScreen().ToString());
230  EXPECT_EQ("300,10 100x100",
231            fullscreen->GetNativeView()->GetBoundsInRootWindow().ToString());
232
233  // Test if the unparented widget has moved.
234  EXPECT_EQ(root_windows[0],
235            unparented_control->GetNativeView()->GetRootWindow());
236  EXPECT_EQ(internal::kShellWindowId_UnparentedControlContainer,
237            unparented_control->GetNativeView()->parent()->id());
238
239  // Test if the panel has moved.
240  EXPECT_EQ(root_windows[0], panel->GetRootWindow());
241  EXPECT_EQ(internal::kShellWindowId_PanelContainer, panel->parent()->id());
242}
243
244#if defined(OS_WIN)
245// Multiple displays are not supported on Windows Ash. http://crbug.com/165962
246#define MAYBE_MoveWindows_Modal DISABLED_MoveWindows_Modal
247#else
248#define MAYBE_MoveWindows_Modal MoveWindows_Modal
249#endif
250
251TEST_F(RootWindowControllerTest, MAYBE_MoveWindows_Modal) {
252  UpdateDisplay("500x500,500x500");
253
254  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
255  // Emulate virtual screen coordinate system.
256  root_windows[0]->SetBounds(gfx::Rect(0, 0, 500, 500));
257  root_windows[1]->SetBounds(gfx::Rect(500, 0, 500, 500));
258
259  views::Widget* normal = CreateTestWidget(gfx::Rect(300, 10, 100, 100));
260  EXPECT_EQ(root_windows[0], normal->GetNativeView()->GetRootWindow());
261  EXPECT_TRUE(wm::IsActiveWindow(normal->GetNativeView()));
262
263  views::Widget* modal = CreateModalWidget(gfx::Rect(650, 10, 100, 100));
264  EXPECT_EQ(root_windows[1], modal->GetNativeView()->GetRootWindow());
265  EXPECT_TRUE(GetModalContainer(root_windows[1])->Contains(
266      modal->GetNativeView()));
267  EXPECT_TRUE(wm::IsActiveWindow(modal->GetNativeView()));
268
269  aura::test::EventGenerator generator_1st(root_windows[0]);
270  generator_1st.ClickLeftButton();
271  EXPECT_TRUE(wm::IsActiveWindow(modal->GetNativeView()));
272
273  UpdateDisplay("500x500");
274  EXPECT_EQ(root_windows[0], modal->GetNativeView()->GetRootWindow());
275  EXPECT_TRUE(wm::IsActiveWindow(modal->GetNativeView()));
276  generator_1st.ClickLeftButton();
277  EXPECT_TRUE(wm::IsActiveWindow(modal->GetNativeView()));
278}
279
280TEST_F(RootWindowControllerTest, ModalContainer) {
281  UpdateDisplay("600x600");
282  Shell* shell = Shell::GetInstance();
283  internal::RootWindowController* controller =
284      shell->GetPrimaryRootWindowController();
285  EXPECT_EQ(user::LOGGED_IN_USER,
286            shell->system_tray_delegate()->GetUserLoginStatus());
287  EXPECT_EQ(Shell::GetContainer(controller->root_window(),
288      internal::kShellWindowId_SystemModalContainer)->layout_manager(),
289          controller->GetSystemModalLayoutManager(NULL));
290
291  views::Widget* session_modal_widget =
292      CreateModalWidget(gfx::Rect(300, 10, 100, 100));
293  EXPECT_EQ(Shell::GetContainer(controller->root_window(),
294      internal::kShellWindowId_SystemModalContainer)->layout_manager(),
295          controller->GetSystemModalLayoutManager(
296              session_modal_widget->GetNativeView()));
297
298  shell->session_state_delegate()->LockScreen();
299  EXPECT_EQ(user::LOGGED_IN_LOCKED,
300            shell->system_tray_delegate()->GetUserLoginStatus());
301  EXPECT_EQ(Shell::GetContainer(controller->root_window(),
302      internal::kShellWindowId_LockSystemModalContainer)->layout_manager(),
303          controller->GetSystemModalLayoutManager(NULL));
304
305  aura::Window* lock_container =
306      Shell::GetContainer(controller->root_window(),
307                          internal::kShellWindowId_LockScreenContainer);
308  views::Widget* lock_modal_widget =
309      CreateModalWidgetWithParent(gfx::Rect(300, 10, 100, 100), lock_container);
310  EXPECT_EQ(Shell::GetContainer(controller->root_window(),
311      internal::kShellWindowId_LockSystemModalContainer)->layout_manager(),
312          controller->GetSystemModalLayoutManager(
313              lock_modal_widget->GetNativeView()));
314  EXPECT_EQ(Shell::GetContainer(controller->root_window(),
315        internal::kShellWindowId_SystemModalContainer)->layout_manager(),
316            controller->GetSystemModalLayoutManager(
317                session_modal_widget->GetNativeView()));
318
319  shell->session_state_delegate()->UnlockScreen();
320}
321
322TEST_F(RootWindowControllerTest, ModalContainerNotLoggedInLoggedIn) {
323  UpdateDisplay("600x600");
324  Shell* shell = Shell::GetInstance();
325
326  // Configure login screen environment.
327  SetUserLoggedIn(false);
328  EXPECT_EQ(user::LOGGED_IN_NONE,
329            shell->system_tray_delegate()->GetUserLoginStatus());
330  EXPECT_FALSE(shell->session_state_delegate()->HasActiveUser());
331  EXPECT_FALSE(shell->session_state_delegate()->IsActiveUserSessionStarted());
332
333  internal::RootWindowController* controller =
334      shell->GetPrimaryRootWindowController();
335  EXPECT_EQ(Shell::GetContainer(controller->root_window(),
336      internal::kShellWindowId_LockSystemModalContainer)->layout_manager(),
337          controller->GetSystemModalLayoutManager(NULL));
338
339  aura::Window* lock_container =
340      Shell::GetContainer(controller->root_window(),
341                          internal::kShellWindowId_LockScreenContainer);
342  views::Widget* login_modal_widget =
343      CreateModalWidgetWithParent(gfx::Rect(300, 10, 100, 100), lock_container);
344  EXPECT_EQ(Shell::GetContainer(controller->root_window(),
345      internal::kShellWindowId_LockSystemModalContainer)->layout_manager(),
346          controller->GetSystemModalLayoutManager(
347              login_modal_widget->GetNativeView()));
348  login_modal_widget->Close();
349
350  // Configure user session environment.
351  SetUserLoggedIn(true);
352  SetSessionStarted(true);
353  EXPECT_EQ(user::LOGGED_IN_USER,
354            shell->system_tray_delegate()->GetUserLoginStatus());
355  EXPECT_TRUE(shell->session_state_delegate()->HasActiveUser());
356  EXPECT_TRUE(shell->session_state_delegate()->IsActiveUserSessionStarted());
357  EXPECT_EQ(Shell::GetContainer(controller->root_window(),
358      internal::kShellWindowId_SystemModalContainer)->layout_manager(),
359          controller->GetSystemModalLayoutManager(NULL));
360
361  views::Widget* session_modal_widget =
362        CreateModalWidget(gfx::Rect(300, 10, 100, 100));
363  EXPECT_EQ(Shell::GetContainer(controller->root_window(),
364      internal::kShellWindowId_SystemModalContainer)->layout_manager(),
365          controller->GetSystemModalLayoutManager(
366              session_modal_widget->GetNativeView()));
367}
368
369// Test that GetFullscreenWindow() returns a fullscreen window only if the
370// fullscreen window is in the active workspace.
371TEST_F(RootWindowControllerTest, GetFullscreenWindow) {
372  UpdateDisplay("600x600");
373  internal::RootWindowController* controller =
374      Shell::GetInstance()->GetPrimaryRootWindowController();
375
376  Widget* w1 = CreateTestWidget(gfx::Rect(0, 0, 100, 100));
377  w1->Maximize();
378  Widget* w2 = CreateTestWidget(gfx::Rect(0, 0, 100, 100));
379  w2->SetFullscreen(true);
380  // |w3| is a transient child of |w2|.
381  Widget* w3 = Widget::CreateWindowWithParentAndBounds(NULL,
382      w2->GetNativeWindow(), gfx::Rect(0, 0, 100, 100));
383
384  // Test that GetFullscreenWindow() finds the fullscreen window when one of
385  // its transient children is active.
386  w3->Activate();
387  EXPECT_EQ(w2->GetNativeWindow(), controller->GetFullscreenWindow());
388
389  // Activate the maximized window's workspace. GetFullscreenWindow() should
390  // fail because the fullscreen window's workspace is no longer active.
391  w1->Activate();
392  EXPECT_FALSE(controller->GetFullscreenWindow());
393
394  // If the fullscreen window is active, GetFullscreenWindow() should find it.
395  w2->Activate();
396  EXPECT_EQ(w2->GetNativeWindow(), controller->GetFullscreenWindow());
397}
398
399}  // namespace test
400}  // namespace ash
401