05b8e88e4debf5781a3f31bb8d93b579a4a8edff
[platform/framework/web/crosswalk.git] / src / ui / wm / core / transient_window_manager_unittest.cc
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.
4
5 #include "ui/wm/core/transient_window_manager.h"
6
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"
16
17 using aura::Window;
18
19 using aura::test::ChildWindowIDsAsString;
20 using aura::test::CreateTestWindowWithId;
21
22 namespace wm {
23
24 class TestTransientWindowObserver : public TransientWindowObserver {
25  public:
26   TestTransientWindowObserver() : add_count_(0), remove_count_(0) {
27   }
28
29   virtual ~TestTransientWindowObserver() {
30   }
31
32   int add_count() const { return add_count_; }
33   int remove_count() const { return remove_count_; }
34
35   // TransientWindowObserver overrides:
36   virtual void OnTransientChildAdded(Window* window,
37                                      Window* transient) OVERRIDE {
38     add_count_++;
39   }
40   virtual void OnTransientChildRemoved(Window* window,
41                                        Window* transient) OVERRIDE {
42     remove_count_++;
43   }
44
45  private:
46   int add_count_;
47   int remove_count_;
48
49   DISALLOW_COPY_AND_ASSIGN(TestTransientWindowObserver);
50 };
51
52 class TransientWindowManagerTest : public aura::test::AuraTestBase {
53  public:
54   TransientWindowManagerTest() {}
55   virtual ~TransientWindowManagerTest() {}
56
57   virtual void SetUp() OVERRIDE {
58     AuraTestBase::SetUp();
59     wm_state_.reset(new wm::WMState);
60   }
61
62   virtual void TearDown() OVERRIDE {
63     wm_state_.reset();
64     AuraTestBase::TearDown();
65   }
66
67  protected:
68   // Creates a transient window that is transient to |parent|.
69   Window* CreateTransientChild(int id, Window* parent) {
70     Window* window = new Window(NULL);
71     window->set_id(id);
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());
76     return window;
77   }
78
79  private:
80   scoped_ptr<wm::WMState> wm_state_;
81
82   DISALLOW_COPY_AND_ASSIGN(TransientWindowManagerTest);
83 };
84
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());
97
98   // Destroy w1, which should also destroy w3 (since it's a transient child).
99   w1.reset();
100   w2 = NULL;
101   ASSERT_EQ(1u, parent->children().size());
102   EXPECT_EQ(w3.get(), parent->children()[0]);
103
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
109   // different parent.
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]);
114
115   // Hiding parent should hide transient children.
116   EXPECT_TRUE(w2->IsVisible());
117   w1->Hide();
118   EXPECT_FALSE(w2->IsVisible());
119 }
120
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());
133
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()));
147
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()));
152
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()));
159
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()));
163
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()));
167
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()));
171
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()));
175
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()));
179
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()));
184
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()));
191
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()));
195 }
196
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());
209
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()));
223
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()));
231
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()));
235
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()));
239
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()));
243
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()));
247
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()));
251
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()));
255
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()));
260
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()));
264
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()));
268 }
269
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()));
274
275   scoped_ptr<Window> window2(CreateTransientChild(2, window0.get()));
276   EXPECT_EQ("0 2 1", ChildWindowIDsAsString(root_window()));
277 }
278
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()));
286
287   AddTransientChild(windows[0].get(), windows[2].get());
288   EXPECT_EQ("0 2 1 3", ChildWindowIDsAsString(root_window()));
289
290   AddTransientChild(windows[0].get(), windows[3].get());
291   EXPECT_EQ("0 2 3 1", ChildWindowIDsAsString(root_window()));
292
293   RemoveTransientChild(windows[0].get(), windows[2].get());
294   EXPECT_EQ("0 3 2 1", ChildWindowIDsAsString(root_window()));
295
296   RemoveTransientChild(windows[0].get(), windows[3].get());
297   EXPECT_EQ("0 3 2 1", ChildWindowIDsAsString(root_window()));
298 }
299
300 namespace {
301
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 {
305  public:
306   explicit DestroyedTrackingDelegate(const std::string& name,
307                                      std::vector<std::string>* results)
308       : name_(name),
309         results_(results) {}
310
311   virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {
312     results_->push_back(name_);
313   }
314
315  private:
316   const std::string name_;
317   std::vector<std::string>* results_;
318
319   DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingDelegate);
320 };
321
322 }  // namespace
323
324 // Verifies the delegate is notified of destruction after transients are
325 // destroyed.
326 TEST_F(TransientWindowManagerTest, NotifyDelegateAfterDeletingTransients) {
327   std::vector<std::string> destruction_order;
328
329   DestroyedTrackingDelegate parent_delegate("parent", &destruction_order);
330   scoped_ptr<Window> parent(new Window(&parent_delegate));
331   parent->Init(aura::WINDOW_LAYER_NOT_DRAWN);
332
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);
337   parent.reset();
338
339   ASSERT_EQ(2u, destruction_order.size());
340   EXPECT_EQ("transient", destruction_order[0]);
341   EXPECT_EQ("parent", destruction_order[1]);
342 }
343
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()));
352
353   EXPECT_EQ("1 11 12 13 2 3", ChildWindowIDsAsString(root_window()));
354
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);
359
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());
363
364   EXPECT_EQ("2 3 1 11 12 13", ChildWindowIDsAsString(root_window()));
365 }
366
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()));
374
375   EXPECT_EQ("1 11 12 13", ChildWindowIDsAsString(root_window()));
376
377   // Stack 11 above 12.
378   root_window()->StackChildAbove(window11.get(), window12.get());
379   EXPECT_EQ("1 12 11 13", ChildWindowIDsAsString(root_window()));
380
381   // Stack 13 below 12.
382   root_window()->StackChildBelow(window13.get(), window12.get());
383   EXPECT_EQ("1 13 12 11", ChildWindowIDsAsString(root_window()));
384
385   // Stack 11 above 1.
386   root_window()->StackChildAbove(window11.get(), window1.get());
387   EXPECT_EQ("1 11 13 12", ChildWindowIDsAsString(root_window()));
388
389   // Stack 12 below 13.
390   root_window()->StackChildBelow(window12.get(), window13.get());
391   EXPECT_EQ("1 11 12 13", ChildWindowIDsAsString(root_window()));
392 }
393
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()));
403
404   EXPECT_EQ("1 11 12 13 2 3", ChildWindowIDsAsString(root_window()));
405
406   window1->layer()->set_delegate(NULL);
407
408   // Stack 1 at top.
409   root_window()->StackChildAtTop(window1.get());
410   EXPECT_EQ("2 3 1 11 12 13", ChildWindowIDsAsString(root_window()));
411 }
412
413 class StackingMadrigalLayoutManager : public aura::LayoutManager {
414  public:
415   explicit StackingMadrigalLayoutManager(Window* root_window)
416       : root_window_(root_window) {
417     root_window_->SetLayoutManager(this);
418   }
419   virtual ~StackingMadrigalLayoutManager() {
420   }
421
422  private:
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) {
434         if (!visible)
435           root_window_->StackChildAbove(last_window, *it);
436         else
437           root_window_->StackChildAbove(*it, last_window);
438         break;
439       }
440       last_window = *it;
441     }
442   }
443   virtual void SetChildBounds(Window* child,
444                               const gfx::Rect& requested_bounds) OVERRIDE {
445     SetChildBoundsDirect(child, requested_bounds);
446   }
447
448   Window* root_window_;
449
450   DISALLOW_COPY_AND_ASSIGN(StackingMadrigalLayoutManager);
451 };
452
453 class StackingMadrigalVisibilityClient : public aura::client::VisibilityClient {
454  public:
455   explicit StackingMadrigalVisibilityClient(Window* root_window)
456       : ignored_window_(NULL) {
457     aura::client::SetVisibilityClient(root_window, this);
458   }
459   virtual ~StackingMadrigalVisibilityClient() {
460   }
461
462   void set_ignored_window(Window* ignored_window) {
463     ignored_window_ = ignored_window;
464   }
465
466  private:
467   // Overridden from client::VisibilityClient:
468   virtual void UpdateLayerVisibility(Window* window, bool visible) OVERRIDE {
469     if (!visible) {
470       if (window == ignored_window_)
471         window->layer()->set_delegate(NULL);
472       else
473         window->layer()->SetVisible(visible);
474     } else {
475       window->layer()->SetVisible(visible);
476     }
477   }
478
479   Window* ignored_window_;
480
481   DISALLOW_COPY_AND_ASSIGN(StackingMadrigalVisibilityClient);
482 };
483
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());
503
504   scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
505   scoped_ptr<Window> window11(CreateTransientChild(11, window1.get()));
506
507   visibility_client.set_ignored_window(window11.get());
508
509   window11->Show();
510   window11->Hide();
511
512   // As a transient, window11 should still be stacked above window1, even when
513   // hidden.
514   EXPECT_TRUE(aura::test::WindowIsAbove(window11.get(), window1.get()));
515   EXPECT_TRUE(aura::test::LayerIsAbove(window11.get(), window1.get()));
516
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
519   // delegates.
520   scoped_ptr<Window> window12(CreateTransientChild(12, window1.get()));
521   window12->Show();
522
523   EXPECT_TRUE(aura::test::WindowIsAbove(window12.get(), window1.get()));
524   EXPECT_TRUE(aura::test::LayerIsAbove(window12.get(), window1.get()));
525
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
530   // through.)
531   root_window()->StackChildAbove(window1.get(), window12.get());
532
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()));
536 }
537
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()));
546
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()));
560
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()));
564
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());
573
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());
579
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());
588
589   // Close the transient.  Remaining windows are stable.
590   transient1.reset();
591
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());
600
601   // Open another window on top.
602   scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window()));
603
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());
614
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());
619
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());
630
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());
634
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());
645 }
646
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()));
651
652   TestTransientWindowObserver test_observer;
653   TransientWindowManager::Get(parent.get())->AddObserver(&test_observer);
654
655   AddTransientChild(parent.get(), w1.get());
656   EXPECT_EQ(1, test_observer.add_count());
657   EXPECT_EQ(0, test_observer.remove_count());
658
659   RemoveTransientChild(parent.get(), w1.get());
660   EXPECT_EQ(1, test_observer.add_count());
661   EXPECT_EQ(1, test_observer.remove_count());
662
663   TransientWindowManager::Get(parent.get())->RemoveObserver(&test_observer);
664 }
665
666 }  // namespace wm