Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(396)

Side by Side Diff: ui/wm/core/transient_window_manager_unittest.cc

Issue 851853002: It is time. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Trying to reup because the last upload failed. Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/wm/core/transient_window_manager.cc ('k') | ui/wm/core/transient_window_observer.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 // And they should stay hidden even after the parent became visible.
121 w1->Show();
122 EXPECT_FALSE(w2->IsVisible());
123
124 // Hidden transient child should stay hidden regardless of
125 // parent's visibility.
126 w2->Hide();
127 EXPECT_FALSE(w2->IsVisible());
128 w1->Hide();
129 EXPECT_FALSE(w2->IsVisible());
130 w1->Show();
131 EXPECT_FALSE(w2->IsVisible());
132
133 // Transient child can be shown even if the transient parent is hidden.
134 w1->Hide();
135 EXPECT_FALSE(w2->IsVisible());
136 w2->Show();
137 EXPECT_TRUE(w2->IsVisible());
138 w1->Show();
139 EXPECT_TRUE(w2->IsVisible());
140
141 // When the parent_controls_visibility is true, TransientWindowManager
142 // controls the children's visibility. It stays invisible even if
143 // Window::Show() is called, and gets shown when the parent becomes visible.
144 wm::TransientWindowManager::Get(w2)->set_parent_controls_visibility(true);
145 w1->Hide();
146 EXPECT_FALSE(w2->IsVisible());
147 w2->Show();
148 EXPECT_FALSE(w2->IsVisible());
149 w1->Show();
150 EXPECT_TRUE(w2->IsVisible());
151
152 // Hiding a transient child that is hidden by the transient parent
153 // is not currently handled and will be shown anyway.
154 w1->Hide();
155 EXPECT_FALSE(w2->IsVisible());
156 w2->Hide();
157 EXPECT_FALSE(w2->IsVisible());
158 w1->Show();
159 EXPECT_TRUE(w2->IsVisible());
160 }
161
162 // Tests that transient children are stacked as a unit when using stack above.
163 TEST_F(TransientWindowManagerTest, TransientChildrenGroupAbove) {
164 scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
165 scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
166 Window* w11 = CreateTestWindowWithId(11, parent.get());
167 scoped_ptr<Window> w2(CreateTestWindowWithId(2, parent.get()));
168 Window* w21 = CreateTestWindowWithId(21, parent.get());
169 Window* w211 = CreateTestWindowWithId(211, parent.get());
170 Window* w212 = CreateTestWindowWithId(212, parent.get());
171 Window* w213 = CreateTestWindowWithId(213, parent.get());
172 Window* w22 = CreateTestWindowWithId(22, parent.get());
173 ASSERT_EQ(8u, parent->children().size());
174
175 // w11 is now owned by w1.
176 AddTransientChild(w1.get(), w11);
177 // w21 is now owned by w2.
178 AddTransientChild(w2.get(), w21);
179 // w22 is now owned by w2.
180 AddTransientChild(w2.get(), w22);
181 // w211 is now owned by w21.
182 AddTransientChild(w21, w211);
183 // w212 is now owned by w21.
184 AddTransientChild(w21, w212);
185 // w213 is now owned by w21.
186 AddTransientChild(w21, w213);
187 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
188
189 // Stack w1 at the top (end), this should force w11 to be last (on top of w1).
190 parent->StackChildAtTop(w1.get());
191 EXPECT_EQ(w11, parent->children().back());
192 EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
193
194 // This tests that the order in children_ array rather than in
195 // transient_children_ array is used when reinserting transient children.
196 // If transient_children_ array was used '22' would be following '21'.
197 parent->StackChildAtTop(w2.get());
198 EXPECT_EQ(w22, parent->children().back());
199 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
200
201 parent->StackChildAbove(w11, w2.get());
202 EXPECT_EQ(w11, parent->children().back());
203 EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
204
205 parent->StackChildAbove(w21, w1.get());
206 EXPECT_EQ(w22, parent->children().back());
207 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
208
209 parent->StackChildAbove(w21, w22);
210 EXPECT_EQ(w213, parent->children().back());
211 EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent.get()));
212
213 parent->StackChildAbove(w11, w21);
214 EXPECT_EQ(w11, parent->children().back());
215 EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent.get()));
216
217 parent->StackChildAbove(w213, w21);
218 EXPECT_EQ(w11, parent->children().back());
219 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
220
221 // No change when stacking a transient parent above its transient child.
222 parent->StackChildAbove(w21, w211);
223 EXPECT_EQ(w11, parent->children().back());
224 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
225
226 // This tests that the order in children_ array rather than in
227 // transient_children_ array is used when reinserting transient children.
228 // If transient_children_ array was used '22' would be following '21'.
229 parent->StackChildAbove(w2.get(), w1.get());
230 EXPECT_EQ(w212, parent->children().back());
231 EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent.get()));
232
233 parent->StackChildAbove(w11, w213);
234 EXPECT_EQ(w11, parent->children().back());
235 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
236 }
237
238 // Tests that transient children are stacked as a unit when using stack below.
239 TEST_F(TransientWindowManagerTest, TransientChildrenGroupBelow) {
240 scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
241 scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
242 Window* w11 = CreateTestWindowWithId(11, parent.get());
243 scoped_ptr<Window> w2(CreateTestWindowWithId(2, parent.get()));
244 Window* w21 = CreateTestWindowWithId(21, parent.get());
245 Window* w211 = CreateTestWindowWithId(211, parent.get());
246 Window* w212 = CreateTestWindowWithId(212, parent.get());
247 Window* w213 = CreateTestWindowWithId(213, parent.get());
248 Window* w22 = CreateTestWindowWithId(22, parent.get());
249 ASSERT_EQ(8u, parent->children().size());
250
251 // w11 is now owned by w1.
252 AddTransientChild(w1.get(), w11);
253 // w21 is now owned by w2.
254 AddTransientChild(w2.get(), w21);
255 // w22 is now owned by w2.
256 AddTransientChild(w2.get(), w22);
257 // w211 is now owned by w21.
258 AddTransientChild(w21, w211);
259 // w212 is now owned by w21.
260 AddTransientChild(w21, w212);
261 // w213 is now owned by w21.
262 AddTransientChild(w21, w213);
263 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
264
265 // Stack w2 at the bottom, this should force w11 to be last (on top of w1).
266 // This also tests that the order in children_ array rather than in
267 // transient_children_ array is used when reinserting transient children.
268 // If transient_children_ array was used '22' would be following '21'.
269 parent->StackChildAtBottom(w2.get());
270 EXPECT_EQ(w11, parent->children().back());
271 EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
272
273 parent->StackChildAtBottom(w1.get());
274 EXPECT_EQ(w22, parent->children().back());
275 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
276
277 parent->StackChildBelow(w21, w1.get());
278 EXPECT_EQ(w11, parent->children().back());
279 EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
280
281 parent->StackChildBelow(w11, w2.get());
282 EXPECT_EQ(w22, parent->children().back());
283 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
284
285 parent->StackChildBelow(w22, w21);
286 EXPECT_EQ(w213, parent->children().back());
287 EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent.get()));
288
289 parent->StackChildBelow(w21, w11);
290 EXPECT_EQ(w11, parent->children().back());
291 EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent.get()));
292
293 parent->StackChildBelow(w213, w211);
294 EXPECT_EQ(w11, parent->children().back());
295 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
296
297 // No change when stacking a transient parent below its transient child.
298 parent->StackChildBelow(w21, w211);
299 EXPECT_EQ(w11, parent->children().back());
300 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
301
302 parent->StackChildBelow(w1.get(), w2.get());
303 EXPECT_EQ(w212, parent->children().back());
304 EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent.get()));
305
306 parent->StackChildBelow(w213, w11);
307 EXPECT_EQ(w11, parent->children().back());
308 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
309 }
310
311 // Tests that transient windows are stacked properly when created.
312 TEST_F(TransientWindowManagerTest, StackUponCreation) {
313 scoped_ptr<Window> window0(CreateTestWindowWithId(0, root_window()));
314 scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
315
316 scoped_ptr<Window> window2(CreateTransientChild(2, window0.get()));
317 EXPECT_EQ("0 2 1", ChildWindowIDsAsString(root_window()));
318 }
319
320 // Tests that windows are restacked properly after a call to AddTransientChild()
321 // or RemoveTransientChild().
322 TEST_F(TransientWindowManagerTest, RestackUponAddOrRemoveTransientChild) {
323 scoped_ptr<Window> windows[4];
324 for (int i = 0; i < 4; i++)
325 windows[i].reset(CreateTestWindowWithId(i, root_window()));
326 EXPECT_EQ("0 1 2 3", ChildWindowIDsAsString(root_window()));
327
328 AddTransientChild(windows[0].get(), windows[2].get());
329 EXPECT_EQ("0 2 1 3", ChildWindowIDsAsString(root_window()));
330
331 AddTransientChild(windows[0].get(), windows[3].get());
332 EXPECT_EQ("0 2 3 1", ChildWindowIDsAsString(root_window()));
333
334 RemoveTransientChild(windows[0].get(), windows[2].get());
335 EXPECT_EQ("0 3 2 1", ChildWindowIDsAsString(root_window()));
336
337 RemoveTransientChild(windows[0].get(), windows[3].get());
338 EXPECT_EQ("0 3 2 1", ChildWindowIDsAsString(root_window()));
339 }
340
341 namespace {
342
343 // Used by NotifyDelegateAfterDeletingTransients. Adds a string to a vector when
344 // OnWindowDestroyed() is invoked so that destruction order can be verified.
345 class DestroyedTrackingDelegate : public aura::test::TestWindowDelegate {
346 public:
347 explicit DestroyedTrackingDelegate(const std::string& name,
348 std::vector<std::string>* results)
349 : name_(name),
350 results_(results) {}
351
352 virtual void OnWindowDestroyed(aura::Window* window) override {
353 results_->push_back(name_);
354 }
355
356 private:
357 const std::string name_;
358 std::vector<std::string>* results_;
359
360 DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingDelegate);
361 };
362
363 } // namespace
364
365 // Verifies the delegate is notified of destruction after transients are
366 // destroyed.
367 TEST_F(TransientWindowManagerTest, NotifyDelegateAfterDeletingTransients) {
368 std::vector<std::string> destruction_order;
369
370 DestroyedTrackingDelegate parent_delegate("parent", &destruction_order);
371 scoped_ptr<Window> parent(new Window(&parent_delegate));
372 parent->Init(aura::WINDOW_LAYER_NOT_DRAWN);
373
374 DestroyedTrackingDelegate transient_delegate("transient", &destruction_order);
375 Window* transient = new Window(&transient_delegate); // Owned by |parent|.
376 transient->Init(aura::WINDOW_LAYER_NOT_DRAWN);
377 AddTransientChild(parent.get(), transient);
378 parent.reset();
379
380 ASSERT_EQ(2u, destruction_order.size());
381 EXPECT_EQ("transient", destruction_order[0]);
382 EXPECT_EQ("parent", destruction_order[1]);
383 }
384
385 TEST_F(TransientWindowManagerTest, StackTransientsWhoseLayersHaveNoDelegate) {
386 // Create a window with several transients, then a couple windows on top.
387 scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
388 scoped_ptr<Window> window11(CreateTransientChild(11, window1.get()));
389 scoped_ptr<Window> window12(CreateTransientChild(12, window1.get()));
390 scoped_ptr<Window> window13(CreateTransientChild(13, window1.get()));
391 scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window()));
392 scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window()));
393
394 EXPECT_EQ("1 11 12 13 2 3", ChildWindowIDsAsString(root_window()));
395
396 // Remove the delegates of a couple of transients, as if they are closing
397 // and animating out.
398 window11->layer()->set_delegate(NULL);
399 window13->layer()->set_delegate(NULL);
400
401 // Move window1 to the front. All transients should move with it, and their
402 // order should be preserved.
403 root_window()->StackChildAtTop(window1.get());
404
405 EXPECT_EQ("2 3 1 11 12 13", ChildWindowIDsAsString(root_window()));
406 }
407
408 TEST_F(TransientWindowManagerTest,
409 StackTransientsLayersRelativeToOtherTransients) {
410 // Create a window with several transients, then a couple windows on top.
411 scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
412 scoped_ptr<Window> window11(CreateTransientChild(11, window1.get()));
413 scoped_ptr<Window> window12(CreateTransientChild(12, window1.get()));
414 scoped_ptr<Window> window13(CreateTransientChild(13, window1.get()));
415
416 EXPECT_EQ("1 11 12 13", ChildWindowIDsAsString(root_window()));
417
418 // Stack 11 above 12.
419 root_window()->StackChildAbove(window11.get(), window12.get());
420 EXPECT_EQ("1 12 11 13", ChildWindowIDsAsString(root_window()));
421
422 // Stack 13 below 12.
423 root_window()->StackChildBelow(window13.get(), window12.get());
424 EXPECT_EQ("1 13 12 11", ChildWindowIDsAsString(root_window()));
425
426 // Stack 11 above 1.
427 root_window()->StackChildAbove(window11.get(), window1.get());
428 EXPECT_EQ("1 11 13 12", ChildWindowIDsAsString(root_window()));
429
430 // Stack 12 below 13.
431 root_window()->StackChildBelow(window12.get(), window13.get());
432 EXPECT_EQ("1 11 12 13", ChildWindowIDsAsString(root_window()));
433 }
434
435 TEST_F(TransientWindowManagerTest,
436 StackTransientsLayersRelativeToOtherTransientsNoLayerDelegate) {
437 // Create a window with several transients, then a couple windows on top.
438 scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
439 scoped_ptr<Window> window11(CreateTransientChild(11, window1.get()));
440 scoped_ptr<Window> window12(CreateTransientChild(12, window1.get()));
441 scoped_ptr<Window> window13(CreateTransientChild(13, window1.get()));
442 scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window()));
443 scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window()));
444
445 EXPECT_EQ("1 11 12 13 2 3", ChildWindowIDsAsString(root_window()));
446
447 window1->layer()->set_delegate(NULL);
448
449 // Stack 1 at top.
450 root_window()->StackChildAtTop(window1.get());
451 EXPECT_EQ("2 3 1 11 12 13", ChildWindowIDsAsString(root_window()));
452 }
453
454 class StackingMadrigalLayoutManager : public aura::LayoutManager {
455 public:
456 explicit StackingMadrigalLayoutManager(Window* root_window)
457 : root_window_(root_window) {
458 root_window_->SetLayoutManager(this);
459 }
460 virtual ~StackingMadrigalLayoutManager() {
461 }
462
463 private:
464 // Overridden from LayoutManager:
465 virtual void OnWindowResized() override {}
466 virtual void OnWindowAddedToLayout(Window* child) override {}
467 virtual void OnWillRemoveWindowFromLayout(Window* child) override {}
468 virtual void OnWindowRemovedFromLayout(Window* child) override {}
469 virtual void OnChildWindowVisibilityChanged(Window* child,
470 bool visible) override {
471 Window::Windows::const_iterator it = root_window_->children().begin();
472 Window* last_window = NULL;
473 for (; it != root_window_->children().end(); ++it) {
474 if (*it == child && last_window) {
475 if (!visible)
476 root_window_->StackChildAbove(last_window, *it);
477 else
478 root_window_->StackChildAbove(*it, last_window);
479 break;
480 }
481 last_window = *it;
482 }
483 }
484 virtual void SetChildBounds(Window* child,
485 const gfx::Rect& requested_bounds) override {
486 SetChildBoundsDirect(child, requested_bounds);
487 }
488
489 Window* root_window_;
490
491 DISALLOW_COPY_AND_ASSIGN(StackingMadrigalLayoutManager);
492 };
493
494 class StackingMadrigalVisibilityClient : public aura::client::VisibilityClient {
495 public:
496 explicit StackingMadrigalVisibilityClient(Window* root_window)
497 : ignored_window_(NULL) {
498 aura::client::SetVisibilityClient(root_window, this);
499 }
500 virtual ~StackingMadrigalVisibilityClient() {
501 }
502
503 void set_ignored_window(Window* ignored_window) {
504 ignored_window_ = ignored_window;
505 }
506
507 private:
508 // Overridden from client::VisibilityClient:
509 virtual void UpdateLayerVisibility(Window* window, bool visible) override {
510 if (!visible) {
511 if (window == ignored_window_)
512 window->layer()->set_delegate(NULL);
513 else
514 window->layer()->SetVisible(visible);
515 } else {
516 window->layer()->SetVisible(visible);
517 }
518 }
519
520 Window* ignored_window_;
521
522 DISALLOW_COPY_AND_ASSIGN(StackingMadrigalVisibilityClient);
523 };
524
525 // This test attempts to reconstruct a circumstance that can happen when the
526 // aura client attempts to manipulate the visibility and delegate of a layer
527 // independent of window visibility.
528 // A use case is where the client attempts to keep a window visible onscreen
529 // even after code has called Hide() on the window. The use case for this would
530 // be that window hides are animated (e.g. the window fades out). To prevent
531 // spurious updating the client code may also clear window's layer's delegate,
532 // so that the window cannot attempt to paint or update it further. The window
533 // uses the presence of a NULL layer delegate as a signal in stacking to note
534 // that the window is being manipulated by such a use case and its stacking
535 // should not be adjusted.
536 // One issue that can arise when a window opens two transient children, and the
537 // first is hidden. Subsequent attempts to activate the transient parent can
538 // result in the transient parent being stacked above the second transient
539 // child. A fix is made to Window::StackAbove to prevent this, and this test
540 // verifies this fix.
541 TEST_F(TransientWindowManagerTest, StackingMadrigal) {
542 new StackingMadrigalLayoutManager(root_window());
543 StackingMadrigalVisibilityClient visibility_client(root_window());
544
545 scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
546 scoped_ptr<Window> window11(CreateTransientChild(11, window1.get()));
547
548 visibility_client.set_ignored_window(window11.get());
549
550 window11->Show();
551 window11->Hide();
552
553 // As a transient, window11 should still be stacked above window1, even when
554 // hidden.
555 EXPECT_TRUE(aura::test::WindowIsAbove(window11.get(), window1.get()));
556 EXPECT_TRUE(aura::test::LayerIsAbove(window11.get(), window1.get()));
557
558 // A new transient should still be above window1. It will appear behind
559 // window11 because we don't stack windows on top of targets with NULL
560 // delegates.
561 scoped_ptr<Window> window12(CreateTransientChild(12, window1.get()));
562 window12->Show();
563
564 EXPECT_TRUE(aura::test::WindowIsAbove(window12.get(), window1.get()));
565 EXPECT_TRUE(aura::test::LayerIsAbove(window12.get(), window1.get()));
566
567 // In earlier versions of the StackChildAbove() method, attempting to stack
568 // window1 above window12 at this point would actually restack the layers
569 // resulting in window12's layer being below window1's layer (though the
570 // windows themselves would still be correctly stacked, so events would pass
571 // through.)
572 root_window()->StackChildAbove(window1.get(), window12.get());
573
574 // Both window12 and its layer should be stacked above window1.
575 EXPECT_TRUE(aura::test::WindowIsAbove(window12.get(), window1.get()));
576 EXPECT_TRUE(aura::test::LayerIsAbove(window12.get(), window1.get()));
577 }
578
579 // Test for an issue where attempting to stack a primary window on top of a
580 // transient with a NULL layer delegate causes that primary window to be moved,
581 // but the layer order not changed to match. http://crbug.com/112562
582 TEST_F(TransientWindowManagerTest, StackOverClosingTransient) {
583 scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
584 scoped_ptr<Window> transient1(CreateTransientChild(11, window1.get()));
585 scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window()));
586 scoped_ptr<Window> transient2(CreateTransientChild(21, window2.get()));
587
588 // Both windows and layers are stacked in creation order.
589 Window* root = root_window();
590 ASSERT_EQ(4u, root->children().size());
591 EXPECT_EQ(root->children()[0], window1.get());
592 EXPECT_EQ(root->children()[1], transient1.get());
593 EXPECT_EQ(root->children()[2], window2.get());
594 EXPECT_EQ(root->children()[3], transient2.get());
595 ASSERT_EQ(4u, root->layer()->children().size());
596 EXPECT_EQ(root->layer()->children()[0], window1->layer());
597 EXPECT_EQ(root->layer()->children()[1], transient1->layer());
598 EXPECT_EQ(root->layer()->children()[2], window2->layer());
599 EXPECT_EQ(root->layer()->children()[3], transient2->layer());
600 EXPECT_EQ("1 11 2 21", ChildWindowIDsAsString(root_window()));
601
602 // This brings window1 and its transient to the front.
603 root->StackChildAtTop(window1.get());
604 EXPECT_EQ("2 21 1 11", ChildWindowIDsAsString(root_window()));
605
606 EXPECT_EQ(root->children()[0], window2.get());
607 EXPECT_EQ(root->children()[1], transient2.get());
608 EXPECT_EQ(root->children()[2], window1.get());
609 EXPECT_EQ(root->children()[3], transient1.get());
610 EXPECT_EQ(root->layer()->children()[0], window2->layer());
611 EXPECT_EQ(root->layer()->children()[1], transient2->layer());
612 EXPECT_EQ(root->layer()->children()[2], window1->layer());
613 EXPECT_EQ(root->layer()->children()[3], transient1->layer());
614
615 // Pretend we're closing the top-most transient, then bring window2 to the
616 // front. This mimics activating a browser window while the status bubble
617 // is fading out. The transient should stay topmost.
618 transient1->layer()->set_delegate(NULL);
619 root->StackChildAtTop(window2.get());
620
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], transient1.get());
625 EXPECT_EQ(root->layer()->children()[0], window1->layer());
626 EXPECT_EQ(root->layer()->children()[1], window2->layer());
627 EXPECT_EQ(root->layer()->children()[2], transient2->layer());
628 EXPECT_EQ(root->layer()->children()[3], transient1->layer());
629
630 // Close the transient. Remaining windows are stable.
631 transient1.reset();
632
633 ASSERT_EQ(3u, root->children().size());
634 EXPECT_EQ(root->children()[0], window1.get());
635 EXPECT_EQ(root->children()[1], window2.get());
636 EXPECT_EQ(root->children()[2], transient2.get());
637 ASSERT_EQ(3u, root->layer()->children().size());
638 EXPECT_EQ(root->layer()->children()[0], window1->layer());
639 EXPECT_EQ(root->layer()->children()[1], window2->layer());
640 EXPECT_EQ(root->layer()->children()[2], transient2->layer());
641
642 // Open another window on top.
643 scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window()));
644
645 ASSERT_EQ(4u, root->children().size());
646 EXPECT_EQ(root->children()[0], window1.get());
647 EXPECT_EQ(root->children()[1], window2.get());
648 EXPECT_EQ(root->children()[2], transient2.get());
649 EXPECT_EQ(root->children()[3], window3.get());
650 ASSERT_EQ(4u, root->layer()->children().size());
651 EXPECT_EQ(root->layer()->children()[0], window1->layer());
652 EXPECT_EQ(root->layer()->children()[1], window2->layer());
653 EXPECT_EQ(root->layer()->children()[2], transient2->layer());
654 EXPECT_EQ(root->layer()->children()[3], window3->layer());
655
656 // Pretend we're closing the topmost non-transient window, then bring
657 // window2 to the top. It should not move.
658 window3->layer()->set_delegate(NULL);
659 root->StackChildAtTop(window2.get());
660
661 ASSERT_EQ(4u, root->children().size());
662 EXPECT_EQ(root->children()[0], window1.get());
663 EXPECT_EQ(root->children()[1], window2.get());
664 EXPECT_EQ(root->children()[2], transient2.get());
665 EXPECT_EQ(root->children()[3], window3.get());
666 ASSERT_EQ(4u, root->layer()->children().size());
667 EXPECT_EQ(root->layer()->children()[0], window1->layer());
668 EXPECT_EQ(root->layer()->children()[1], window2->layer());
669 EXPECT_EQ(root->layer()->children()[2], transient2->layer());
670 EXPECT_EQ(root->layer()->children()[3], window3->layer());
671
672 // Bring window1 to the top. It should move ahead of window2, but not
673 // ahead of window3 (with NULL delegate).
674 root->StackChildAtTop(window1.get());
675
676 ASSERT_EQ(4u, root->children().size());
677 EXPECT_EQ(root->children()[0], window2.get());
678 EXPECT_EQ(root->children()[1], transient2.get());
679 EXPECT_EQ(root->children()[2], window1.get());
680 EXPECT_EQ(root->children()[3], window3.get());
681 ASSERT_EQ(4u, root->layer()->children().size());
682 EXPECT_EQ(root->layer()->children()[0], window2->layer());
683 EXPECT_EQ(root->layer()->children()[1], transient2->layer());
684 EXPECT_EQ(root->layer()->children()[2], window1->layer());
685 EXPECT_EQ(root->layer()->children()[3], window3->layer());
686 }
687
688 // Verifies TransientWindowObserver is notified appropriately.
689 TEST_F(TransientWindowManagerTest, TransientWindowObserverNotified) {
690 scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
691 scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
692
693 TestTransientWindowObserver test_observer;
694 TransientWindowManager::Get(parent.get())->AddObserver(&test_observer);
695
696 AddTransientChild(parent.get(), w1.get());
697 EXPECT_EQ(1, test_observer.add_count());
698 EXPECT_EQ(0, test_observer.remove_count());
699
700 RemoveTransientChild(parent.get(), w1.get());
701 EXPECT_EQ(1, test_observer.add_count());
702 EXPECT_EQ(1, test_observer.remove_count());
703
704 TransientWindowManager::Get(parent.get())->RemoveObserver(&test_observer);
705 }
706
707 } // namespace wm
OLDNEW
« no previous file with comments | « ui/wm/core/transient_window_manager.cc ('k') | ui/wm/core/transient_window_observer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698