1 // Copyright 2014 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.
5 #include "ui/wm/core/transient_window_manager.h"
7 #include "ui/aura/client/visibility_client.h"
8 #include "ui/aura/client/window_tree_client.h"
9 #include "ui/aura/layout_manager.h"
10 #include "ui/aura/test/aura_test_base.h"
11 #include "ui/aura/test/test_windows.h"
12 #include "ui/aura/window.h"
13 #include "ui/wm/core/transient_window_observer.h"
14 #include "ui/wm/core/window_util.h"
15 #include "ui/wm/core/wm_state.h"
19 using aura::test::ChildWindowIDsAsString
;
20 using aura::test::CreateTestWindowWithId
;
24 class TestTransientWindowObserver
: public TransientWindowObserver
{
26 TestTransientWindowObserver() : add_count_(0), remove_count_(0) {
29 virtual ~TestTransientWindowObserver() {
32 int add_count() const { return add_count_
; }
33 int remove_count() const { return remove_count_
; }
35 // TransientWindowObserver overrides:
36 virtual void OnTransientChildAdded(Window
* window
,
37 Window
* transient
) OVERRIDE
{
40 virtual void OnTransientChildRemoved(Window
* window
,
41 Window
* transient
) OVERRIDE
{
49 DISALLOW_COPY_AND_ASSIGN(TestTransientWindowObserver
);
52 class TransientWindowManagerTest
: public aura::test::AuraTestBase
{
54 TransientWindowManagerTest() {}
55 virtual ~TransientWindowManagerTest() {}
57 virtual void SetUp() OVERRIDE
{
58 AuraTestBase::SetUp();
59 wm_state_
.reset(new wm::WMState
);
62 virtual void TearDown() OVERRIDE
{
64 AuraTestBase::TearDown();
68 // Creates a transient window that is transient to |parent|.
69 Window
* CreateTransientChild(int id
, Window
* parent
) {
70 Window
* window
= new Window(NULL
);
72 window
->SetType(ui::wm::WINDOW_TYPE_NORMAL
);
73 window
->Init(aura::WINDOW_LAYER_TEXTURED
);
74 AddTransientChild(parent
, window
);
75 aura::client::ParentWindowWithContext(window
, root_window(), gfx::Rect());
80 scoped_ptr
<wm::WMState
> wm_state_
;
82 DISALLOW_COPY_AND_ASSIGN(TransientWindowManagerTest
);
85 // Various assertions for transient children.
86 TEST_F(TransientWindowManagerTest
, TransientChildren
) {
87 scoped_ptr
<Window
> parent(CreateTestWindowWithId(0, root_window()));
88 scoped_ptr
<Window
> w1(CreateTestWindowWithId(1, parent
.get()));
89 scoped_ptr
<Window
> w3(CreateTestWindowWithId(3, parent
.get()));
90 Window
* w2
= CreateTestWindowWithId(2, parent
.get());
91 // w2 is now owned by w1.
92 AddTransientChild(w1
.get(), w2
);
93 // Stack w1 at the top (end), this should force w2 to be last (on top of w1).
94 parent
->StackChildAtTop(w1
.get());
95 ASSERT_EQ(3u, parent
->children().size());
96 EXPECT_EQ(w2
, parent
->children().back());
98 // Destroy w1, which should also destroy w3 (since it's a transient child).
101 ASSERT_EQ(1u, parent
->children().size());
102 EXPECT_EQ(w3
.get(), parent
->children()[0]);
104 w1
.reset(CreateTestWindowWithId(4, parent
.get()));
105 w2
= CreateTestWindowWithId(5, w3
.get());
106 AddTransientChild(w1
.get(), w2
);
107 parent
->StackChildAtTop(w3
.get());
108 // Stack w1 at the top (end), this shouldn't affect w2 since it has a
110 parent
->StackChildAtTop(w1
.get());
111 ASSERT_EQ(2u, parent
->children().size());
112 EXPECT_EQ(w3
.get(), parent
->children()[0]);
113 EXPECT_EQ(w1
.get(), parent
->children()[1]);
115 // Hiding parent should hide transient children.
116 EXPECT_TRUE(w2
->IsVisible());
118 EXPECT_FALSE(w2
->IsVisible());
121 // Tests that transient children are stacked as a unit when using stack above.
122 TEST_F(TransientWindowManagerTest
, TransientChildrenGroupAbove
) {
123 scoped_ptr
<Window
> parent(CreateTestWindowWithId(0, root_window()));
124 scoped_ptr
<Window
> w1(CreateTestWindowWithId(1, parent
.get()));
125 Window
* w11
= CreateTestWindowWithId(11, parent
.get());
126 scoped_ptr
<Window
> w2(CreateTestWindowWithId(2, parent
.get()));
127 Window
* w21
= CreateTestWindowWithId(21, parent
.get());
128 Window
* w211
= CreateTestWindowWithId(211, parent
.get());
129 Window
* w212
= CreateTestWindowWithId(212, parent
.get());
130 Window
* w213
= CreateTestWindowWithId(213, parent
.get());
131 Window
* w22
= CreateTestWindowWithId(22, parent
.get());
132 ASSERT_EQ(8u, parent
->children().size());
134 // w11 is now owned by w1.
135 AddTransientChild(w1
.get(), w11
);
136 // w21 is now owned by w2.
137 AddTransientChild(w2
.get(), w21
);
138 // w22 is now owned by w2.
139 AddTransientChild(w2
.get(), w22
);
140 // w211 is now owned by w21.
141 AddTransientChild(w21
, w211
);
142 // w212 is now owned by w21.
143 AddTransientChild(w21
, w212
);
144 // w213 is now owned by w21.
145 AddTransientChild(w21
, w213
);
146 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent
.get()));
148 // Stack w1 at the top (end), this should force w11 to be last (on top of w1).
149 parent
->StackChildAtTop(w1
.get());
150 EXPECT_EQ(w11
, parent
->children().back());
151 EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent
.get()));
153 // This tests that the order in children_ array rather than in
154 // transient_children_ array is used when reinserting transient children.
155 // If transient_children_ array was used '22' would be following '21'.
156 parent
->StackChildAtTop(w2
.get());
157 EXPECT_EQ(w22
, parent
->children().back());
158 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent
.get()));
160 parent
->StackChildAbove(w11
, w2
.get());
161 EXPECT_EQ(w11
, parent
->children().back());
162 EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent
.get()));
164 parent
->StackChildAbove(w21
, w1
.get());
165 EXPECT_EQ(w22
, parent
->children().back());
166 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent
.get()));
168 parent
->StackChildAbove(w21
, w22
);
169 EXPECT_EQ(w213
, parent
->children().back());
170 EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent
.get()));
172 parent
->StackChildAbove(w11
, w21
);
173 EXPECT_EQ(w11
, parent
->children().back());
174 EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent
.get()));
176 parent
->StackChildAbove(w213
, w21
);
177 EXPECT_EQ(w11
, parent
->children().back());
178 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent
.get()));
180 // No change when stacking a transient parent above its transient child.
181 parent
->StackChildAbove(w21
, w211
);
182 EXPECT_EQ(w11
, parent
->children().back());
183 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent
.get()));
185 // This tests that the order in children_ array rather than in
186 // transient_children_ array is used when reinserting transient children.
187 // If transient_children_ array was used '22' would be following '21'.
188 parent
->StackChildAbove(w2
.get(), w1
.get());
189 EXPECT_EQ(w212
, parent
->children().back());
190 EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent
.get()));
192 parent
->StackChildAbove(w11
, w213
);
193 EXPECT_EQ(w11
, parent
->children().back());
194 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent
.get()));
197 // Tests that transient children are stacked as a unit when using stack below.
198 TEST_F(TransientWindowManagerTest
, TransientChildrenGroupBelow
) {
199 scoped_ptr
<Window
> parent(CreateTestWindowWithId(0, root_window()));
200 scoped_ptr
<Window
> w1(CreateTestWindowWithId(1, parent
.get()));
201 Window
* w11
= CreateTestWindowWithId(11, parent
.get());
202 scoped_ptr
<Window
> w2(CreateTestWindowWithId(2, parent
.get()));
203 Window
* w21
= CreateTestWindowWithId(21, parent
.get());
204 Window
* w211
= CreateTestWindowWithId(211, parent
.get());
205 Window
* w212
= CreateTestWindowWithId(212, parent
.get());
206 Window
* w213
= CreateTestWindowWithId(213, parent
.get());
207 Window
* w22
= CreateTestWindowWithId(22, parent
.get());
208 ASSERT_EQ(8u, parent
->children().size());
210 // w11 is now owned by w1.
211 AddTransientChild(w1
.get(), w11
);
212 // w21 is now owned by w2.
213 AddTransientChild(w2
.get(), w21
);
214 // w22 is now owned by w2.
215 AddTransientChild(w2
.get(), w22
);
216 // w211 is now owned by w21.
217 AddTransientChild(w21
, w211
);
218 // w212 is now owned by w21.
219 AddTransientChild(w21
, w212
);
220 // w213 is now owned by w21.
221 AddTransientChild(w21
, w213
);
222 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent
.get()));
224 // Stack w2 at the bottom, this should force w11 to be last (on top of w1).
225 // This also tests that the order in children_ array rather than in
226 // transient_children_ array is used when reinserting transient children.
227 // If transient_children_ array was used '22' would be following '21'.
228 parent
->StackChildAtBottom(w2
.get());
229 EXPECT_EQ(w11
, parent
->children().back());
230 EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent
.get()));
232 parent
->StackChildAtBottom(w1
.get());
233 EXPECT_EQ(w22
, parent
->children().back());
234 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent
.get()));
236 parent
->StackChildBelow(w21
, w1
.get());
237 EXPECT_EQ(w11
, parent
->children().back());
238 EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent
.get()));
240 parent
->StackChildBelow(w11
, w2
.get());
241 EXPECT_EQ(w22
, parent
->children().back());
242 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent
.get()));
244 parent
->StackChildBelow(w22
, w21
);
245 EXPECT_EQ(w213
, parent
->children().back());
246 EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent
.get()));
248 parent
->StackChildBelow(w21
, w11
);
249 EXPECT_EQ(w11
, parent
->children().back());
250 EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent
.get()));
252 parent
->StackChildBelow(w213
, w211
);
253 EXPECT_EQ(w11
, parent
->children().back());
254 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent
.get()));
256 // No change when stacking a transient parent below its transient child.
257 parent
->StackChildBelow(w21
, w211
);
258 EXPECT_EQ(w11
, parent
->children().back());
259 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent
.get()));
261 parent
->StackChildBelow(w1
.get(), w2
.get());
262 EXPECT_EQ(w212
, parent
->children().back());
263 EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent
.get()));
265 parent
->StackChildBelow(w213
, w11
);
266 EXPECT_EQ(w11
, parent
->children().back());
267 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent
.get()));
270 // Tests that transient windows are stacked properly when created.
271 TEST_F(TransientWindowManagerTest
, StackUponCreation
) {
272 scoped_ptr
<Window
> window0(CreateTestWindowWithId(0, root_window()));
273 scoped_ptr
<Window
> window1(CreateTestWindowWithId(1, root_window()));
275 scoped_ptr
<Window
> window2(CreateTransientChild(2, window0
.get()));
276 EXPECT_EQ("0 2 1", ChildWindowIDsAsString(root_window()));
279 // Tests that windows are restacked properly after a call to AddTransientChild()
280 // or RemoveTransientChild().
281 TEST_F(TransientWindowManagerTest
, RestackUponAddOrRemoveTransientChild
) {
282 scoped_ptr
<Window
> windows
[4];
283 for (int i
= 0; i
< 4; i
++)
284 windows
[i
].reset(CreateTestWindowWithId(i
, root_window()));
285 EXPECT_EQ("0 1 2 3", ChildWindowIDsAsString(root_window()));
287 AddTransientChild(windows
[0].get(), windows
[2].get());
288 EXPECT_EQ("0 2 1 3", ChildWindowIDsAsString(root_window()));
290 AddTransientChild(windows
[0].get(), windows
[3].get());
291 EXPECT_EQ("0 2 3 1", ChildWindowIDsAsString(root_window()));
293 RemoveTransientChild(windows
[0].get(), windows
[2].get());
294 EXPECT_EQ("0 3 2 1", ChildWindowIDsAsString(root_window()));
296 RemoveTransientChild(windows
[0].get(), windows
[3].get());
297 EXPECT_EQ("0 3 2 1", ChildWindowIDsAsString(root_window()));
302 // Used by NotifyDelegateAfterDeletingTransients. Adds a string to a vector when
303 // OnWindowDestroyed() is invoked so that destruction order can be verified.
304 class DestroyedTrackingDelegate
: public aura::test::TestWindowDelegate
{
306 explicit DestroyedTrackingDelegate(const std::string
& name
,
307 std::vector
<std::string
>* results
)
311 virtual void OnWindowDestroyed(aura::Window
* window
) OVERRIDE
{
312 results_
->push_back(name_
);
316 const std::string name_
;
317 std::vector
<std::string
>* results_
;
319 DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingDelegate
);
324 // Verifies the delegate is notified of destruction after transients are
326 TEST_F(TransientWindowManagerTest
, NotifyDelegateAfterDeletingTransients
) {
327 std::vector
<std::string
> destruction_order
;
329 DestroyedTrackingDelegate
parent_delegate("parent", &destruction_order
);
330 scoped_ptr
<Window
> parent(new Window(&parent_delegate
));
331 parent
->Init(aura::WINDOW_LAYER_NOT_DRAWN
);
333 DestroyedTrackingDelegate
transient_delegate("transient", &destruction_order
);
334 Window
* transient
= new Window(&transient_delegate
); // Owned by |parent|.
335 transient
->Init(aura::WINDOW_LAYER_NOT_DRAWN
);
336 AddTransientChild(parent
.get(), transient
);
339 ASSERT_EQ(2u, destruction_order
.size());
340 EXPECT_EQ("transient", destruction_order
[0]);
341 EXPECT_EQ("parent", destruction_order
[1]);
344 TEST_F(TransientWindowManagerTest
, StackTransientsWhoseLayersHaveNoDelegate
) {
345 // Create a window with several transients, then a couple windows on top.
346 scoped_ptr
<Window
> window1(CreateTestWindowWithId(1, root_window()));
347 scoped_ptr
<Window
> window11(CreateTransientChild(11, window1
.get()));
348 scoped_ptr
<Window
> window12(CreateTransientChild(12, window1
.get()));
349 scoped_ptr
<Window
> window13(CreateTransientChild(13, window1
.get()));
350 scoped_ptr
<Window
> window2(CreateTestWindowWithId(2, root_window()));
351 scoped_ptr
<Window
> window3(CreateTestWindowWithId(3, root_window()));
353 EXPECT_EQ("1 11 12 13 2 3", ChildWindowIDsAsString(root_window()));
355 // Remove the delegates of a couple of transients, as if they are closing
356 // and animating out.
357 window11
->layer()->set_delegate(NULL
);
358 window13
->layer()->set_delegate(NULL
);
360 // Move window1 to the front. All transients should move with it, and their
361 // order should be preserved.
362 root_window()->StackChildAtTop(window1
.get());
364 EXPECT_EQ("2 3 1 11 12 13", ChildWindowIDsAsString(root_window()));
367 TEST_F(TransientWindowManagerTest
,
368 StackTransientsLayersRelativeToOtherTransients
) {
369 // Create a window with several transients, then a couple windows on top.
370 scoped_ptr
<Window
> window1(CreateTestWindowWithId(1, root_window()));
371 scoped_ptr
<Window
> window11(CreateTransientChild(11, window1
.get()));
372 scoped_ptr
<Window
> window12(CreateTransientChild(12, window1
.get()));
373 scoped_ptr
<Window
> window13(CreateTransientChild(13, window1
.get()));
375 EXPECT_EQ("1 11 12 13", ChildWindowIDsAsString(root_window()));
377 // Stack 11 above 12.
378 root_window()->StackChildAbove(window11
.get(), window12
.get());
379 EXPECT_EQ("1 12 11 13", ChildWindowIDsAsString(root_window()));
381 // Stack 13 below 12.
382 root_window()->StackChildBelow(window13
.get(), window12
.get());
383 EXPECT_EQ("1 13 12 11", ChildWindowIDsAsString(root_window()));
386 root_window()->StackChildAbove(window11
.get(), window1
.get());
387 EXPECT_EQ("1 11 13 12", ChildWindowIDsAsString(root_window()));
389 // Stack 12 below 13.
390 root_window()->StackChildBelow(window12
.get(), window13
.get());
391 EXPECT_EQ("1 11 12 13", ChildWindowIDsAsString(root_window()));
394 TEST_F(TransientWindowManagerTest
,
395 StackTransientsLayersRelativeToOtherTransientsNoLayerDelegate
) {
396 // Create a window with several transients, then a couple windows on top.
397 scoped_ptr
<Window
> window1(CreateTestWindowWithId(1, root_window()));
398 scoped_ptr
<Window
> window11(CreateTransientChild(11, window1
.get()));
399 scoped_ptr
<Window
> window12(CreateTransientChild(12, window1
.get()));
400 scoped_ptr
<Window
> window13(CreateTransientChild(13, window1
.get()));
401 scoped_ptr
<Window
> window2(CreateTestWindowWithId(2, root_window()));
402 scoped_ptr
<Window
> window3(CreateTestWindowWithId(3, root_window()));
404 EXPECT_EQ("1 11 12 13 2 3", ChildWindowIDsAsString(root_window()));
406 window1
->layer()->set_delegate(NULL
);
409 root_window()->StackChildAtTop(window1
.get());
410 EXPECT_EQ("2 3 1 11 12 13", ChildWindowIDsAsString(root_window()));
413 class StackingMadrigalLayoutManager
: public aura::LayoutManager
{
415 explicit StackingMadrigalLayoutManager(Window
* root_window
)
416 : root_window_(root_window
) {
417 root_window_
->SetLayoutManager(this);
419 virtual ~StackingMadrigalLayoutManager() {
423 // Overridden from LayoutManager:
424 virtual void OnWindowResized() OVERRIDE
{}
425 virtual void OnWindowAddedToLayout(Window
* child
) OVERRIDE
{}
426 virtual void OnWillRemoveWindowFromLayout(Window
* child
) OVERRIDE
{}
427 virtual void OnWindowRemovedFromLayout(Window
* child
) OVERRIDE
{}
428 virtual void OnChildWindowVisibilityChanged(Window
* child
,
429 bool visible
) OVERRIDE
{
430 Window::Windows::const_iterator it
= root_window_
->children().begin();
431 Window
* last_window
= NULL
;
432 for (; it
!= root_window_
->children().end(); ++it
) {
433 if (*it
== child
&& last_window
) {
435 root_window_
->StackChildAbove(last_window
, *it
);
437 root_window_
->StackChildAbove(*it
, last_window
);
443 virtual void SetChildBounds(Window
* child
,
444 const gfx::Rect
& requested_bounds
) OVERRIDE
{
445 SetChildBoundsDirect(child
, requested_bounds
);
448 Window
* root_window_
;
450 DISALLOW_COPY_AND_ASSIGN(StackingMadrigalLayoutManager
);
453 class StackingMadrigalVisibilityClient
: public aura::client::VisibilityClient
{
455 explicit StackingMadrigalVisibilityClient(Window
* root_window
)
456 : ignored_window_(NULL
) {
457 aura::client::SetVisibilityClient(root_window
, this);
459 virtual ~StackingMadrigalVisibilityClient() {
462 void set_ignored_window(Window
* ignored_window
) {
463 ignored_window_
= ignored_window
;
467 // Overridden from client::VisibilityClient:
468 virtual void UpdateLayerVisibility(Window
* window
, bool visible
) OVERRIDE
{
470 if (window
== ignored_window_
)
471 window
->layer()->set_delegate(NULL
);
473 window
->layer()->SetVisible(visible
);
475 window
->layer()->SetVisible(visible
);
479 Window
* ignored_window_
;
481 DISALLOW_COPY_AND_ASSIGN(StackingMadrigalVisibilityClient
);
484 // This test attempts to reconstruct a circumstance that can happen when the
485 // aura client attempts to manipulate the visibility and delegate of a layer
486 // independent of window visibility.
487 // A use case is where the client attempts to keep a window visible onscreen
488 // even after code has called Hide() on the window. The use case for this would
489 // be that window hides are animated (e.g. the window fades out). To prevent
490 // spurious updating the client code may also clear window's layer's delegate,
491 // so that the window cannot attempt to paint or update it further. The window
492 // uses the presence of a NULL layer delegate as a signal in stacking to note
493 // that the window is being manipulated by such a use case and its stacking
494 // should not be adjusted.
495 // One issue that can arise when a window opens two transient children, and the
496 // first is hidden. Subsequent attempts to activate the transient parent can
497 // result in the transient parent being stacked above the second transient
498 // child. A fix is made to Window::StackAbove to prevent this, and this test
499 // verifies this fix.
500 TEST_F(TransientWindowManagerTest
, StackingMadrigal
) {
501 new StackingMadrigalLayoutManager(root_window());
502 StackingMadrigalVisibilityClient
visibility_client(root_window());
504 scoped_ptr
<Window
> window1(CreateTestWindowWithId(1, root_window()));
505 scoped_ptr
<Window
> window11(CreateTransientChild(11, window1
.get()));
507 visibility_client
.set_ignored_window(window11
.get());
512 // As a transient, window11 should still be stacked above window1, even when
514 EXPECT_TRUE(aura::test::WindowIsAbove(window11
.get(), window1
.get()));
515 EXPECT_TRUE(aura::test::LayerIsAbove(window11
.get(), window1
.get()));
517 // A new transient should still be above window1. It will appear behind
518 // window11 because we don't stack windows on top of targets with NULL
520 scoped_ptr
<Window
> window12(CreateTransientChild(12, window1
.get()));
523 EXPECT_TRUE(aura::test::WindowIsAbove(window12
.get(), window1
.get()));
524 EXPECT_TRUE(aura::test::LayerIsAbove(window12
.get(), window1
.get()));
526 // In earlier versions of the StackChildAbove() method, attempting to stack
527 // window1 above window12 at this point would actually restack the layers
528 // resulting in window12's layer being below window1's layer (though the
529 // windows themselves would still be correctly stacked, so events would pass
531 root_window()->StackChildAbove(window1
.get(), window12
.get());
533 // Both window12 and its layer should be stacked above window1.
534 EXPECT_TRUE(aura::test::WindowIsAbove(window12
.get(), window1
.get()));
535 EXPECT_TRUE(aura::test::LayerIsAbove(window12
.get(), window1
.get()));
538 // Test for an issue where attempting to stack a primary window on top of a
539 // transient with a NULL layer delegate causes that primary window to be moved,
540 // but the layer order not changed to match. http://crbug.com/112562
541 TEST_F(TransientWindowManagerTest
, StackOverClosingTransient
) {
542 scoped_ptr
<Window
> window1(CreateTestWindowWithId(1, root_window()));
543 scoped_ptr
<Window
> transient1(CreateTransientChild(11, window1
.get()));
544 scoped_ptr
<Window
> window2(CreateTestWindowWithId(2, root_window()));
545 scoped_ptr
<Window
> transient2(CreateTransientChild(21, window2
.get()));
547 // Both windows and layers are stacked in creation order.
548 Window
* root
= root_window();
549 ASSERT_EQ(4u, root
->children().size());
550 EXPECT_EQ(root
->children()[0], window1
.get());
551 EXPECT_EQ(root
->children()[1], transient1
.get());
552 EXPECT_EQ(root
->children()[2], window2
.get());
553 EXPECT_EQ(root
->children()[3], transient2
.get());
554 ASSERT_EQ(4u, root
->layer()->children().size());
555 EXPECT_EQ(root
->layer()->children()[0], window1
->layer());
556 EXPECT_EQ(root
->layer()->children()[1], transient1
->layer());
557 EXPECT_EQ(root
->layer()->children()[2], window2
->layer());
558 EXPECT_EQ(root
->layer()->children()[3], transient2
->layer());
559 EXPECT_EQ("1 11 2 21", ChildWindowIDsAsString(root_window()));
561 // This brings window1 and its transient to the front.
562 root
->StackChildAtTop(window1
.get());
563 EXPECT_EQ("2 21 1 11", ChildWindowIDsAsString(root_window()));
565 EXPECT_EQ(root
->children()[0], window2
.get());
566 EXPECT_EQ(root
->children()[1], transient2
.get());
567 EXPECT_EQ(root
->children()[2], window1
.get());
568 EXPECT_EQ(root
->children()[3], transient1
.get());
569 EXPECT_EQ(root
->layer()->children()[0], window2
->layer());
570 EXPECT_EQ(root
->layer()->children()[1], transient2
->layer());
571 EXPECT_EQ(root
->layer()->children()[2], window1
->layer());
572 EXPECT_EQ(root
->layer()->children()[3], transient1
->layer());
574 // Pretend we're closing the top-most transient, then bring window2 to the
575 // front. This mimics activating a browser window while the status bubble
576 // is fading out. The transient should stay topmost.
577 transient1
->layer()->set_delegate(NULL
);
578 root
->StackChildAtTop(window2
.get());
580 EXPECT_EQ(root
->children()[0], window1
.get());
581 EXPECT_EQ(root
->children()[1], window2
.get());
582 EXPECT_EQ(root
->children()[2], transient2
.get());
583 EXPECT_EQ(root
->children()[3], transient1
.get());
584 EXPECT_EQ(root
->layer()->children()[0], window1
->layer());
585 EXPECT_EQ(root
->layer()->children()[1], window2
->layer());
586 EXPECT_EQ(root
->layer()->children()[2], transient2
->layer());
587 EXPECT_EQ(root
->layer()->children()[3], transient1
->layer());
589 // Close the transient. Remaining windows are stable.
592 ASSERT_EQ(3u, root
->children().size());
593 EXPECT_EQ(root
->children()[0], window1
.get());
594 EXPECT_EQ(root
->children()[1], window2
.get());
595 EXPECT_EQ(root
->children()[2], transient2
.get());
596 ASSERT_EQ(3u, root
->layer()->children().size());
597 EXPECT_EQ(root
->layer()->children()[0], window1
->layer());
598 EXPECT_EQ(root
->layer()->children()[1], window2
->layer());
599 EXPECT_EQ(root
->layer()->children()[2], transient2
->layer());
601 // Open another window on top.
602 scoped_ptr
<Window
> window3(CreateTestWindowWithId(3, root_window()));
604 ASSERT_EQ(4u, root
->children().size());
605 EXPECT_EQ(root
->children()[0], window1
.get());
606 EXPECT_EQ(root
->children()[1], window2
.get());
607 EXPECT_EQ(root
->children()[2], transient2
.get());
608 EXPECT_EQ(root
->children()[3], window3
.get());
609 ASSERT_EQ(4u, root
->layer()->children().size());
610 EXPECT_EQ(root
->layer()->children()[0], window1
->layer());
611 EXPECT_EQ(root
->layer()->children()[1], window2
->layer());
612 EXPECT_EQ(root
->layer()->children()[2], transient2
->layer());
613 EXPECT_EQ(root
->layer()->children()[3], window3
->layer());
615 // Pretend we're closing the topmost non-transient window, then bring
616 // window2 to the top. It should not move.
617 window3
->layer()->set_delegate(NULL
);
618 root
->StackChildAtTop(window2
.get());
620 ASSERT_EQ(4u, root
->children().size());
621 EXPECT_EQ(root
->children()[0], window1
.get());
622 EXPECT_EQ(root
->children()[1], window2
.get());
623 EXPECT_EQ(root
->children()[2], transient2
.get());
624 EXPECT_EQ(root
->children()[3], window3
.get());
625 ASSERT_EQ(4u, root
->layer()->children().size());
626 EXPECT_EQ(root
->layer()->children()[0], window1
->layer());
627 EXPECT_EQ(root
->layer()->children()[1], window2
->layer());
628 EXPECT_EQ(root
->layer()->children()[2], transient2
->layer());
629 EXPECT_EQ(root
->layer()->children()[3], window3
->layer());
631 // Bring window1 to the top. It should move ahead of window2, but not
632 // ahead of window3 (with NULL delegate).
633 root
->StackChildAtTop(window1
.get());
635 ASSERT_EQ(4u, root
->children().size());
636 EXPECT_EQ(root
->children()[0], window2
.get());
637 EXPECT_EQ(root
->children()[1], transient2
.get());
638 EXPECT_EQ(root
->children()[2], window1
.get());
639 EXPECT_EQ(root
->children()[3], window3
.get());
640 ASSERT_EQ(4u, root
->layer()->children().size());
641 EXPECT_EQ(root
->layer()->children()[0], window2
->layer());
642 EXPECT_EQ(root
->layer()->children()[1], transient2
->layer());
643 EXPECT_EQ(root
->layer()->children()[2], window1
->layer());
644 EXPECT_EQ(root
->layer()->children()[3], window3
->layer());
647 // Verifies TransientWindowObserver is notified appropriately.
648 TEST_F(TransientWindowManagerTest
, TransientWindowObserverNotified
) {
649 scoped_ptr
<Window
> parent(CreateTestWindowWithId(0, root_window()));
650 scoped_ptr
<Window
> w1(CreateTestWindowWithId(1, parent
.get()));
652 TestTransientWindowObserver test_observer
;
653 TransientWindowManager::Get(parent
.get())->AddObserver(&test_observer
);
655 AddTransientChild(parent
.get(), w1
.get());
656 EXPECT_EQ(1, test_observer
.add_count());
657 EXPECT_EQ(0, test_observer
.remove_count());
659 RemoveTransientChild(parent
.get(), w1
.get());
660 EXPECT_EQ(1, test_observer
.add_count());
661 EXPECT_EQ(1, test_observer
.remove_count());
663 TransientWindowManager::Get(parent
.get())->RemoveObserver(&test_observer
);