1// Copyright (c) 2013 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_stacking_client.h"
6
7#include "base/memory/scoped_ptr.h"
8#include "ui/aura/test/aura_test_base.h"
9#include "ui/aura/test/test_windows.h"
10#include "ui/compositor/test/test_layers.h"
11#include "ui/wm/core/window_util.h"
12
13using aura::test::ChildWindowIDsAsString;
14using aura::test::CreateTestWindowWithId;
15using aura::Window;
16
17namespace wm {
18
19class TransientWindowStackingClientTest : public aura::test::AuraTestBase {
20 public:
21  TransientWindowStackingClientTest() {}
22  virtual ~TransientWindowStackingClientTest() {}
23
24  virtual void SetUp() OVERRIDE {
25    AuraTestBase::SetUp();
26    client_.reset(new TransientWindowStackingClient);
27    aura::client::SetWindowStackingClient(client_.get());
28  }
29
30  virtual void TearDown() OVERRIDE {
31    aura::client::SetWindowStackingClient(NULL);
32    AuraTestBase::TearDown();
33  }
34
35 private:
36  scoped_ptr<TransientWindowStackingClient> client_;
37  DISALLOW_COPY_AND_ASSIGN(TransientWindowStackingClientTest);
38};
39
40// Tests that transient children are stacked as a unit when using stack above.
41TEST_F(TransientWindowStackingClientTest, TransientChildrenGroupAbove) {
42  scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
43  scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
44  Window* w11 = CreateTestWindowWithId(11, parent.get());
45  scoped_ptr<Window> w2(CreateTestWindowWithId(2, parent.get()));
46  Window* w21 = CreateTestWindowWithId(21, parent.get());
47  Window* w211 = CreateTestWindowWithId(211, parent.get());
48  Window* w212 = CreateTestWindowWithId(212, parent.get());
49  Window* w213 = CreateTestWindowWithId(213, parent.get());
50  Window* w22 = CreateTestWindowWithId(22, parent.get());
51  ASSERT_EQ(8u, parent->children().size());
52
53  AddTransientChild(w1.get(), w11);  // w11 is now owned by w1.
54  AddTransientChild(w2.get(), w21);  // w21 is now owned by w2.
55  AddTransientChild(w2.get(), w22);  // w22 is now owned by w2.
56  AddTransientChild(w21, w211);  // w211 is now owned by w21.
57  AddTransientChild(w21, w212);  // w212 is now owned by w21.
58  AddTransientChild(w21, w213);  // w213 is now owned by w21.
59  EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
60
61  // Stack w1 at the top (end), this should force w11 to be last (on top of w1).
62  parent->StackChildAtTop(w1.get());
63  EXPECT_EQ(w11, parent->children().back());
64  EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
65
66  // This tests that the order in children_ array rather than in
67  // transient_children_ array is used when reinserting transient children.
68  // If transient_children_ array was used '22' would be following '21'.
69  parent->StackChildAtTop(w2.get());
70  EXPECT_EQ(w22, parent->children().back());
71  EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
72
73  parent->StackChildAbove(w11, w2.get());
74  EXPECT_EQ(w11, parent->children().back());
75  EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
76
77  parent->StackChildAbove(w21, w1.get());
78  EXPECT_EQ(w22, parent->children().back());
79  EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
80
81  parent->StackChildAbove(w21, w22);
82  EXPECT_EQ(w213, parent->children().back());
83  EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent.get()));
84
85  parent->StackChildAbove(w11, w21);
86  EXPECT_EQ(w11, parent->children().back());
87  EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent.get()));
88
89  parent->StackChildAbove(w213, w21);
90  EXPECT_EQ(w11, parent->children().back());
91  EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
92
93  // No change when stacking a transient parent above its transient child.
94  parent->StackChildAbove(w21, w211);
95  EXPECT_EQ(w11, parent->children().back());
96  EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
97
98  // This tests that the order in children_ array rather than in
99  // transient_children_ array is used when reinserting transient children.
100  // If transient_children_ array was used '22' would be following '21'.
101  parent->StackChildAbove(w2.get(), w1.get());
102  EXPECT_EQ(w212, parent->children().back());
103  EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent.get()));
104
105  parent->StackChildAbove(w11, w213);
106  EXPECT_EQ(w11, parent->children().back());
107  EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
108}
109
110// Tests that transient children are stacked as a unit when using stack below.
111TEST_F(TransientWindowStackingClientTest, TransientChildrenGroupBelow) {
112  scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
113  scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
114  Window* w11 = CreateTestWindowWithId(11, parent.get());
115  scoped_ptr<Window> w2(CreateTestWindowWithId(2, parent.get()));
116  Window* w21 = CreateTestWindowWithId(21, parent.get());
117  Window* w211 = CreateTestWindowWithId(211, parent.get());
118  Window* w212 = CreateTestWindowWithId(212, parent.get());
119  Window* w213 = CreateTestWindowWithId(213, parent.get());
120  Window* w22 = CreateTestWindowWithId(22, parent.get());
121  ASSERT_EQ(8u, parent->children().size());
122
123  AddTransientChild(w1.get(), w11);  // w11 is now owned by w1.
124  AddTransientChild(w2.get(), w21);  // w21 is now owned by w2.
125  AddTransientChild(w2.get(), w22);  // w22 is now owned by w2.
126  AddTransientChild(w21, w211);  // w211 is now owned by w21.
127  AddTransientChild(w21, w212);  // w212 is now owned by w21.
128  AddTransientChild(w21, w213);  // w213 is now owned by w21.
129  EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
130
131  // Stack w2 at the bottom, this should force w11 to be last (on top of w1).
132  // This also tests that the order in children_ array rather than in
133  // transient_children_ array is used when reinserting transient children.
134  // If transient_children_ array was used '22' would be following '21'.
135  parent->StackChildAtBottom(w2.get());
136  EXPECT_EQ(w11, parent->children().back());
137  EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
138
139  parent->StackChildAtBottom(w1.get());
140  EXPECT_EQ(w22, parent->children().back());
141  EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
142
143  parent->StackChildBelow(w21, w1.get());
144  EXPECT_EQ(w11, parent->children().back());
145  EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
146
147  parent->StackChildBelow(w11, w2.get());
148  EXPECT_EQ(w22, parent->children().back());
149  EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
150
151  parent->StackChildBelow(w22, w21);
152  EXPECT_EQ(w213, parent->children().back());
153  EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent.get()));
154
155  parent->StackChildBelow(w21, w11);
156  EXPECT_EQ(w11, parent->children().back());
157  EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent.get()));
158
159  parent->StackChildBelow(w213, w211);
160  EXPECT_EQ(w11, parent->children().back());
161  EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
162
163  // No change when stacking a transient parent below its transient child.
164  parent->StackChildBelow(w21, w211);
165  EXPECT_EQ(w11, parent->children().back());
166  EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
167
168  parent->StackChildBelow(w1.get(), w2.get());
169  EXPECT_EQ(w212, parent->children().back());
170  EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent.get()));
171
172  parent->StackChildBelow(w213, w11);
173  EXPECT_EQ(w11, parent->children().back());
174  EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
175}
176
177TEST_F(TransientWindowStackingClientTest,
178       StackWindowsWhoseLayersHaveNoDelegate) {
179  scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
180  window1->layer()->set_name("1");
181  scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window()));
182  window2->layer()->set_name("2");
183  scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window()));
184  window3->layer()->set_name("3");
185
186  // This brings |window1| (and its layer) to the front.
187  root_window()->StackChildAbove(window1.get(), window3.get());
188  EXPECT_EQ("2 3 1", ChildWindowIDsAsString(root_window()));
189  EXPECT_EQ("2 3 1",
190            ui::test::ChildLayerNamesAsString(*root_window()->layer()));
191
192  // Since |window1| does not have a delegate, |window2| should not move in
193  // front of it, nor should its layer.
194  window1->layer()->set_delegate(NULL);
195  root_window()->StackChildAbove(window2.get(), window1.get());
196  EXPECT_EQ("3 2 1", ChildWindowIDsAsString(root_window()));
197  EXPECT_EQ("3 2 1",
198            ui::test::ChildLayerNamesAsString(*root_window()->layer()));
199
200  // It should still be possible to stack |window3| immediately below |window1|.
201  root_window()->StackChildBelow(window3.get(), window1.get());
202  EXPECT_EQ("2 3 1", ChildWindowIDsAsString(root_window()));
203  EXPECT_EQ("2 3 1",
204            ui::test::ChildLayerNamesAsString(*root_window()->layer()));
205
206  // Since neither |window3| nor |window1| have a delegate, |window2| should
207  // not move in front of either.
208  window3->layer()->set_delegate(NULL);
209  root_window()->StackChildBelow(window2.get(), window1.get());
210  EXPECT_EQ("2 3 1", ChildWindowIDsAsString(root_window()));
211  EXPECT_EQ("2 3 1",
212            ui::test::ChildLayerNamesAsString(*root_window()->layer()));
213}
214
215}  // namespace wm
216