OLD | NEW |
| (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 "services/ui/public/cpp/window.h" | |
6 | |
7 #include <limits.h> | |
8 #include <stdint.h> | |
9 | |
10 #include "base/logging.h" | |
11 #include "base/macros.h" | |
12 #include "base/strings/string_number_conversions.h" | |
13 #include "base/strings/stringprintf.h" | |
14 #include "services/ui/common/util.h" | |
15 #include "services/ui/public/cpp/property_type_converters.h" | |
16 #include "services/ui/public/cpp/tests/test_window.h" | |
17 #include "services/ui/public/cpp/window_observer.h" | |
18 #include "services/ui/public/cpp/window_private.h" | |
19 #include "services/ui/public/cpp/window_property.h" | |
20 #include "testing/gtest/include/gtest/gtest.h" | |
21 #include "ui/gfx/geometry/rect.h" | |
22 | |
23 namespace ui { | |
24 | |
25 namespace { | |
26 | |
27 TestWindow* CreateTestWindow(TestWindow* parent) { | |
28 TestWindow* window = new TestWindow; | |
29 if (parent) | |
30 parent->AddChild(window); | |
31 return window; | |
32 } | |
33 | |
34 TestWindow* CreateTestWindow(int id, TestWindow* parent) { | |
35 TestWindow* window = new TestWindow(0); | |
36 window->set_local_id(id); | |
37 if (parent) | |
38 parent->AddChild(window); | |
39 return window; | |
40 } | |
41 | |
42 std::string ChildWindowIDsAsString(TestWindow* parent) { | |
43 std::string result; | |
44 for (Window* child : parent->children()) { | |
45 if (!result.empty()) | |
46 result += " "; | |
47 result += base::IntToString(child->local_id()); | |
48 } | |
49 return result; | |
50 } | |
51 | |
52 } // namespace | |
53 // Window --------------------------------------------------------------------- | |
54 | |
55 using WindowTest = testing::Test; | |
56 | |
57 TEST_F(WindowTest, AddChild) { | |
58 TestWindow w1; | |
59 TestWindow w11; | |
60 w1.AddChild(&w11); | |
61 EXPECT_EQ(1U, w1.children().size()); | |
62 } | |
63 | |
64 TEST_F(WindowTest, RemoveChild) { | |
65 TestWindow w1; | |
66 TestWindow w11; | |
67 w1.AddChild(&w11); | |
68 EXPECT_EQ(1U, w1.children().size()); | |
69 w1.RemoveChild(&w11); | |
70 EXPECT_EQ(0U, w1.children().size()); | |
71 } | |
72 | |
73 TEST_F(WindowTest, Reparent) { | |
74 TestWindow w1; | |
75 TestWindow w2; | |
76 TestWindow w11; | |
77 w1.AddChild(&w11); | |
78 EXPECT_EQ(1U, w1.children().size()); | |
79 w2.AddChild(&w11); | |
80 EXPECT_EQ(1U, w2.children().size()); | |
81 EXPECT_EQ(0U, w1.children().size()); | |
82 } | |
83 | |
84 TEST_F(WindowTest, Contains) { | |
85 TestWindow w1; | |
86 | |
87 // Direct descendant. | |
88 TestWindow w11; | |
89 w1.AddChild(&w11); | |
90 EXPECT_TRUE(w1.Contains(&w11)); | |
91 | |
92 // Indirect descendant. | |
93 TestWindow w111; | |
94 w11.AddChild(&w111); | |
95 EXPECT_TRUE(w1.Contains(&w111)); | |
96 } | |
97 TEST_F(WindowTest, GetChildByLocalId) { | |
98 TestWindow w1; | |
99 w1.set_local_id(0); | |
100 EXPECT_EQ(&w1, w1.GetChildByLocalId(0)); | |
101 | |
102 TestWindow w11; | |
103 w11.set_local_id(11); | |
104 w1.AddChild(&w11); | |
105 | |
106 TestWindow w12; | |
107 w12.set_local_id(w1.local_id()); | |
108 w1.AddChild(&w12); | |
109 | |
110 TestWindow w111; | |
111 w111.set_local_id(111); | |
112 w11.AddChild(&w111); | |
113 | |
114 // Find direct & indirect descendents. | |
115 EXPECT_EQ(&w11, w1.GetChildByLocalId(w11.local_id())); | |
116 EXPECT_EQ(&w111, w1.GetChildByLocalId(w111.local_id())); | |
117 // Verifies parent returned by child with same id. | |
118 EXPECT_EQ(&w1, w1.GetChildByLocalId(w1.local_id())); | |
119 } | |
120 | |
121 TEST_F(WindowTest, DrawnAndVisible) { | |
122 TestWindow w1; | |
123 EXPECT_FALSE(w1.visible()); | |
124 w1.SetVisible(true); | |
125 EXPECT_TRUE(w1.visible()); | |
126 EXPECT_FALSE(w1.IsDrawn()); | |
127 | |
128 WindowPrivate(&w1).set_parent_drawn(true); | |
129 | |
130 TestWindow w11; | |
131 w11.SetVisible(true); | |
132 w1.AddChild(&w11); | |
133 EXPECT_TRUE(w11.visible()); | |
134 EXPECT_TRUE(w11.IsDrawn()); | |
135 | |
136 w1.RemoveChild(&w11); | |
137 EXPECT_TRUE(w11.visible()); | |
138 EXPECT_FALSE(w11.IsDrawn()); | |
139 } | |
140 | |
141 namespace { | |
142 MUS_DEFINE_WINDOW_PROPERTY_KEY(int, kIntKey, -2); | |
143 MUS_DEFINE_WINDOW_PROPERTY_KEY(const char*, kStringKey, "squeamish"); | |
144 } | |
145 | |
146 TEST_F(WindowTest, Property) { | |
147 TestWindow w; | |
148 | |
149 // Non-existent properties should return the default values. | |
150 EXPECT_EQ(-2, w.GetLocalProperty(kIntKey)); | |
151 EXPECT_EQ(std::string("squeamish"), w.GetLocalProperty(kStringKey)); | |
152 | |
153 // A set property value should be returned again (even if it's the default | |
154 // value). | |
155 w.SetLocalProperty(kIntKey, INT_MAX); | |
156 EXPECT_EQ(INT_MAX, w.GetLocalProperty(kIntKey)); | |
157 w.SetLocalProperty(kIntKey, -2); | |
158 EXPECT_EQ(-2, w.GetLocalProperty(kIntKey)); | |
159 w.SetLocalProperty(kIntKey, INT_MIN); | |
160 EXPECT_EQ(INT_MIN, w.GetLocalProperty(kIntKey)); | |
161 | |
162 w.SetLocalProperty(kStringKey, static_cast<const char*>(NULL)); | |
163 EXPECT_EQ(NULL, w.GetLocalProperty(kStringKey)); | |
164 w.SetLocalProperty(kStringKey, "squeamish"); | |
165 EXPECT_EQ(std::string("squeamish"), w.GetLocalProperty(kStringKey)); | |
166 w.SetLocalProperty(kStringKey, "ossifrage"); | |
167 EXPECT_EQ(std::string("ossifrage"), w.GetLocalProperty(kStringKey)); | |
168 | |
169 // ClearProperty should restore the default value. | |
170 w.ClearLocalProperty(kIntKey); | |
171 EXPECT_EQ(-2, w.GetLocalProperty(kIntKey)); | |
172 w.ClearLocalProperty(kStringKey); | |
173 EXPECT_EQ(std::string("squeamish"), w.GetLocalProperty(kStringKey)); | |
174 } | |
175 | |
176 namespace { | |
177 | |
178 class TestProperty { | |
179 public: | |
180 TestProperty() {} | |
181 virtual ~TestProperty() { last_deleted_ = this; } | |
182 static TestProperty* last_deleted() { return last_deleted_; } | |
183 | |
184 private: | |
185 static TestProperty* last_deleted_; | |
186 DISALLOW_COPY_AND_ASSIGN(TestProperty); | |
187 }; | |
188 | |
189 TestProperty* TestProperty::last_deleted_ = NULL; | |
190 | |
191 MUS_DEFINE_OWNED_WINDOW_PROPERTY_KEY(TestProperty, kOwnedKey, NULL); | |
192 | |
193 } // namespace | |
194 | |
195 TEST_F(WindowTest, OwnedProperty) { | |
196 TestProperty* p3 = NULL; | |
197 { | |
198 TestWindow w; | |
199 EXPECT_EQ(NULL, w.GetLocalProperty(kOwnedKey)); | |
200 TestProperty* p1 = new TestProperty(); | |
201 w.SetLocalProperty(kOwnedKey, p1); | |
202 EXPECT_EQ(p1, w.GetLocalProperty(kOwnedKey)); | |
203 EXPECT_EQ(NULL, TestProperty::last_deleted()); | |
204 | |
205 TestProperty* p2 = new TestProperty(); | |
206 w.SetLocalProperty(kOwnedKey, p2); | |
207 EXPECT_EQ(p2, w.GetLocalProperty(kOwnedKey)); | |
208 EXPECT_EQ(p1, TestProperty::last_deleted()); | |
209 | |
210 w.ClearLocalProperty(kOwnedKey); | |
211 EXPECT_EQ(NULL, w.GetLocalProperty(kOwnedKey)); | |
212 EXPECT_EQ(p2, TestProperty::last_deleted()); | |
213 | |
214 p3 = new TestProperty(); | |
215 w.SetLocalProperty(kOwnedKey, p3); | |
216 EXPECT_EQ(p3, w.GetLocalProperty(kOwnedKey)); | |
217 EXPECT_EQ(p2, TestProperty::last_deleted()); | |
218 } | |
219 | |
220 EXPECT_EQ(p3, TestProperty::last_deleted()); | |
221 } | |
222 | |
223 // WindowObserver -------------------------------------------------------- | |
224 | |
225 typedef testing::Test WindowObserverTest; | |
226 | |
227 bool TreeChangeParamsMatch(const WindowObserver::TreeChangeParams& lhs, | |
228 const WindowObserver::TreeChangeParams& rhs) { | |
229 return lhs.target == rhs.target && lhs.old_parent == rhs.old_parent && | |
230 lhs.new_parent == rhs.new_parent && lhs.receiver == rhs.receiver; | |
231 } | |
232 | |
233 class TreeChangeObserver : public WindowObserver { | |
234 public: | |
235 explicit TreeChangeObserver(Window* observee) : observee_(observee) { | |
236 observee_->AddObserver(this); | |
237 } | |
238 ~TreeChangeObserver() override { observee_->RemoveObserver(this); } | |
239 | |
240 void Reset() { received_params_.clear(); } | |
241 | |
242 const std::vector<TreeChangeParams>& received_params() { | |
243 return received_params_; | |
244 } | |
245 | |
246 private: | |
247 // Overridden from WindowObserver: | |
248 void OnTreeChanging(const TreeChangeParams& params) override { | |
249 received_params_.push_back(params); | |
250 } | |
251 void OnTreeChanged(const TreeChangeParams& params) override { | |
252 received_params_.push_back(params); | |
253 } | |
254 | |
255 Window* observee_; | |
256 std::vector<TreeChangeParams> received_params_; | |
257 | |
258 DISALLOW_COPY_AND_ASSIGN(TreeChangeObserver); | |
259 }; | |
260 | |
261 // Adds/Removes w11 to w1. | |
262 TEST_F(WindowObserverTest, TreeChange_SimpleAddRemove) { | |
263 TestWindow w1; | |
264 w1.set_local_id(1); | |
265 TreeChangeObserver o1(&w1); | |
266 EXPECT_TRUE(o1.received_params().empty()); | |
267 | |
268 TestWindow w11; | |
269 w11.set_local_id(11); | |
270 TreeChangeObserver o11(&w11); | |
271 EXPECT_TRUE(o11.received_params().empty()); | |
272 | |
273 // Add. | |
274 | |
275 w1.AddChild(&w11); | |
276 | |
277 EXPECT_EQ(2U, o1.received_params().size()); | |
278 WindowObserver::TreeChangeParams p1; | |
279 p1.target = &w11; | |
280 p1.receiver = &w1; | |
281 p1.old_parent = NULL; | |
282 p1.new_parent = &w1; | |
283 EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().back())); | |
284 | |
285 EXPECT_EQ(2U, o11.received_params().size()); | |
286 WindowObserver::TreeChangeParams p11 = p1; | |
287 p11.receiver = &w11; | |
288 EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front())); | |
289 EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().back())); | |
290 | |
291 o1.Reset(); | |
292 o11.Reset(); | |
293 EXPECT_TRUE(o1.received_params().empty()); | |
294 EXPECT_TRUE(o11.received_params().empty()); | |
295 | |
296 // Remove. | |
297 | |
298 w1.RemoveChild(&w11); | |
299 | |
300 EXPECT_EQ(2U, o1.received_params().size()); | |
301 p1.target = &w11; | |
302 p1.receiver = &w1; | |
303 p1.old_parent = &w1; | |
304 p1.new_parent = NULL; | |
305 EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().front())); | |
306 | |
307 EXPECT_EQ(2U, o11.received_params().size()); | |
308 p11 = p1; | |
309 p11.receiver = &w11; | |
310 EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front())); | |
311 EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().back())); | |
312 } | |
313 | |
314 // Creates these two trees: | |
315 // w1 | |
316 // +- w11 | |
317 // w111 | |
318 // +- w1111 | |
319 // +- w1112 | |
320 // Then adds/removes w111 from w11. | |
321 TEST_F(WindowObserverTest, TreeChange_NestedAddRemove) { | |
322 TestWindow w1, w11, w111, w1111, w1112; | |
323 | |
324 // Root tree. | |
325 w1.AddChild(&w11); | |
326 | |
327 // Tree to be attached. | |
328 w111.AddChild(&w1111); | |
329 w111.AddChild(&w1112); | |
330 | |
331 TreeChangeObserver o1(&w1), o11(&w11), o111(&w111), o1111(&w1111), | |
332 o1112(&w1112); | |
333 WindowObserver::TreeChangeParams p1, p11, p111, p1111, p1112; | |
334 | |
335 // Add. | |
336 | |
337 w11.AddChild(&w111); | |
338 | |
339 EXPECT_EQ(2U, o1.received_params().size()); | |
340 p1.target = &w111; | |
341 p1.receiver = &w1; | |
342 p1.old_parent = NULL; | |
343 p1.new_parent = &w11; | |
344 EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().back())); | |
345 | |
346 EXPECT_EQ(2U, o11.received_params().size()); | |
347 p11 = p1; | |
348 p11.receiver = &w11; | |
349 EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().back())); | |
350 | |
351 EXPECT_EQ(2U, o111.received_params().size()); | |
352 p111 = p11; | |
353 p111.receiver = &w111; | |
354 EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().front())); | |
355 EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().back())); | |
356 | |
357 EXPECT_EQ(2U, o1111.received_params().size()); | |
358 p1111 = p111; | |
359 p1111.receiver = &w1111; | |
360 EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().front())); | |
361 EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().back())); | |
362 | |
363 EXPECT_EQ(2U, o1112.received_params().size()); | |
364 p1112 = p111; | |
365 p1112.receiver = &w1112; | |
366 EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().front())); | |
367 EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().back())); | |
368 | |
369 // Remove. | |
370 o1.Reset(); | |
371 o11.Reset(); | |
372 o111.Reset(); | |
373 o1111.Reset(); | |
374 o1112.Reset(); | |
375 EXPECT_TRUE(o1.received_params().empty()); | |
376 EXPECT_TRUE(o11.received_params().empty()); | |
377 EXPECT_TRUE(o111.received_params().empty()); | |
378 EXPECT_TRUE(o1111.received_params().empty()); | |
379 EXPECT_TRUE(o1112.received_params().empty()); | |
380 | |
381 w11.RemoveChild(&w111); | |
382 | |
383 EXPECT_EQ(2U, o1.received_params().size()); | |
384 p1.target = &w111; | |
385 p1.receiver = &w1; | |
386 p1.old_parent = &w11; | |
387 p1.new_parent = NULL; | |
388 EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().front())); | |
389 | |
390 EXPECT_EQ(2U, o11.received_params().size()); | |
391 p11 = p1; | |
392 p11.receiver = &w11; | |
393 EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front())); | |
394 | |
395 EXPECT_EQ(2U, o111.received_params().size()); | |
396 p111 = p11; | |
397 p111.receiver = &w111; | |
398 EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().front())); | |
399 EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().back())); | |
400 | |
401 EXPECT_EQ(2U, o1111.received_params().size()); | |
402 p1111 = p111; | |
403 p1111.receiver = &w1111; | |
404 EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().front())); | |
405 EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().back())); | |
406 | |
407 EXPECT_EQ(2U, o1112.received_params().size()); | |
408 p1112 = p111; | |
409 p1112.receiver = &w1112; | |
410 EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().front())); | |
411 EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().back())); | |
412 } | |
413 | |
414 TEST_F(WindowObserverTest, TreeChange_Reparent) { | |
415 TestWindow w1, w11, w12, w111; | |
416 w1.AddChild(&w11); | |
417 w1.AddChild(&w12); | |
418 w11.AddChild(&w111); | |
419 | |
420 TreeChangeObserver o1(&w1), o11(&w11), o12(&w12), o111(&w111); | |
421 | |
422 // Reparent. | |
423 w12.AddChild(&w111); | |
424 | |
425 // w1 (root) should see both changing and changed notifications. | |
426 EXPECT_EQ(4U, o1.received_params().size()); | |
427 WindowObserver::TreeChangeParams p1; | |
428 p1.target = &w111; | |
429 p1.receiver = &w1; | |
430 p1.old_parent = &w11; | |
431 p1.new_parent = &w12; | |
432 EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().front())); | |
433 EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().back())); | |
434 | |
435 // w11 should see changing notifications. | |
436 EXPECT_EQ(2U, o11.received_params().size()); | |
437 WindowObserver::TreeChangeParams p11; | |
438 p11 = p1; | |
439 p11.receiver = &w11; | |
440 EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front())); | |
441 | |
442 // w12 should see changed notifications. | |
443 EXPECT_EQ(2U, o12.received_params().size()); | |
444 WindowObserver::TreeChangeParams p12; | |
445 p12 = p1; | |
446 p12.receiver = &w12; | |
447 EXPECT_TRUE(TreeChangeParamsMatch(p12, o12.received_params().back())); | |
448 | |
449 // w111 should see both changing and changed notifications. | |
450 EXPECT_EQ(2U, o111.received_params().size()); | |
451 WindowObserver::TreeChangeParams p111; | |
452 p111 = p1; | |
453 p111.receiver = &w111; | |
454 EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().front())); | |
455 EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().back())); | |
456 } | |
457 | |
458 namespace { | |
459 | |
460 class OrderChangeObserver : public WindowObserver { | |
461 public: | |
462 struct Change { | |
463 Window* window; | |
464 Window* relative_window; | |
465 mojom::OrderDirection direction; | |
466 }; | |
467 typedef std::vector<Change> Changes; | |
468 | |
469 explicit OrderChangeObserver(Window* observee) : observee_(observee) { | |
470 observee_->AddObserver(this); | |
471 } | |
472 ~OrderChangeObserver() override { observee_->RemoveObserver(this); } | |
473 | |
474 Changes GetAndClearChanges() { | |
475 Changes changes; | |
476 changes_.swap(changes); | |
477 return changes; | |
478 } | |
479 | |
480 private: | |
481 // Overridden from WindowObserver: | |
482 void OnWindowReordering(Window* window, | |
483 Window* relative_window, | |
484 mojom::OrderDirection direction) override { | |
485 OnWindowReordered(window, relative_window, direction); | |
486 } | |
487 | |
488 void OnWindowReordered(Window* window, | |
489 Window* relative_window, | |
490 mojom::OrderDirection direction) override { | |
491 Change change; | |
492 change.window = window; | |
493 change.relative_window = relative_window; | |
494 change.direction = direction; | |
495 changes_.push_back(change); | |
496 } | |
497 | |
498 Window* observee_; | |
499 Changes changes_; | |
500 | |
501 DISALLOW_COPY_AND_ASSIGN(OrderChangeObserver); | |
502 }; | |
503 | |
504 } // namespace | |
505 | |
506 TEST_F(WindowObserverTest, Order) { | |
507 TestWindow w1, w11, w12, w13; | |
508 w1.AddChild(&w11); | |
509 w1.AddChild(&w12); | |
510 w1.AddChild(&w13); | |
511 | |
512 // Order: w11, w12, w13 | |
513 EXPECT_EQ(3U, w1.children().size()); | |
514 EXPECT_EQ(&w11, w1.children().front()); | |
515 EXPECT_EQ(&w13, w1.children().back()); | |
516 | |
517 { | |
518 OrderChangeObserver observer(&w11); | |
519 | |
520 // Move w11 to front. | |
521 // Resulting order: w12, w13, w11 | |
522 w11.MoveToFront(); | |
523 EXPECT_EQ(&w12, w1.children().front()); | |
524 EXPECT_EQ(&w11, w1.children().back()); | |
525 | |
526 OrderChangeObserver::Changes changes = observer.GetAndClearChanges(); | |
527 ASSERT_EQ(2U, changes.size()); | |
528 EXPECT_EQ(&w11, changes[0].window); | |
529 EXPECT_EQ(&w13, changes[0].relative_window); | |
530 EXPECT_EQ(mojom::OrderDirection::ABOVE, changes[0].direction); | |
531 | |
532 EXPECT_EQ(&w11, changes[1].window); | |
533 EXPECT_EQ(&w13, changes[1].relative_window); | |
534 EXPECT_EQ(mojom::OrderDirection::ABOVE, changes[1].direction); | |
535 } | |
536 | |
537 { | |
538 OrderChangeObserver observer(&w11); | |
539 | |
540 // Move w11 to back. | |
541 // Resulting order: w11, w12, w13 | |
542 w11.MoveToBack(); | |
543 EXPECT_EQ(&w11, w1.children().front()); | |
544 EXPECT_EQ(&w13, w1.children().back()); | |
545 | |
546 OrderChangeObserver::Changes changes = observer.GetAndClearChanges(); | |
547 ASSERT_EQ(2U, changes.size()); | |
548 EXPECT_EQ(&w11, changes[0].window); | |
549 EXPECT_EQ(&w12, changes[0].relative_window); | |
550 EXPECT_EQ(mojom::OrderDirection::BELOW, changes[0].direction); | |
551 | |
552 EXPECT_EQ(&w11, changes[1].window); | |
553 EXPECT_EQ(&w12, changes[1].relative_window); | |
554 EXPECT_EQ(mojom::OrderDirection::BELOW, changes[1].direction); | |
555 } | |
556 | |
557 { | |
558 OrderChangeObserver observer(&w11); | |
559 | |
560 // Move w11 above w12. | |
561 // Resulting order: w12. w11, w13 | |
562 w11.Reorder(&w12, mojom::OrderDirection::ABOVE); | |
563 EXPECT_EQ(&w12, w1.children().front()); | |
564 EXPECT_EQ(&w13, w1.children().back()); | |
565 | |
566 OrderChangeObserver::Changes changes = observer.GetAndClearChanges(); | |
567 ASSERT_EQ(2U, changes.size()); | |
568 EXPECT_EQ(&w11, changes[0].window); | |
569 EXPECT_EQ(&w12, changes[0].relative_window); | |
570 EXPECT_EQ(mojom::OrderDirection::ABOVE, changes[0].direction); | |
571 | |
572 EXPECT_EQ(&w11, changes[1].window); | |
573 EXPECT_EQ(&w12, changes[1].relative_window); | |
574 EXPECT_EQ(mojom::OrderDirection::ABOVE, changes[1].direction); | |
575 } | |
576 | |
577 { | |
578 OrderChangeObserver observer(&w11); | |
579 | |
580 // Move w11 below w12. | |
581 // Resulting order: w11, w12, w13 | |
582 w11.Reorder(&w12, mojom::OrderDirection::BELOW); | |
583 EXPECT_EQ(&w11, w1.children().front()); | |
584 EXPECT_EQ(&w13, w1.children().back()); | |
585 | |
586 OrderChangeObserver::Changes changes = observer.GetAndClearChanges(); | |
587 ASSERT_EQ(2U, changes.size()); | |
588 EXPECT_EQ(&w11, changes[0].window); | |
589 EXPECT_EQ(&w12, changes[0].relative_window); | |
590 EXPECT_EQ(mojom::OrderDirection::BELOW, changes[0].direction); | |
591 | |
592 EXPECT_EQ(&w11, changes[1].window); | |
593 EXPECT_EQ(&w12, changes[1].relative_window); | |
594 EXPECT_EQ(mojom::OrderDirection::BELOW, changes[1].direction); | |
595 } | |
596 } | |
597 | |
598 namespace { | |
599 | |
600 typedef std::vector<std::string> Changes; | |
601 | |
602 std::string RectToString(const gfx::Rect& rect) { | |
603 return base::StringPrintf("%d,%d %dx%d", rect.x(), rect.y(), rect.width(), | |
604 rect.height()); | |
605 } | |
606 | |
607 class BoundsChangeObserver : public WindowObserver { | |
608 public: | |
609 explicit BoundsChangeObserver(Window* window) : window_(window) { | |
610 window_->AddObserver(this); | |
611 } | |
612 ~BoundsChangeObserver() override { window_->RemoveObserver(this); } | |
613 | |
614 Changes GetAndClearChanges() { | |
615 Changes changes; | |
616 changes.swap(changes_); | |
617 return changes; | |
618 } | |
619 | |
620 private: | |
621 // Overridden from WindowObserver: | |
622 void OnWindowBoundsChanging(Window* window, | |
623 const gfx::Rect& old_bounds, | |
624 const gfx::Rect& new_bounds) override { | |
625 changes_.push_back(base::StringPrintf( | |
626 "window=%d old_bounds=%s new_bounds=%s phase=changing", | |
627 window->local_id(), RectToString(old_bounds).c_str(), | |
628 RectToString(new_bounds).c_str())); | |
629 } | |
630 void OnWindowBoundsChanged(Window* window, | |
631 const gfx::Rect& old_bounds, | |
632 const gfx::Rect& new_bounds) override { | |
633 changes_.push_back(base::StringPrintf( | |
634 "window=%d old_bounds=%s new_bounds=%s phase=changed", | |
635 window->local_id(), RectToString(old_bounds).c_str(), | |
636 RectToString(new_bounds).c_str())); | |
637 } | |
638 | |
639 Window* window_; | |
640 Changes changes_; | |
641 | |
642 DISALLOW_COPY_AND_ASSIGN(BoundsChangeObserver); | |
643 }; | |
644 | |
645 } // namespace | |
646 | |
647 TEST_F(WindowObserverTest, SetBounds) { | |
648 TestWindow w1; | |
649 w1.set_local_id(1); | |
650 { | |
651 BoundsChangeObserver observer(&w1); | |
652 w1.SetBounds(gfx::Rect(0, 0, 100, 100)); | |
653 | |
654 Changes changes = observer.GetAndClearChanges(); | |
655 ASSERT_EQ(2U, changes.size()); | |
656 EXPECT_EQ( | |
657 "window=1 old_bounds=0,0 0x0 new_bounds=0,0 100x100 phase=changing", | |
658 changes[0]); | |
659 EXPECT_EQ( | |
660 "window=1 old_bounds=0,0 0x0 new_bounds=0,0 100x100 phase=changed", | |
661 changes[1]); | |
662 } | |
663 } | |
664 | |
665 namespace { | |
666 | |
667 class VisibilityChangeObserver : public WindowObserver { | |
668 public: | |
669 explicit VisibilityChangeObserver(Window* window) : window_(window) { | |
670 window_->AddObserver(this); | |
671 } | |
672 ~VisibilityChangeObserver() override { window_->RemoveObserver(this); } | |
673 | |
674 Changes GetAndClearChanges() { | |
675 Changes changes; | |
676 changes.swap(changes_); | |
677 return changes; | |
678 } | |
679 | |
680 private: | |
681 // Overridden from WindowObserver: | |
682 void OnWindowVisibilityChanging(Window* window, bool visible) override { | |
683 changes_.push_back( | |
684 base::StringPrintf("window=%d phase=changing visibility=%s", | |
685 window->local_id(), visible ? "true" : "false")); | |
686 } | |
687 void OnChildWindowVisibilityChanged(Window* window, bool visible) override { | |
688 changes_.push_back( | |
689 base::StringPrintf("window=%d phase=child-changed visibility=%s", | |
690 window->local_id(), visible ? "true" : "false")); | |
691 } | |
692 void OnWindowVisibilityChanged(Window* window, bool visible) override { | |
693 changes_.push_back( | |
694 base::StringPrintf("window=%d phase=changed visibility=%s", | |
695 window->local_id(), visible ? "true" : "false")); | |
696 } | |
697 | |
698 Window* window_; | |
699 Changes changes_; | |
700 | |
701 DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver); | |
702 }; | |
703 | |
704 } // namespace | |
705 | |
706 TEST_F(WindowObserverTest, SetVisible) { | |
707 TestWindow w1; | |
708 EXPECT_FALSE(w1.visible()); | |
709 w1.set_local_id(1); | |
710 w1.SetVisible(true); | |
711 EXPECT_TRUE(w1.visible()); | |
712 { | |
713 // Change visibility from true to false and make sure we get notifications. | |
714 VisibilityChangeObserver observer(&w1); | |
715 w1.SetVisible(false); | |
716 | |
717 Changes changes = observer.GetAndClearChanges(); | |
718 ASSERT_EQ(2U, changes.size()); | |
719 EXPECT_EQ("window=1 phase=changing visibility=false", changes[0]); | |
720 EXPECT_EQ("window=1 phase=changed visibility=false", changes[1]); | |
721 } | |
722 { | |
723 // Set visible to existing value and verify no notifications. | |
724 VisibilityChangeObserver observer(&w1); | |
725 w1.SetVisible(false); | |
726 EXPECT_TRUE(observer.GetAndClearChanges().empty()); | |
727 } | |
728 } | |
729 | |
730 TEST_F(WindowObserverTest, SetVisibleParent) { | |
731 TestWindow parent; | |
732 parent.SetVisible(true); | |
733 parent.set_local_id(1); | |
734 TestWindow child; | |
735 child.SetVisible(true); | |
736 child.set_local_id(2); | |
737 parent.AddChild(&child); | |
738 EXPECT_TRUE(parent.visible()); | |
739 EXPECT_TRUE(child.visible()); | |
740 { | |
741 // Change visibility from true to false and make sure we get notifications | |
742 // on the parent. | |
743 VisibilityChangeObserver observer(&parent); | |
744 child.SetVisible(false); | |
745 | |
746 Changes changes = observer.GetAndClearChanges(); | |
747 ASSERT_EQ(2U, changes.size()); | |
748 EXPECT_EQ("window=2 phase=child-changed visibility=false", changes[0]); | |
749 EXPECT_EQ("window=2 phase=changed visibility=false", changes[1]); | |
750 } | |
751 } | |
752 | |
753 TEST_F(WindowObserverTest, SetVisibleChild) { | |
754 TestWindow parent; | |
755 parent.SetVisible(true); | |
756 parent.set_local_id(1); | |
757 TestWindow child; | |
758 child.SetVisible(true); | |
759 child.set_local_id(2); | |
760 parent.AddChild(&child); | |
761 EXPECT_TRUE(parent.visible()); | |
762 EXPECT_TRUE(child.visible()); | |
763 { | |
764 // Change visibility from true to false and make sure we get notifications | |
765 // on the child. | |
766 VisibilityChangeObserver observer(&child); | |
767 parent.SetVisible(false); | |
768 | |
769 Changes changes = observer.GetAndClearChanges(); | |
770 ASSERT_EQ(1U, changes.size()); | |
771 EXPECT_EQ("window=1 phase=changed visibility=false", changes[0]); | |
772 } | |
773 } | |
774 | |
775 namespace { | |
776 | |
777 class OpacityChangeObserver : public WindowObserver { | |
778 public: | |
779 explicit OpacityChangeObserver(Window* window) : window_(window) { | |
780 window_->AddObserver(this); | |
781 } | |
782 ~OpacityChangeObserver() override { window_->RemoveObserver(this); } | |
783 | |
784 Changes GetAndClearChanges() { | |
785 Changes changes; | |
786 changes.swap(changes_); | |
787 return changes; | |
788 } | |
789 | |
790 private: | |
791 // WindowObserver: | |
792 void OnWindowOpacityChanged(Window* window, | |
793 float old_opacity, | |
794 float new_opacity) override { | |
795 changes_.push_back( | |
796 base::StringPrintf("window=%d old_opacity=%.2f new_opacity=%.2f", | |
797 window->local_id(), old_opacity, new_opacity)); | |
798 } | |
799 | |
800 Window* window_; | |
801 Changes changes_; | |
802 | |
803 DISALLOW_COPY_AND_ASSIGN(OpacityChangeObserver); | |
804 }; | |
805 | |
806 } // namespace | |
807 | |
808 // Tests that WindowObserver is only notified when opacity changes. | |
809 TEST_F(WindowObserverTest, SetOpacity) { | |
810 TestWindow w1; | |
811 w1.set_local_id(1); | |
812 EXPECT_FLOAT_EQ(1.0f, w1.opacity()); | |
813 | |
814 // Changing the opacity should trigger a notification. | |
815 OpacityChangeObserver observer(&w1); | |
816 w1.SetOpacity(0.5f); | |
817 EXPECT_FLOAT_EQ(0.5f, w1.opacity()); | |
818 Changes changes = observer.GetAndClearChanges(); | |
819 ASSERT_EQ(1u, changes.size()); | |
820 EXPECT_EQ("window=1 old_opacity=1.00 new_opacity=0.50", changes[0]); | |
821 | |
822 // Setting to the same opacity should be rejected, no notification. | |
823 w1.SetOpacity(0.5f); | |
824 EXPECT_FLOAT_EQ(0.5f, w1.opacity()); | |
825 changes = observer.GetAndClearChanges(); | |
826 EXPECT_TRUE(changes.empty()); | |
827 | |
828 // Alternate sources of opacity changes should trigger a notification. | |
829 WindowPrivate(&w1).LocalSetOpacity(1.0f); | |
830 EXPECT_FLOAT_EQ(1.0f, w1.opacity()); | |
831 changes = observer.GetAndClearChanges(); | |
832 ASSERT_EQ(1u, changes.size()); | |
833 EXPECT_EQ("window=1 old_opacity=0.50 new_opacity=1.00", changes[0]); | |
834 } | |
835 | |
836 namespace { | |
837 | |
838 class SharedPropertyChangeObserver : public WindowObserver { | |
839 public: | |
840 explicit SharedPropertyChangeObserver(Window* window) : window_(window) { | |
841 window_->AddObserver(this); | |
842 } | |
843 ~SharedPropertyChangeObserver() override { window_->RemoveObserver(this); } | |
844 | |
845 Changes GetAndClearChanges() { | |
846 Changes changes; | |
847 changes.swap(changes_); | |
848 return changes; | |
849 } | |
850 | |
851 private: | |
852 // Overridden from WindowObserver: | |
853 void OnWindowSharedPropertyChanged( | |
854 Window* window, | |
855 const std::string& name, | |
856 const std::vector<uint8_t>* old_data, | |
857 const std::vector<uint8_t>* new_data) override { | |
858 changes_.push_back(base::StringPrintf( | |
859 "window=%d shared property changed key=%s old_value=%s new_value=%s", | |
860 window->local_id(), name.c_str(), VectorToString(old_data).c_str(), | |
861 VectorToString(new_data).c_str())); | |
862 } | |
863 | |
864 std::string VectorToString(const std::vector<uint8_t>* data) { | |
865 if (!data) | |
866 return "NULL"; | |
867 gfx::Size size = mojo::ConvertTo<gfx::Size>(*data); | |
868 return base::StringPrintf("%d,%d", size.width(), size.height()); | |
869 } | |
870 | |
871 Window* window_; | |
872 Changes changes_; | |
873 | |
874 DISALLOW_COPY_AND_ASSIGN(SharedPropertyChangeObserver); | |
875 }; | |
876 | |
877 } // namespace | |
878 | |
879 TEST_F(WindowObserverTest, SetSharedProperty) { | |
880 TestWindow w1; | |
881 w1.set_local_id(1); | |
882 gfx::Size size(100, 100); | |
883 | |
884 { | |
885 // Change visibility from true to false and make sure we get notifications. | |
886 SharedPropertyChangeObserver observer(&w1); | |
887 w1.SetSharedProperty<gfx::Size>("size", size); | |
888 Changes changes = observer.GetAndClearChanges(); | |
889 ASSERT_EQ(1U, changes.size()); | |
890 EXPECT_EQ( | |
891 "window=1 shared property changed key=size old_value=NULL " | |
892 "new_value=100,100", | |
893 changes[0]); | |
894 EXPECT_EQ(1U, w1.shared_properties().size()); | |
895 EXPECT_EQ(w1.GetSharedProperty<gfx::Size>("size"), size); | |
896 EXPECT_TRUE(w1.HasSharedProperty("size")); | |
897 } | |
898 { | |
899 // Set visible to existing value and verify no notifications. | |
900 SharedPropertyChangeObserver observer(&w1); | |
901 w1.SetSharedProperty<gfx::Size>("size", size); | |
902 EXPECT_TRUE(observer.GetAndClearChanges().empty()); | |
903 EXPECT_EQ(1U, w1.shared_properties().size()); | |
904 EXPECT_TRUE(w1.HasSharedProperty("size")); | |
905 } | |
906 { | |
907 // Clear the shared property. | |
908 // Change visibility from true to false and make sure we get notifications. | |
909 SharedPropertyChangeObserver observer(&w1); | |
910 w1.ClearSharedProperty("size"); | |
911 Changes changes = observer.GetAndClearChanges(); | |
912 ASSERT_EQ(1U, changes.size()); | |
913 EXPECT_EQ( | |
914 "window=1 shared property changed key=size old_value=100,100 " | |
915 "new_value=NULL", | |
916 changes[0]); | |
917 EXPECT_EQ(0U, w1.shared_properties().size()); | |
918 EXPECT_FALSE(w1.HasSharedProperty("size")); | |
919 } | |
920 { | |
921 // Clearing a non-existent property shouldn't update us. | |
922 SharedPropertyChangeObserver observer(&w1); | |
923 w1.ClearSharedProperty("size"); | |
924 EXPECT_TRUE(observer.GetAndClearChanges().empty()); | |
925 EXPECT_EQ(0U, w1.shared_properties().size()); | |
926 EXPECT_FALSE(w1.HasSharedProperty("size")); | |
927 } | |
928 } | |
929 | |
930 namespace { | |
931 | |
932 typedef std::pair<const void*, intptr_t> PropertyChangeInfo; | |
933 | |
934 class LocalPropertyChangeObserver : public WindowObserver { | |
935 public: | |
936 explicit LocalPropertyChangeObserver(Window* window) | |
937 : window_(window), property_key_(nullptr), old_property_value_(-1) { | |
938 window_->AddObserver(this); | |
939 } | |
940 ~LocalPropertyChangeObserver() override { window_->RemoveObserver(this); } | |
941 | |
942 PropertyChangeInfo PropertyChangeInfoAndClear() { | |
943 PropertyChangeInfo result(property_key_, old_property_value_); | |
944 property_key_ = NULL; | |
945 old_property_value_ = -3; | |
946 return result; | |
947 } | |
948 | |
949 private: | |
950 void OnWindowLocalPropertyChanged(Window* window, | |
951 const void* key, | |
952 intptr_t old) override { | |
953 property_key_ = key; | |
954 old_property_value_ = old; | |
955 } | |
956 | |
957 Window* window_; | |
958 const void* property_key_; | |
959 intptr_t old_property_value_; | |
960 | |
961 DISALLOW_COPY_AND_ASSIGN(LocalPropertyChangeObserver); | |
962 }; | |
963 | |
964 } // namespace | |
965 | |
966 TEST_F(WindowObserverTest, LocalPropertyChanged) { | |
967 TestWindow w1; | |
968 LocalPropertyChangeObserver o(&w1); | |
969 | |
970 static const WindowProperty<int> prop = {-2}; | |
971 | |
972 w1.SetLocalProperty(&prop, 1); | |
973 EXPECT_EQ(PropertyChangeInfo(&prop, -2), o.PropertyChangeInfoAndClear()); | |
974 w1.SetLocalProperty(&prop, -2); | |
975 EXPECT_EQ(PropertyChangeInfo(&prop, 1), o.PropertyChangeInfoAndClear()); | |
976 w1.SetLocalProperty(&prop, 3); | |
977 EXPECT_EQ(PropertyChangeInfo(&prop, -2), o.PropertyChangeInfoAndClear()); | |
978 w1.ClearLocalProperty(&prop); | |
979 EXPECT_EQ(PropertyChangeInfo(&prop, 3), o.PropertyChangeInfoAndClear()); | |
980 | |
981 // Sanity check to see if |PropertyChangeInfoAndClear| really clears. | |
982 EXPECT_EQ(PropertyChangeInfo(reinterpret_cast<const void*>(NULL), -3), | |
983 o.PropertyChangeInfoAndClear()); | |
984 } | |
985 | |
986 TEST_F(WindowTest, RemoveTransientWindow) { | |
987 std::unique_ptr<TestWindow> w1(CreateTestWindow(nullptr)); | |
988 std::unique_ptr<TestWindow> w11(CreateTestWindow(w1.get())); | |
989 TestWindow* w12 = CreateTestWindow(w1.get()); | |
990 EXPECT_EQ(2u, w1->children().size()); | |
991 // w12's lifetime is now tied to w11. | |
992 w11->AddTransientWindow(w12); | |
993 w11.reset(); | |
994 EXPECT_EQ(0u, w1->children().size()); | |
995 } | |
996 | |
997 TEST_F(WindowTest, TransientWindow) { | |
998 std::unique_ptr<TestWindow> parent(CreateTestWindow(nullptr)); | |
999 std::unique_ptr<TestWindow> w1(CreateTestWindow(parent.get())); | |
1000 std::unique_ptr<TestWindow> w3(CreateTestWindow(parent.get())); | |
1001 | |
1002 Window* w2 = CreateTestWindow(parent.get()); | |
1003 EXPECT_EQ(w2, parent->children().back()); | |
1004 ASSERT_EQ(3u, parent->children().size()); | |
1005 | |
1006 w1->AddTransientWindow(w2); | |
1007 // Stack w1 at the top (end). This should force w2 to be last (on top of w1). | |
1008 w1->MoveToFront(); | |
1009 ASSERT_EQ(3u, parent->children().size()); | |
1010 EXPECT_EQ(w2, parent->children().back()); | |
1011 | |
1012 // Destroy w1, which should also destroy w3 (since it's a transient child).A | |
1013 w1.reset(); | |
1014 w2 = nullptr; | |
1015 ASSERT_EQ(1u, parent->children().size()); | |
1016 EXPECT_EQ(w3.get(), parent->children()[0]); | |
1017 } | |
1018 | |
1019 // Tests that transient windows are stacked as a unit when using order above. | |
1020 TEST_F(WindowTest, TransientWindowsGroupAbove) { | |
1021 std::unique_ptr<TestWindow> parent(CreateTestWindow(0, nullptr)); | |
1022 std::unique_ptr<TestWindow> w1(CreateTestWindow(1, parent.get())); | |
1023 | |
1024 TestWindow* w11 = CreateTestWindow(11, parent.get()); | |
1025 std::unique_ptr<TestWindow> w2(CreateTestWindow(2, parent.get())); | |
1026 | |
1027 TestWindow* w21 = CreateTestWindow(21, parent.get()); | |
1028 TestWindow* w211 = CreateTestWindow(211, parent.get()); | |
1029 TestWindow* w212 = CreateTestWindow(212, parent.get()); | |
1030 TestWindow* w213 = CreateTestWindow(213, parent.get()); | |
1031 TestWindow* w22 = CreateTestWindow(22, parent.get()); | |
1032 ASSERT_EQ(8u, parent->children().size()); | |
1033 | |
1034 // w11 is now owned by w1. | |
1035 w1->AddTransientWindow(w11); | |
1036 // w21 is now owned by w2. | |
1037 w2->AddTransientWindow(w21); | |
1038 // w22 is now owned by w2. | |
1039 w2->AddTransientWindow(w22); | |
1040 // w211 is now owned by w21. | |
1041 w21->AddTransientWindow(w211); | |
1042 // w212 is now owned by w21. | |
1043 w21->AddTransientWindow(w212); | |
1044 // w213 is now owned by w21. | |
1045 w21->AddTransientWindow(w213); | |
1046 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get())); | |
1047 | |
1048 // Stack w1 at the top (end), this should force w11 to be last (on top of w1). | |
1049 w1->MoveToFront(); | |
1050 EXPECT_EQ(w11, parent->children().back()); | |
1051 EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get())); | |
1052 | |
1053 // This tests that the order in children_ array rather than in | |
1054 // transient_children_ array is used when reinserting transient children. | |
1055 // If transient_children_ array was used '22' would be following '21'. | |
1056 w2->MoveToFront(); | |
1057 EXPECT_EQ(w22, parent->children().back()); | |
1058 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get())); | |
1059 | |
1060 w11->Reorder(w2.get(), mojom::OrderDirection::ABOVE); | |
1061 EXPECT_EQ(w11, parent->children().back()); | |
1062 EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get())); | |
1063 | |
1064 w21->Reorder(w1.get(), mojom::OrderDirection::ABOVE); | |
1065 EXPECT_EQ(w22, parent->children().back()); | |
1066 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get())); | |
1067 | |
1068 w21->Reorder(w22, mojom::OrderDirection::ABOVE); | |
1069 EXPECT_EQ(w213, parent->children().back()); | |
1070 EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent.get())); | |
1071 | |
1072 w11->Reorder(w21, mojom::OrderDirection::ABOVE); | |
1073 EXPECT_EQ(w11, parent->children().back()); | |
1074 EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent.get())); | |
1075 | |
1076 w213->Reorder(w21, mojom::OrderDirection::ABOVE); | |
1077 EXPECT_EQ(w11, parent->children().back()); | |
1078 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get())); | |
1079 | |
1080 // No change when stacking a transient parent above its transient child. | |
1081 w21->Reorder(w211, mojom::OrderDirection::ABOVE); | |
1082 EXPECT_EQ(w11, parent->children().back()); | |
1083 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get())); | |
1084 | |
1085 // This tests that the order in children_ array rather than in | |
1086 // transient_children_ array is used when reinserting transient children. | |
1087 // If transient_children_ array was used '22' would be following '21'. | |
1088 w2->Reorder(w1.get(), mojom::OrderDirection::ABOVE); | |
1089 EXPECT_EQ(w212, parent->children().back()); | |
1090 EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent.get())); | |
1091 | |
1092 w11->Reorder(w213, mojom::OrderDirection::ABOVE); | |
1093 EXPECT_EQ(w11, parent->children().back()); | |
1094 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get())); | |
1095 } | |
1096 | |
1097 // Tests that transient children are stacked as a unit when using order below. | |
1098 TEST_F(WindowTest, TransientWindowsGroupBelow) { | |
1099 std::unique_ptr<TestWindow> parent(CreateTestWindow(0, nullptr)); | |
1100 std::unique_ptr<TestWindow> w1(CreateTestWindow(1, parent.get())); | |
1101 | |
1102 TestWindow* w11 = CreateTestWindow(11, parent.get()); | |
1103 std::unique_ptr<TestWindow> w2(CreateTestWindow(2, parent.get())); | |
1104 | |
1105 TestWindow* w21 = CreateTestWindow(21, parent.get()); | |
1106 TestWindow* w211 = CreateTestWindow(211, parent.get()); | |
1107 TestWindow* w212 = CreateTestWindow(212, parent.get()); | |
1108 TestWindow* w213 = CreateTestWindow(213, parent.get()); | |
1109 TestWindow* w22 = CreateTestWindow(22, parent.get()); | |
1110 ASSERT_EQ(8u, parent->children().size()); | |
1111 | |
1112 // w11 is now owned by w1. | |
1113 w1->AddTransientWindow(w11); | |
1114 // w21 is now owned by w2. | |
1115 w2->AddTransientWindow(w21); | |
1116 // w22 is now owned by w2. | |
1117 w2->AddTransientWindow(w22); | |
1118 // w211 is now owned by w21. | |
1119 w21->AddTransientWindow(w211); | |
1120 // w212 is now owned by w21. | |
1121 w21->AddTransientWindow(w212); | |
1122 // w213 is now owned by w21. | |
1123 w21->AddTransientWindow(w213); | |
1124 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get())); | |
1125 | |
1126 // Stack w2 at the bottom, this should force w11 to be last (on top of w1). | |
1127 // This also tests that the order in children_ array rather than in | |
1128 // transient_children_ array is used when reinserting transient children. | |
1129 // If transient_children_ array was used '22' would be following '21'. | |
1130 w2->MoveToBack(); | |
1131 EXPECT_EQ(w11, parent->children().back()); | |
1132 EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get())); | |
1133 | |
1134 w1->MoveToBack(); | |
1135 EXPECT_EQ(w22, parent->children().back()); | |
1136 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get())); | |
1137 | |
1138 w21->Reorder(w1.get(), mojom::OrderDirection::BELOW); | |
1139 EXPECT_EQ(w11, parent->children().back()); | |
1140 EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get())); | |
1141 | |
1142 w11->Reorder(w2.get(), mojom::OrderDirection::BELOW); | |
1143 EXPECT_EQ(w22, parent->children().back()); | |
1144 EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get())); | |
1145 | |
1146 w22->Reorder(w21, mojom::OrderDirection::BELOW); | |
1147 EXPECT_EQ(w213, parent->children().back()); | |
1148 EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent.get())); | |
1149 | |
1150 w21->Reorder(w11, mojom::OrderDirection::BELOW); | |
1151 EXPECT_EQ(w11, parent->children().back()); | |
1152 EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent.get())); | |
1153 | |
1154 w213->Reorder(w211, mojom::OrderDirection::BELOW); | |
1155 EXPECT_EQ(w11, parent->children().back()); | |
1156 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get())); | |
1157 | |
1158 // No change when stacking a transient parent below its transient child. | |
1159 w21->Reorder(w211, mojom::OrderDirection::BELOW); | |
1160 EXPECT_EQ(w11, parent->children().back()); | |
1161 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get())); | |
1162 | |
1163 w1->Reorder(w2.get(), mojom::OrderDirection::BELOW); | |
1164 EXPECT_EQ(w212, parent->children().back()); | |
1165 EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent.get())); | |
1166 | |
1167 w213->Reorder(w11, mojom::OrderDirection::BELOW); | |
1168 EXPECT_EQ(w11, parent->children().back()); | |
1169 EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get())); | |
1170 } | |
1171 | |
1172 // Tests that windows are restacked properly after a call to | |
1173 // AddTransientWindow() or RemoveTransientWindow). | |
1174 TEST_F(WindowTest, RestackUponAddOrRemoveTransientWindow) { | |
1175 std::unique_ptr<TestWindow> parent(CreateTestWindow(0, nullptr)); | |
1176 std::unique_ptr<TestWindow> windows[4]; | |
1177 for (int i = 0; i < 4; i++) | |
1178 windows[i].reset(CreateTestWindow(i, parent.get())); | |
1179 | |
1180 EXPECT_EQ("0 1 2 3", ChildWindowIDsAsString(parent.get())); | |
1181 | |
1182 windows[0]->AddTransientWindow(windows[2].get()); | |
1183 EXPECT_EQ("0 2 1 3", ChildWindowIDsAsString(parent.get())); | |
1184 | |
1185 windows[0]->AddTransientWindow(windows[3].get()); | |
1186 EXPECT_EQ("0 2 3 1", ChildWindowIDsAsString(parent.get())); | |
1187 | |
1188 windows[0]->RemoveTransientWindow(windows[2].get()); | |
1189 EXPECT_EQ("0 3 2 1", ChildWindowIDsAsString(parent.get())); | |
1190 | |
1191 windows[0]->RemoveTransientWindow(windows[3].get()); | |
1192 EXPECT_EQ("0 3 2 1", ChildWindowIDsAsString(parent.get())); | |
1193 } | |
1194 | |
1195 // Tests that transient windows are stacked properly when created. | |
1196 TEST_F(WindowTest, StackUponCreation) { | |
1197 std::unique_ptr<TestWindow> parent(CreateTestWindow(0, nullptr)); | |
1198 std::unique_ptr<TestWindow> window0(CreateTestWindow(1, parent.get())); | |
1199 std::unique_ptr<TestWindow> window1(CreateTestWindow(2, parent.get())); | |
1200 | |
1201 TestWindow* window2 = CreateTestWindow(3, parent.get()); | |
1202 | |
1203 window0->AddTransientWindow(window2); | |
1204 EXPECT_EQ("1 3 2", ChildWindowIDsAsString(parent.get())); | |
1205 } | |
1206 | |
1207 namespace { | |
1208 | |
1209 class TransientWindowObserver : public WindowObserver { | |
1210 public: | |
1211 TransientWindowObserver() {} | |
1212 ~TransientWindowObserver() override {} | |
1213 | |
1214 void ResetCounts() { added_count_ = removed_count_ = 0; } | |
1215 | |
1216 int added_count() const { return added_count_; } | |
1217 int removed_count() const { return removed_count_; } | |
1218 | |
1219 // WindowObserver: | |
1220 void OnTransientChildAdded(ui::Window* window, | |
1221 ui::Window* transient) override { | |
1222 added_count_++; | |
1223 } | |
1224 void OnTransientChildRemoved(ui::Window* window, | |
1225 ui::Window* transient) override { | |
1226 removed_count_++; | |
1227 } | |
1228 | |
1229 private: | |
1230 int added_count_ = 0; | |
1231 int removed_count_ = 0; | |
1232 | |
1233 DISALLOW_COPY_AND_ASSIGN(TransientWindowObserver); | |
1234 }; | |
1235 | |
1236 } // namespace | |
1237 | |
1238 // Verifies WindowObserver is notified of transient windows added/removed. | |
1239 TEST_F(WindowTest, TransientNotifiesObserver) { | |
1240 std::unique_ptr<TestWindow> parent(CreateTestWindow(0, nullptr)); | |
1241 TransientWindowObserver observer; | |
1242 parent->AddObserver(&observer); | |
1243 std::unique_ptr<TestWindow> child(CreateTestWindow(0, nullptr)); | |
1244 parent->AddTransientWindow(child.get()); | |
1245 EXPECT_EQ(1, observer.added_count()); | |
1246 EXPECT_EQ(0, observer.removed_count()); | |
1247 observer.ResetCounts(); | |
1248 | |
1249 parent->RemoveTransientWindow(child.get()); | |
1250 EXPECT_EQ(0, observer.added_count()); | |
1251 EXPECT_EQ(1, observer.removed_count()); | |
1252 observer.ResetCounts(); | |
1253 | |
1254 parent->AddTransientWindow(child.get()); | |
1255 EXPECT_EQ(1, observer.added_count()); | |
1256 EXPECT_EQ(0, observer.removed_count()); | |
1257 observer.ResetCounts(); | |
1258 | |
1259 child.reset(); | |
1260 EXPECT_EQ(0, observer.added_count()); | |
1261 EXPECT_EQ(1, observer.removed_count()); | |
1262 observer.ResetCounts(); | |
1263 } | |
1264 | |
1265 } // namespace ui | |
OLD | NEW |