Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ui / wm / core / transient_window_manager_unittest.cc
blobbbc3820c479dd6a17a0df55f77b3df3702880d03
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/window_tree_client.h"
8 #include "ui/aura/test/aura_test_base.h"
9 #include "ui/aura/test/test_windows.h"
10 #include "ui/aura/window.h"
11 #include "ui/wm/core/transient_window_observer.h"
12 #include "ui/wm/core/window_util.h"
13 #include "ui/wm/core/wm_state.h"
15 using aura::Window;
17 using aura::test::ChildWindowIDsAsString;
18 using aura::test::CreateTestWindowWithId;
20 namespace wm {
22 class TestTransientWindowObserver : public TransientWindowObserver {
23 public:
24 TestTransientWindowObserver() : add_count_(0), remove_count_(0) {
27 ~TestTransientWindowObserver() override {}
29 int add_count() const { return add_count_; }
30 int remove_count() const { return remove_count_; }
32 // TransientWindowObserver overrides:
33 void OnTransientChildAdded(Window* window, Window* transient) override {
34 add_count_++;
36 void OnTransientChildRemoved(Window* window, Window* transient) override {
37 remove_count_++;
40 private:
41 int add_count_;
42 int remove_count_;
44 DISALLOW_COPY_AND_ASSIGN(TestTransientWindowObserver);
47 class TransientWindowManagerTest : public aura::test::AuraTestBase {
48 public:
49 TransientWindowManagerTest() {}
50 ~TransientWindowManagerTest() override {}
52 void SetUp() override {
53 AuraTestBase::SetUp();
54 wm_state_.reset(new wm::WMState);
57 void TearDown() override {
58 wm_state_.reset();
59 AuraTestBase::TearDown();
62 protected:
63 // Creates a transient window that is transient to |parent|.
64 Window* CreateTransientChild(int id, Window* parent) {
65 Window* window = new Window(NULL);
66 window->set_id(id);
67 window->SetType(ui::wm::WINDOW_TYPE_NORMAL);
68 window->Init(ui::LAYER_TEXTURED);
69 AddTransientChild(parent, window);
70 aura::client::ParentWindowWithContext(window, root_window(), gfx::Rect());
71 return window;
74 private:
75 scoped_ptr<wm::WMState> wm_state_;
77 DISALLOW_COPY_AND_ASSIGN(TransientWindowManagerTest);
80 // Various assertions for transient children.
81 TEST_F(TransientWindowManagerTest, TransientChildren) {
82 scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
83 scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
84 scoped_ptr<Window> w3(CreateTestWindowWithId(3, parent.get()));
85 Window* w2 = CreateTestWindowWithId(2, parent.get());
86 // w2 is now owned by w1.
87 AddTransientChild(w1.get(), w2);
88 // Stack w1 at the top (end), this should force w2 to be last (on top of w1).
89 parent->StackChildAtTop(w1.get());
90 ASSERT_EQ(3u, parent->children().size());
91 EXPECT_EQ(w2, parent->children().back());
93 // Destroy w1, which should also destroy w3 (since it's a transient child).
94 w1.reset();
95 w2 = NULL;
96 ASSERT_EQ(1u, parent->children().size());
97 EXPECT_EQ(w3.get(), parent->children()[0]);
99 w1.reset(CreateTestWindowWithId(4, parent.get()));
100 w2 = CreateTestWindowWithId(5, w3.get());
101 AddTransientChild(w1.get(), w2);
102 parent->StackChildAtTop(w3.get());
103 // Stack w1 at the top (end), this shouldn't affect w2 since it has a
104 // different parent.
105 parent->StackChildAtTop(w1.get());
106 ASSERT_EQ(2u, parent->children().size());
107 EXPECT_EQ(w3.get(), parent->children()[0]);
108 EXPECT_EQ(w1.get(), parent->children()[1]);
110 // Hiding parent should hide transient children.
111 EXPECT_TRUE(w2->IsVisible());
112 w1->Hide();
113 EXPECT_FALSE(w2->IsVisible());
115 // And they should stay hidden even after the parent became visible.
116 w1->Show();
117 EXPECT_FALSE(w2->IsVisible());
119 // Hidden transient child should stay hidden regardless of
120 // parent's visibility.
121 w2->Hide();
122 EXPECT_FALSE(w2->IsVisible());
123 w1->Hide();
124 EXPECT_FALSE(w2->IsVisible());
125 w1->Show();
126 EXPECT_FALSE(w2->IsVisible());
128 // Transient child can be shown even if the transient parent is hidden.
129 w1->Hide();
130 EXPECT_FALSE(w2->IsVisible());
131 w2->Show();
132 EXPECT_TRUE(w2->IsVisible());
133 w1->Show();
134 EXPECT_TRUE(w2->IsVisible());
136 // When the parent_controls_visibility is true, TransientWindowManager
137 // controls the children's visibility. It stays invisible even if
138 // Window::Show() is called, and gets shown when the parent becomes visible.
139 wm::TransientWindowManager::Get(w2)->set_parent_controls_visibility(true);
140 w1->Hide();
141 EXPECT_FALSE(w2->IsVisible());
142 w2->Show();
143 EXPECT_FALSE(w2->IsVisible());
144 w1->Show();
145 EXPECT_TRUE(w2->IsVisible());
147 // Hiding a transient child that is hidden by the transient parent
148 // is not currently handled and will be shown anyway.
149 w1->Hide();
150 EXPECT_FALSE(w2->IsVisible());
151 w2->Hide();
152 EXPECT_FALSE(w2->IsVisible());
153 w1->Show();
154 EXPECT_TRUE(w2->IsVisible());
157 // Tests that transient children are stacked as a unit when using stack above.
158 TEST_F(TransientWindowManagerTest, TransientChildrenGroupAbove) {
159 scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
160 scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
161 Window* w11 = CreateTestWindowWithId(11, parent.get());
162 scoped_ptr<Window> w2(CreateTestWindowWithId(2, parent.get()));
163 Window* w21 = CreateTestWindowWithId(21, parent.get());
164 Window* w211 = CreateTestWindowWithId(211, parent.get());
165 Window* w212 = CreateTestWindowWithId(212, parent.get());
166 Window* w213 = CreateTestWindowWithId(213, parent.get());
167 Window* w22 = CreateTestWindowWithId(22, parent.get());
168 ASSERT_EQ(8u, parent->children().size());
170 // w11 is now owned by w1.
171 AddTransientChild(w1.get(), w11);
172 // w21 is now owned by w2.
173 AddTransientChild(w2.get(), w21);
174 // w22 is now owned by w2.
175 AddTransientChild(w2.get(), w22);
176 // w211 is now owned by w21.
177 AddTransientChild(w21, w211);
178 // w212 is now owned by w21.
179 AddTransientChild(w21, w212);
180 // w213 is now owned by w21.
181 AddTransientChild(w21, w213);
182 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
184 // Stack w1 at the top (end), this should force w11 to be last (on top of w1).
185 parent->StackChildAtTop(w1.get());
186 EXPECT_EQ(w11, parent->children().back());
187 EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
189 // This tests that the order in children_ array rather than in
190 // transient_children_ array is used when reinserting transient children.
191 // If transient_children_ array was used '22' would be following '21'.
192 parent->StackChildAtTop(w2.get());
193 EXPECT_EQ(w22, parent->children().back());
194 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
196 parent->StackChildAbove(w11, w2.get());
197 EXPECT_EQ(w11, parent->children().back());
198 EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
200 parent->StackChildAbove(w21, w1.get());
201 EXPECT_EQ(w22, parent->children().back());
202 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
204 parent->StackChildAbove(w21, w22);
205 EXPECT_EQ(w213, parent->children().back());
206 EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent.get()));
208 parent->StackChildAbove(w11, w21);
209 EXPECT_EQ(w11, parent->children().back());
210 EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent.get()));
212 parent->StackChildAbove(w213, w21);
213 EXPECT_EQ(w11, parent->children().back());
214 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
216 // No change when stacking a transient parent above its transient child.
217 parent->StackChildAbove(w21, w211);
218 EXPECT_EQ(w11, parent->children().back());
219 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
221 // This tests that the order in children_ array rather than in
222 // transient_children_ array is used when reinserting transient children.
223 // If transient_children_ array was used '22' would be following '21'.
224 parent->StackChildAbove(w2.get(), w1.get());
225 EXPECT_EQ(w212, parent->children().back());
226 EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent.get()));
228 parent->StackChildAbove(w11, w213);
229 EXPECT_EQ(w11, parent->children().back());
230 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
233 // Tests that transient children are stacked as a unit when using stack below.
234 TEST_F(TransientWindowManagerTest, TransientChildrenGroupBelow) {
235 scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
236 scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
237 Window* w11 = CreateTestWindowWithId(11, parent.get());
238 scoped_ptr<Window> w2(CreateTestWindowWithId(2, parent.get()));
239 Window* w21 = CreateTestWindowWithId(21, parent.get());
240 Window* w211 = CreateTestWindowWithId(211, parent.get());
241 Window* w212 = CreateTestWindowWithId(212, parent.get());
242 Window* w213 = CreateTestWindowWithId(213, parent.get());
243 Window* w22 = CreateTestWindowWithId(22, parent.get());
244 ASSERT_EQ(8u, parent->children().size());
246 // w11 is now owned by w1.
247 AddTransientChild(w1.get(), w11);
248 // w21 is now owned by w2.
249 AddTransientChild(w2.get(), w21);
250 // w22 is now owned by w2.
251 AddTransientChild(w2.get(), w22);
252 // w211 is now owned by w21.
253 AddTransientChild(w21, w211);
254 // w212 is now owned by w21.
255 AddTransientChild(w21, w212);
256 // w213 is now owned by w21.
257 AddTransientChild(w21, w213);
258 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
260 // Stack w2 at the bottom, this should force w11 to be last (on top of w1).
261 // This also tests that the order in children_ array rather than in
262 // transient_children_ array is used when reinserting transient children.
263 // If transient_children_ array was used '22' would be following '21'.
264 parent->StackChildAtBottom(w2.get());
265 EXPECT_EQ(w11, parent->children().back());
266 EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
268 parent->StackChildAtBottom(w1.get());
269 EXPECT_EQ(w22, parent->children().back());
270 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
272 parent->StackChildBelow(w21, w1.get());
273 EXPECT_EQ(w11, parent->children().back());
274 EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
276 parent->StackChildBelow(w11, w2.get());
277 EXPECT_EQ(w22, parent->children().back());
278 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
280 parent->StackChildBelow(w22, w21);
281 EXPECT_EQ(w213, parent->children().back());
282 EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent.get()));
284 parent->StackChildBelow(w21, w11);
285 EXPECT_EQ(w11, parent->children().back());
286 EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent.get()));
288 parent->StackChildBelow(w213, w211);
289 EXPECT_EQ(w11, parent->children().back());
290 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
292 // No change when stacking a transient parent below its transient child.
293 parent->StackChildBelow(w21, w211);
294 EXPECT_EQ(w11, parent->children().back());
295 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
297 parent->StackChildBelow(w1.get(), w2.get());
298 EXPECT_EQ(w212, parent->children().back());
299 EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent.get()));
301 parent->StackChildBelow(w213, w11);
302 EXPECT_EQ(w11, parent->children().back());
303 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
306 // Tests that transient windows are stacked properly when created.
307 TEST_F(TransientWindowManagerTest, StackUponCreation) {
308 scoped_ptr<Window> window0(CreateTestWindowWithId(0, root_window()));
309 scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
311 scoped_ptr<Window> window2(CreateTransientChild(2, window0.get()));
312 EXPECT_EQ("0 2 1", ChildWindowIDsAsString(root_window()));
315 // Tests that windows are restacked properly after a call to AddTransientChild()
316 // or RemoveTransientChild().
317 TEST_F(TransientWindowManagerTest, RestackUponAddOrRemoveTransientChild) {
318 scoped_ptr<Window> windows[4];
319 for (int i = 0; i < 4; i++)
320 windows[i].reset(CreateTestWindowWithId(i, root_window()));
321 EXPECT_EQ("0 1 2 3", ChildWindowIDsAsString(root_window()));
323 AddTransientChild(windows[0].get(), windows[2].get());
324 EXPECT_EQ("0 2 1 3", ChildWindowIDsAsString(root_window()));
326 AddTransientChild(windows[0].get(), windows[3].get());
327 EXPECT_EQ("0 2 3 1", ChildWindowIDsAsString(root_window()));
329 RemoveTransientChild(windows[0].get(), windows[2].get());
330 EXPECT_EQ("0 3 2 1", ChildWindowIDsAsString(root_window()));
332 RemoveTransientChild(windows[0].get(), windows[3].get());
333 EXPECT_EQ("0 3 2 1", ChildWindowIDsAsString(root_window()));
336 namespace {
338 // Used by NotifyDelegateAfterDeletingTransients. Adds a string to a vector when
339 // OnWindowDestroyed() is invoked so that destruction order can be verified.
340 class DestroyedTrackingDelegate : public aura::test::TestWindowDelegate {
341 public:
342 explicit DestroyedTrackingDelegate(const std::string& name,
343 std::vector<std::string>* results)
344 : name_(name),
345 results_(results) {}
347 void OnWindowDestroyed(aura::Window* window) override {
348 results_->push_back(name_);
351 private:
352 const std::string name_;
353 std::vector<std::string>* results_;
355 DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingDelegate);
358 } // namespace
360 // Verifies the delegate is notified of destruction after transients are
361 // destroyed.
362 TEST_F(TransientWindowManagerTest, NotifyDelegateAfterDeletingTransients) {
363 std::vector<std::string> destruction_order;
365 DestroyedTrackingDelegate parent_delegate("parent", &destruction_order);
366 scoped_ptr<Window> parent(new Window(&parent_delegate));
367 parent->Init(ui::LAYER_NOT_DRAWN);
369 DestroyedTrackingDelegate transient_delegate("transient", &destruction_order);
370 Window* transient = new Window(&transient_delegate); // Owned by |parent|.
371 transient->Init(ui::LAYER_NOT_DRAWN);
372 AddTransientChild(parent.get(), transient);
373 parent.reset();
375 ASSERT_EQ(2u, destruction_order.size());
376 EXPECT_EQ("transient", destruction_order[0]);
377 EXPECT_EQ("parent", destruction_order[1]);
380 TEST_F(TransientWindowManagerTest,
381 StackTransientsLayersRelativeToOtherTransients) {
382 // Create a window with several transients, then a couple windows on top.
383 scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
384 scoped_ptr<Window> window11(CreateTransientChild(11, window1.get()));
385 scoped_ptr<Window> window12(CreateTransientChild(12, window1.get()));
386 scoped_ptr<Window> window13(CreateTransientChild(13, window1.get()));
388 EXPECT_EQ("1 11 12 13", ChildWindowIDsAsString(root_window()));
390 // Stack 11 above 12.
391 root_window()->StackChildAbove(window11.get(), window12.get());
392 EXPECT_EQ("1 12 11 13", ChildWindowIDsAsString(root_window()));
394 // Stack 13 below 12.
395 root_window()->StackChildBelow(window13.get(), window12.get());
396 EXPECT_EQ("1 13 12 11", ChildWindowIDsAsString(root_window()));
398 // Stack 11 above 1.
399 root_window()->StackChildAbove(window11.get(), window1.get());
400 EXPECT_EQ("1 11 13 12", ChildWindowIDsAsString(root_window()));
402 // Stack 12 below 13.
403 root_window()->StackChildBelow(window12.get(), window13.get());
404 EXPECT_EQ("1 11 12 13", ChildWindowIDsAsString(root_window()));
407 // Verifies TransientWindowObserver is notified appropriately.
408 TEST_F(TransientWindowManagerTest, TransientWindowObserverNotified) {
409 scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
410 scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
412 TestTransientWindowObserver test_observer;
413 TransientWindowManager::Get(parent.get())->AddObserver(&test_observer);
415 AddTransientChild(parent.get(), w1.get());
416 EXPECT_EQ(1, test_observer.add_count());
417 EXPECT_EQ(0, test_observer.remove_count());
419 RemoveTransientChild(parent.get(), w1.get());
420 EXPECT_EQ(1, test_observer.add_count());
421 EXPECT_EQ(1, test_observer.remove_count());
423 TransientWindowManager::Get(parent.get())->RemoveObserver(&test_observer);
426 } // namespace wm