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.
10 #include "ash/ash_switches.h"
11 #include "ash/desktop_background/desktop_background_widget_controller.h"
12 #include "ash/launcher/launcher.h"
13 #include "ash/root_window_controller.h"
14 #include "ash/shell_delegate.h"
15 #include "ash/shell_window_ids.h"
16 #include "ash/test/ash_test_base.h"
17 #include "ash/wm/root_window_layout_manager.h"
18 #include "ash/wm/shelf_layout_manager.h"
19 #include "ash/wm/window_util.h"
20 #include "base/utf_string_conversions.h"
21 #include "ui/aura/client/aura_constants.h"
22 #include "ui/aura/root_window.h"
23 #include "ui/aura/window.h"
24 #include "ui/gfx/size.h"
25 #include "ui/views/widget/widget.h"
26 #include "ui/views/widget/widget_delegate.h"
28 using aura::RootWindow
;
34 views::Widget
* CreateTestWindow(const views::Widget::InitParams
& params
) {
35 views::Widget
* widget
= new views::Widget
;
40 aura::Window
* GetDefaultContainer() {
41 return Shell::GetContainer(
42 Shell::GetPrimaryRootWindow(),
43 internal::kShellWindowId_DefaultContainer
);
46 aura::Window
* GetAlwaysOnTopContainer() {
47 return Shell::GetContainer(
48 Shell::GetPrimaryRootWindow(),
49 internal::kShellWindowId_AlwaysOnTopContainer
);
52 // Expect ALL the containers!
53 void ExpectAllContainers() {
54 aura::RootWindow
* root_window
= Shell::GetPrimaryRootWindow();
55 EXPECT_TRUE(Shell::GetContainer(
56 root_window
, internal::kShellWindowId_DesktopBackgroundContainer
));
57 EXPECT_TRUE(Shell::GetContainer(
58 root_window
, internal::kShellWindowId_DefaultContainer
));
59 EXPECT_TRUE(Shell::GetContainer(
60 root_window
, internal::kShellWindowId_AlwaysOnTopContainer
));
61 EXPECT_TRUE(Shell::GetContainer(
62 root_window
, internal::kShellWindowId_PanelContainer
));
63 EXPECT_TRUE(Shell::GetContainer(
64 root_window
, internal::kShellWindowId_LauncherContainer
));
65 EXPECT_TRUE(Shell::GetContainer(
66 root_window
, internal::kShellWindowId_SystemModalContainer
));
67 EXPECT_TRUE(Shell::GetContainer(
68 root_window
, internal::kShellWindowId_LockScreenBackgroundContainer
));
69 EXPECT_TRUE(Shell::GetContainer(
70 root_window
, internal::kShellWindowId_LockScreenContainer
));
71 EXPECT_TRUE(Shell::GetContainer(
72 root_window
, internal::kShellWindowId_LockSystemModalContainer
));
73 EXPECT_TRUE(Shell::GetContainer(
74 root_window
, internal::kShellWindowId_StatusContainer
));
75 EXPECT_TRUE(Shell::GetContainer(
76 root_window
, internal::kShellWindowId_MenuContainer
));
77 EXPECT_TRUE(Shell::GetContainer(
78 root_window
, internal::kShellWindowId_DragImageAndTooltipContainer
));
79 EXPECT_TRUE(Shell::GetContainer(
80 root_window
, internal::kShellWindowId_SettingBubbleContainer
));
81 EXPECT_TRUE(Shell::GetContainer(
82 root_window
, internal::kShellWindowId_OverlayContainer
));
85 void TestCreateWindow(views::Widget::InitParams::Type type
,
87 aura::Window
* expected_container
) {
88 views::Widget::InitParams
widget_params(type
);
89 widget_params
.keep_on_top
= always_on_top
;
91 views::Widget
* widget
= CreateTestWindow(widget_params
);
94 EXPECT_TRUE(expected_container
->Contains(
95 widget
->GetNativeWindow()->parent())) <<
96 "TestCreateWindow: type=" << type
<< ", always_on_top=" << always_on_top
;
101 class ModalWindow
: public views::WidgetDelegateView
{
104 virtual ~ModalWindow() {}
106 // Overridden from views::WidgetDelegate:
107 virtual views::View
* GetContentsView() OVERRIDE
{
110 virtual bool CanResize() const OVERRIDE
{
113 virtual string16
GetWindowTitle() const OVERRIDE
{
114 return ASCIIToUTF16("Modal Window");
116 virtual ui::ModalType
GetModalType() const OVERRIDE
{
117 return ui::MODAL_TYPE_SYSTEM
;
121 DISALLOW_COPY_AND_ASSIGN(ModalWindow
);
126 typedef test::AshTestBase ShellTest
;
128 TEST_F(ShellTest
, CreateWindow
) {
129 // Normal window should be created in default container.
130 TestCreateWindow(views::Widget::InitParams::TYPE_WINDOW
,
131 false, // always_on_top
132 GetDefaultContainer());
133 TestCreateWindow(views::Widget::InitParams::TYPE_POPUP
,
134 false, // always_on_top
135 GetDefaultContainer());
137 // Always-on-top window and popup are created in always-on-top container.
138 TestCreateWindow(views::Widget::InitParams::TYPE_WINDOW
,
139 true, // always_on_top
140 GetAlwaysOnTopContainer());
141 TestCreateWindow(views::Widget::InitParams::TYPE_POPUP
,
142 true, // always_on_top
143 GetAlwaysOnTopContainer());
146 TEST_F(ShellTest
, ChangeAlwaysOnTop
) {
147 views::Widget::InitParams
widget_params(
148 views::Widget::InitParams::TYPE_WINDOW
);
150 // Creates a normal window
151 views::Widget
* widget
= CreateTestWindow(widget_params
);
154 // It should be in default container.
155 EXPECT_TRUE(GetDefaultContainer()->Contains(
156 widget
->GetNativeWindow()->parent()));
158 // Flip always-on-top flag.
159 widget
->SetAlwaysOnTop(true);
160 // And it should in always on top container now.
161 EXPECT_EQ(GetAlwaysOnTopContainer(), widget
->GetNativeWindow()->parent());
163 // Flip always-on-top flag.
164 widget
->SetAlwaysOnTop(false);
165 // It should go back to default container.
166 EXPECT_TRUE(GetDefaultContainer()->Contains(
167 widget
->GetNativeWindow()->parent()));
169 // Set the same always-on-top flag again.
170 widget
->SetAlwaysOnTop(false);
171 // Should have no effect and we are still in the default container.
172 EXPECT_TRUE(GetDefaultContainer()->Contains(
173 widget
->GetNativeWindow()->parent()));
178 TEST_F(ShellTest
, CreateModalWindow
) {
179 views::Widget::InitParams
widget_params(
180 views::Widget::InitParams::TYPE_WINDOW
);
182 // Create a normal window.
183 views::Widget
* widget
= CreateTestWindow(widget_params
);
186 // It should be in default container.
187 EXPECT_TRUE(GetDefaultContainer()->Contains(
188 widget
->GetNativeWindow()->parent()));
190 // Create a modal window.
191 views::Widget
* modal_widget
= views::Widget::CreateWindowWithParent(
192 new ModalWindow(), widget
->GetNativeView());
193 modal_widget
->Show();
195 // It should be in modal container.
196 aura::Window
* modal_container
= Shell::GetContainer(
197 Shell::GetPrimaryRootWindow(),
198 internal::kShellWindowId_SystemModalContainer
);
199 EXPECT_EQ(modal_container
, modal_widget
->GetNativeWindow()->parent());
201 modal_widget
->Close();
205 TEST_F(ShellTest
, CreateLockScreenModalWindow
) {
206 views::Widget::InitParams
widget_params(
207 views::Widget::InitParams::TYPE_WINDOW
);
209 // Create a normal window.
210 views::Widget
* widget
= CreateTestWindow(widget_params
);
213 // It should be in default container.
214 EXPECT_TRUE(GetDefaultContainer()->Contains(
215 widget
->GetNativeWindow()->parent()));
217 Shell::GetInstance()->delegate()->LockScreen();
218 // Create a LockScreen window.
219 views::Widget
* lock_widget
= CreateTestWindow(widget_params
);
220 ash::Shell::GetContainer(
221 Shell::GetPrimaryRootWindow(),
222 ash::internal::kShellWindowId_LockScreenContainer
)->
223 AddChild(lock_widget
->GetNativeView());
226 // It should be in LockScreen container.
227 aura::Window
* lock_screen
= Shell::GetContainer(
228 Shell::GetPrimaryRootWindow(),
229 ash::internal::kShellWindowId_LockScreenContainer
);
230 EXPECT_EQ(lock_screen
, lock_widget
->GetNativeWindow()->parent());
232 // Create a modal window with a lock window as parent.
233 views::Widget
* lock_modal_widget
= views::Widget::CreateWindowWithParent(
234 new ModalWindow(), lock_widget
->GetNativeView());
235 lock_modal_widget
->Show();
237 // It should be in LockScreen modal container.
238 aura::Window
* lock_modal_container
= Shell::GetContainer(
239 Shell::GetPrimaryRootWindow(),
240 ash::internal::kShellWindowId_LockSystemModalContainer
);
241 EXPECT_EQ(lock_modal_container
,
242 lock_modal_widget
->GetNativeWindow()->parent());
244 // Create a modal window with a normal window as parent.
245 views::Widget
* modal_widget
= views::Widget::CreateWindowWithParent(
246 new ModalWindow(), widget
->GetNativeView());
247 modal_widget
->Show();
249 // It should be in non-LockScreen modal container.
250 aura::Window
* modal_container
= Shell::GetContainer(
251 Shell::GetPrimaryRootWindow(),
252 ash::internal::kShellWindowId_SystemModalContainer
);
253 EXPECT_EQ(modal_container
, modal_widget
->GetNativeWindow()->parent());
255 modal_widget
->Close();
256 lock_modal_widget
->Close();
257 lock_widget
->Close();
261 TEST_F(ShellTest
, IsScreenLocked
) {
262 ash::Shell::GetInstance()->delegate()->LockScreen();
263 EXPECT_TRUE(Shell::GetInstance()->IsScreenLocked());
264 ash::Shell::GetInstance()->delegate()->UnlockScreen();
265 EXPECT_FALSE(Shell::GetInstance()->IsScreenLocked());
268 // Fails on Mac, see http://crbug.com/115662
269 #if defined(OS_MACOSX)
270 #define MAYBE_ManagedWindowModeBasics DISABLED_ManagedWindowModeBasics
272 #define MAYBE_ManagedWindowModeBasics ManagedWindowModeBasics
274 TEST_F(ShellTest
, MAYBE_ManagedWindowModeBasics
) {
275 Shell
* shell
= Shell::GetInstance();
276 Shell::TestApi
test_api(shell
);
278 // We start with the usual window containers.
279 ExpectAllContainers();
280 // Launcher is visible.
281 views::Widget
* launcher_widget
= Launcher::ForPrimaryDisplay()->widget();
282 EXPECT_TRUE(launcher_widget
->IsVisible());
283 // Launcher is at bottom-left of screen.
284 EXPECT_EQ(0, launcher_widget
->GetWindowBoundsInScreen().x());
285 EXPECT_EQ(Shell::GetPrimaryRootWindow()->GetHostSize().height(),
286 launcher_widget
->GetWindowBoundsInScreen().bottom());
287 // We have a desktop background but not a bare layer.
288 // TODO (antrim): enable once we find out why it fails component build.
289 // internal::DesktopBackgroundWidgetController* background =
290 // Shell::GetPrimaryRootWindow()->
291 // GetProperty(internal::kWindowDesktopComponent);
292 // EXPECT_TRUE(background);
293 // EXPECT_TRUE(background->widget());
294 // EXPECT_FALSE(background->layer());
296 // Create a normal window. It is not maximized.
297 views::Widget::InitParams
widget_params(
298 views::Widget::InitParams::TYPE_WINDOW
);
299 widget_params
.bounds
.SetRect(11, 22, 300, 400);
300 views::Widget
* widget
= CreateTestWindow(widget_params
);
302 EXPECT_FALSE(widget
->IsMaximized());
308 TEST_F(ShellTest
, FullscreenWindowHidesShelf
) {
309 ExpectAllContainers();
311 // Create a normal window. It is not maximized.
312 views::Widget::InitParams
widget_params(
313 views::Widget::InitParams::TYPE_WINDOW
);
314 widget_params
.bounds
.SetRect(11, 22, 300, 400);
315 views::Widget
* widget
= CreateTestWindow(widget_params
);
317 EXPECT_FALSE(widget
->IsMaximized());
319 // Shelf defaults to visible.
321 internal::ShelfLayoutManager::VISIBLE
,
322 Shell::GetPrimaryRootWindowController()->shelf()->visibility_state());
324 // Fullscreen window hides it.
325 widget
->SetFullscreen(true);
327 internal::ShelfLayoutManager::HIDDEN
,
328 Shell::GetPrimaryRootWindowController()->shelf()->visibility_state());
330 // Restoring the window restores it.
333 internal::ShelfLayoutManager::VISIBLE
,
334 Shell::GetPrimaryRootWindowController()->shelf()->visibility_state());
342 // Builds the list of parents from |window| to the root. The returned vector is
343 // in reverse order (|window| is first).
344 std::vector
<aura::Window
*> BuildPathToRoot(aura::Window
* window
) {
345 std::vector
<aura::Window
*> results
;
347 results
.push_back(window
);
348 window
= window
->parent();
355 // Various assertions around IsAutoHideMenuHideChecked() and
356 // ToggleAutoHideMenu().
357 TEST_F(ShellTest
, ToggleAutoHide
) {
358 scoped_ptr
<aura::Window
> window(new aura::Window(NULL
));
359 window
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_NORMAL
);
360 window
->SetType(aura::client::WINDOW_TYPE_NORMAL
);
361 window
->Init(ui::LAYER_TEXTURED
);
362 window
->SetParent(NULL
);
364 wm::ActivateWindow(window
.get());
366 internal::RootWindowController
* controller
=
367 Shell::GetPrimaryRootWindowController();
368 controller
->SetShelfAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS
);
369 EXPECT_EQ(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS
,
370 controller
->GetShelfAutoHideBehavior());
371 EXPECT_TRUE(controller
->IsShelfAutoHideMenuHideChecked());
372 controller
->SetShelfAutoHideBehavior(
373 controller
->GetToggledShelfAutoHideBehavior());
374 EXPECT_EQ(ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER
,
375 controller
->GetShelfAutoHideBehavior());
377 window
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_MAXIMIZED
);
378 EXPECT_FALSE(controller
->IsShelfAutoHideMenuHideChecked());
379 controller
->SetShelfAutoHideBehavior(
380 controller
->GetToggledShelfAutoHideBehavior());
381 EXPECT_EQ(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS
,
382 controller
->GetShelfAutoHideBehavior());
383 EXPECT_TRUE(controller
->IsShelfAutoHideMenuHideChecked());
384 controller
->SetShelfAutoHideBehavior(
385 controller
->GetToggledShelfAutoHideBehavior());
386 EXPECT_EQ(ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER
,
387 controller
->GetShelfAutoHideBehavior());
390 // This verifies WindowObservers are removed when a window is destroyed after
391 // the Shell is destroyed. This scenario (aura::Windows being deleted after the
392 // Shell) occurs if someone is holding a reference to an unparented Window, as
393 // is the case with a RenderWidgetHostViewAura that isn't on screen. As long as
394 // everything is ok, we won't crash. If there is a bug, window's destructor will
395 // notify some deleted object (say VideoDetector or ActivationController) and
397 class ShellTest2
: public test::AshTestBase
{
400 virtual ~ShellTest2() {}
403 scoped_ptr
<aura::Window
> window_
;
406 DISALLOW_COPY_AND_ASSIGN(ShellTest2
);
409 TEST_F(ShellTest2
, DontCrashWhenWindowDeleted
) {
410 window_
.reset(new aura::Window(NULL
));
411 window_
->Init(ui::LAYER_NOT_DRAWN
);