Fix build break
[chromium-blink-merge.git] / ui / aura / window_unittest.cc
blob0800ec5fa05c2afa563a306d7736f08d11e708b6
1 // Copyright (c) 2012 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/aura/window.h"
7 #include <utility>
9 #include "base/basictypes.h"
10 #include "base/compiler_specific.h"
11 #include "base/string_number_conversions.h"
12 #include "base/stringprintf.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "ui/aura/client/capture_client.h"
15 #include "ui/aura/client/focus_change_observer.h"
16 #include "ui/aura/client/stacking_client.h"
17 #include "ui/aura/client/visibility_client.h"
18 #include "ui/aura/layout_manager.h"
19 #include "ui/aura/root_window.h"
20 #include "ui/aura/root_window_host.h"
21 #include "ui/aura/root_window_observer.h"
22 #include "ui/aura/test/aura_test_base.h"
23 #include "ui/aura/test/event_generator.h"
24 #include "ui/aura/test/test_window_delegate.h"
25 #include "ui/aura/test/test_windows.h"
26 #include "ui/aura/test/window_test_api.h"
27 #include "ui/aura/window_delegate.h"
28 #include "ui/aura/window_observer.h"
29 #include "ui/aura/window_property.h"
30 #include "ui/base/events/event.h"
31 #include "ui/base/events/event_utils.h"
32 #include "ui/base/gestures/gesture_configuration.h"
33 #include "ui/base/hit_test.h"
34 #include "ui/base/keycodes/keyboard_codes.h"
35 #include "ui/compositor/layer.h"
36 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
37 #include "ui/compositor/scoped_layer_animation_settings.h"
38 #include "ui/gfx/canvas.h"
39 #include "ui/gfx/screen.h"
41 DECLARE_WINDOW_PROPERTY_TYPE(const char*)
42 DECLARE_WINDOW_PROPERTY_TYPE(int)
44 namespace aura {
45 namespace test {
47 class WindowTest : public AuraTestBase {
48 public:
49 WindowTest() : max_separation_(0) {
52 virtual void SetUp() OVERRIDE {
53 AuraTestBase::SetUp();
54 // TODO: there needs to be an easier way to do this.
55 max_separation_ = ui::GestureConfiguration::
56 max_separation_for_gesture_touches_in_pixels();
57 ui::GestureConfiguration::
58 set_max_separation_for_gesture_touches_in_pixels(0);
61 virtual void TearDown() OVERRIDE {
62 AuraTestBase::TearDown();
63 ui::GestureConfiguration::
64 set_max_separation_for_gesture_touches_in_pixels(max_separation_);
67 // Adds |window| to |root_window_|, through the StackingClient.
68 void SetDefaultParentByPrimaryRootWindow(aura::Window* window) {
69 window->SetDefaultParentByRootWindow(root_window(), gfx::Rect());
72 private:
73 int max_separation_;
75 DISALLOW_COPY_AND_ASSIGN(WindowTest);
78 namespace {
80 // Used for verifying destruction methods are invoked.
81 class DestroyTrackingDelegateImpl : public TestWindowDelegate {
82 public:
83 DestroyTrackingDelegateImpl()
84 : destroying_count_(0),
85 destroyed_count_(0),
86 in_destroying_(false) {}
88 void clear_destroying_count() { destroying_count_ = 0; }
89 int destroying_count() const { return destroying_count_; }
91 void clear_destroyed_count() { destroyed_count_ = 0; }
92 int destroyed_count() const { return destroyed_count_; }
94 bool in_destroying() const { return in_destroying_; }
96 virtual void OnWindowDestroying() OVERRIDE {
97 EXPECT_FALSE(in_destroying_);
98 in_destroying_ = true;
99 destroying_count_++;
102 virtual void OnWindowDestroyed() OVERRIDE {
103 EXPECT_TRUE(in_destroying_);
104 in_destroying_ = false;
105 destroyed_count_++;
108 private:
109 int destroying_count_;
110 int destroyed_count_;
111 bool in_destroying_;
113 DISALLOW_COPY_AND_ASSIGN(DestroyTrackingDelegateImpl);
116 // Used to verify that when OnWindowDestroying is invoked the parent is also
117 // is in the process of being destroyed.
118 class ChildWindowDelegateImpl : public DestroyTrackingDelegateImpl {
119 public:
120 explicit ChildWindowDelegateImpl(
121 DestroyTrackingDelegateImpl* parent_delegate)
122 : parent_delegate_(parent_delegate) {
125 virtual void OnWindowDestroying() OVERRIDE {
126 EXPECT_TRUE(parent_delegate_->in_destroying());
127 DestroyTrackingDelegateImpl::OnWindowDestroying();
130 private:
131 DestroyTrackingDelegateImpl* parent_delegate_;
133 DISALLOW_COPY_AND_ASSIGN(ChildWindowDelegateImpl);
136 // Used to verify that a Window is removed from its parent when
137 // OnWindowDestroyed is called.
138 class DestroyOrphanDelegate : public TestWindowDelegate {
139 public:
140 DestroyOrphanDelegate() : window_(NULL) {
143 void set_window(Window* window) { window_ = window; }
145 virtual void OnWindowDestroyed() OVERRIDE {
146 EXPECT_FALSE(window_->parent());
149 private:
150 Window* window_;
151 DISALLOW_COPY_AND_ASSIGN(DestroyOrphanDelegate);
154 // Used in verifying mouse capture.
155 class CaptureWindowDelegateImpl : public TestWindowDelegate {
156 public:
157 CaptureWindowDelegateImpl() {
158 ResetCounts();
161 void ResetCounts() {
162 capture_changed_event_count_ = 0;
163 capture_lost_count_ = 0;
164 mouse_event_count_ = 0;
165 touch_event_count_ = 0;
166 gesture_event_count_ = 0;
169 int capture_changed_event_count() const {
170 return capture_changed_event_count_;
172 int capture_lost_count() const { return capture_lost_count_; }
173 int mouse_event_count() const { return mouse_event_count_; }
174 int touch_event_count() const { return touch_event_count_; }
175 int gesture_event_count() const { return gesture_event_count_; }
177 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
178 if (event->type() == ui::ET_MOUSE_CAPTURE_CHANGED)
179 capture_changed_event_count_++;
180 mouse_event_count_++;
182 virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE {
183 touch_event_count_++;
185 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
186 gesture_event_count_++;
188 virtual void OnCaptureLost() OVERRIDE {
189 capture_lost_count_++;
192 private:
193 int capture_changed_event_count_;
194 int capture_lost_count_;
195 int mouse_event_count_;
196 int touch_event_count_;
197 int gesture_event_count_;
199 DISALLOW_COPY_AND_ASSIGN(CaptureWindowDelegateImpl);
202 // aura::WindowDelegate that tracks the window that was reported as having the
203 // focus before us.
204 class FocusDelegate : public TestWindowDelegate,
205 public aura::client::FocusChangeObserver {
206 public:
207 FocusDelegate() : previous_focused_window_(NULL) {
210 aura::Window* previous_focused_window() const {
211 return previous_focused_window_;
214 // Overridden from client::FocusChangeObserver:
215 virtual void OnWindowFocused(Window* gained_focus,
216 Window* lost_focus) OVERRIDE {
217 previous_focused_window_ = lost_focus;
220 private:
221 aura::Window* previous_focused_window_;
223 DISALLOW_COPY_AND_ASSIGN(FocusDelegate);
226 // Keeps track of the location of the gesture.
227 class GestureTrackPositionDelegate : public TestWindowDelegate {
228 public:
229 GestureTrackPositionDelegate() {}
231 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
232 position_ = event->location();
233 event->StopPropagation();
236 const gfx::Point& position() const { return position_; }
238 private:
239 gfx::Point position_;
241 DISALLOW_COPY_AND_ASSIGN(GestureTrackPositionDelegate);
244 base::TimeDelta getTime() {
245 return ui::EventTimeForNow();
248 class SelfEventHandlingWindowDelegate : public TestWindowDelegate {
249 public:
250 SelfEventHandlingWindowDelegate() {}
252 virtual bool ShouldDescendIntoChildForEventHandling(
253 Window* child,
254 const gfx::Point& location) OVERRIDE {
255 return false;
258 private:
259 DISALLOW_COPY_AND_ASSIGN(SelfEventHandlingWindowDelegate);
262 // The delegate deletes itself when the window is being destroyed.
263 class DestroyWindowDelegate : public TestWindowDelegate {
264 public:
265 DestroyWindowDelegate() {}
267 private:
268 virtual ~DestroyWindowDelegate() {}
270 // Overridden from WindowDelegate.
271 virtual void OnWindowDestroyed() OVERRIDE {
272 delete this;
275 DISALLOW_COPY_AND_ASSIGN(DestroyWindowDelegate);
278 } // namespace
280 TEST_F(WindowTest, GetChildById) {
281 scoped_ptr<Window> w1(CreateTestWindowWithId(1, root_window()));
282 scoped_ptr<Window> w11(CreateTestWindowWithId(11, w1.get()));
283 scoped_ptr<Window> w111(CreateTestWindowWithId(111, w11.get()));
284 scoped_ptr<Window> w12(CreateTestWindowWithId(12, w1.get()));
286 EXPECT_EQ(NULL, w1->GetChildById(57));
287 EXPECT_EQ(w12.get(), w1->GetChildById(12));
288 EXPECT_EQ(w111.get(), w1->GetChildById(111));
291 // Make sure that Window::Contains correctly handles children, grandchildren,
292 // and not containing NULL or parents.
293 TEST_F(WindowTest, Contains) {
294 Window parent(NULL);
295 parent.Init(ui::LAYER_NOT_DRAWN);
296 Window child1(NULL);
297 child1.Init(ui::LAYER_NOT_DRAWN);
298 Window child2(NULL);
299 child2.Init(ui::LAYER_NOT_DRAWN);
301 parent.AddChild(&child1);
302 child1.AddChild(&child2);
304 EXPECT_TRUE(parent.Contains(&parent));
305 EXPECT_TRUE(parent.Contains(&child1));
306 EXPECT_TRUE(parent.Contains(&child2));
308 EXPECT_FALSE(parent.Contains(NULL));
309 EXPECT_FALSE(child1.Contains(&parent));
310 EXPECT_FALSE(child2.Contains(&child1));
313 TEST_F(WindowTest, ContainsPointInRoot) {
314 scoped_ptr<Window> w(
315 CreateTestWindow(SK_ColorWHITE, 1, gfx::Rect(10, 10, 5, 5),
316 root_window()));
317 EXPECT_FALSE(w->ContainsPointInRoot(gfx::Point(9, 9)));
318 EXPECT_TRUE(w->ContainsPointInRoot(gfx::Point(10, 10)));
319 EXPECT_TRUE(w->ContainsPointInRoot(gfx::Point(14, 14)));
320 EXPECT_FALSE(w->ContainsPointInRoot(gfx::Point(15, 15)));
321 EXPECT_FALSE(w->ContainsPointInRoot(gfx::Point(20, 20)));
324 TEST_F(WindowTest, ContainsPoint) {
325 scoped_ptr<Window> w(
326 CreateTestWindow(SK_ColorWHITE, 1, gfx::Rect(10, 10, 5, 5),
327 root_window()));
328 EXPECT_TRUE(w->ContainsPoint(gfx::Point(0, 0)));
329 EXPECT_TRUE(w->ContainsPoint(gfx::Point(4, 4)));
330 EXPECT_FALSE(w->ContainsPoint(gfx::Point(5, 5)));
331 EXPECT_FALSE(w->ContainsPoint(gfx::Point(10, 10)));
334 TEST_F(WindowTest, ConvertPointToWindow) {
335 // Window::ConvertPointToWindow is mostly identical to
336 // Layer::ConvertPointToLayer, except NULL values for |source| are permitted,
337 // in which case the function just returns.
338 scoped_ptr<Window> w1(CreateTestWindowWithId(1, root_window()));
339 gfx::Point reference_point(100, 100);
340 gfx::Point test_point = reference_point;
341 Window::ConvertPointToTarget(NULL, w1.get(), &test_point);
342 EXPECT_EQ(reference_point, test_point);
345 TEST_F(WindowTest, MoveCursorTo) {
346 scoped_ptr<Window> w1(
347 CreateTestWindow(SK_ColorWHITE, 1, gfx::Rect(10, 10, 500, 500),
348 root_window()));
349 scoped_ptr<Window> w11(
350 CreateTestWindow(SK_ColorGREEN, 11, gfx::Rect(5, 5, 100, 100), w1.get()));
351 scoped_ptr<Window> w111(
352 CreateTestWindow(SK_ColorCYAN, 111, gfx::Rect(5, 5, 75, 75), w11.get()));
353 scoped_ptr<Window> w1111(
354 CreateTestWindow(SK_ColorRED, 1111, gfx::Rect(5, 5, 50, 50), w111.get()));
356 RootWindow* root = root_window();
357 root->MoveCursorTo(gfx::Point(10, 10));
358 EXPECT_EQ("10,10",
359 gfx::Screen::GetScreenFor(root)->GetCursorScreenPoint().ToString());
360 w1->MoveCursorTo(gfx::Point(10, 10));
361 EXPECT_EQ("20,20",
362 gfx::Screen::GetScreenFor(root)->GetCursorScreenPoint().ToString());
363 w11->MoveCursorTo(gfx::Point(10, 10));
364 EXPECT_EQ("25,25",
365 gfx::Screen::GetScreenFor(root)->GetCursorScreenPoint().ToString());
366 w111->MoveCursorTo(gfx::Point(10, 10));
367 EXPECT_EQ("30,30",
368 gfx::Screen::GetScreenFor(root)->GetCursorScreenPoint().ToString());
369 w1111->MoveCursorTo(gfx::Point(10, 10));
370 EXPECT_EQ("35,35",
371 gfx::Screen::GetScreenFor(root)->GetCursorScreenPoint().ToString());
374 TEST_F(WindowTest, ContainsMouse) {
375 scoped_ptr<Window> w(
376 CreateTestWindow(SK_ColorWHITE, 1, gfx::Rect(10, 10, 500, 500),
377 root_window()));
378 w->Show();
379 WindowTestApi w_test_api(w.get());
380 RootWindow* root = root_window();
381 root->MoveCursorTo(gfx::Point(10, 10));
382 EXPECT_TRUE(w_test_api.ContainsMouse());
383 root->MoveCursorTo(gfx::Point(9, 10));
384 EXPECT_FALSE(w_test_api.ContainsMouse());
387 // Test Window::ConvertPointToWindow() with transform to root_window.
388 TEST_F(WindowTest, MoveCursorToWithTransformRootWindow) {
389 RootWindow* root = root_window();
390 gfx::Transform transform;
391 transform.Translate(100.0, 100.0);
392 transform.Rotate(90.0);
393 transform.Scale(2.0, 5.0);
394 root->SetTransform(transform);
395 root->MoveCursorTo(gfx::Point(10, 10));
396 #if !defined(OS_WIN)
397 gfx::Point mouse_location;
398 EXPECT_TRUE(root->QueryMouseLocationForTest(&mouse_location));
399 // TODO(yoshiki): fix this to build on Windows. See crbug.com/133413.OD
400 EXPECT_EQ("50,120", mouse_location.ToString());
401 #endif
402 EXPECT_EQ("10,10",
403 gfx::Screen::GetScreenFor(root)->GetCursorScreenPoint().ToString());
406 // Tests Window::ConvertPointToWindow() with transform to non-root windows.
407 TEST_F(WindowTest, MoveCursorToWithTransformWindow) {
408 scoped_ptr<Window> w1(
409 CreateTestWindow(SK_ColorWHITE, 1, gfx::Rect(10, 10, 500, 500),
410 root_window()));
412 gfx::Transform transform1;
413 transform1.Scale(2, 2);
414 w1->SetTransform(transform1);
415 w1->MoveCursorTo(gfx::Point(10, 10));
416 EXPECT_EQ("30,30",
417 gfx::Screen::GetScreenFor(w1.get())->GetCursorScreenPoint().ToString());
419 gfx::Transform transform2;
420 transform2.Translate(-10, 20);
421 w1->SetTransform(transform2);
422 w1->MoveCursorTo(gfx::Point(10, 10));
423 EXPECT_EQ("10,40",
424 gfx::Screen::GetScreenFor(w1.get())->GetCursorScreenPoint().ToString());
426 gfx::Transform transform3;
427 transform3.Rotate(90.0);
428 w1->SetTransform(transform3);
429 w1->MoveCursorTo(gfx::Point(5, 5));
430 EXPECT_EQ("5,15",
431 gfx::Screen::GetScreenFor(w1.get())->GetCursorScreenPoint().ToString());
433 gfx::Transform transform4;
434 transform4.Translate(100.0, 100.0);
435 transform4.Rotate(90.0);
436 transform4.Scale(2.0, 5.0);
437 w1->SetTransform(transform4);
438 w1->MoveCursorTo(gfx::Point(10, 10));
439 EXPECT_EQ("60,130",
440 gfx::Screen::GetScreenFor(w1.get())->GetCursorScreenPoint().ToString());
443 // Test Window::ConvertPointToWindow() with complex transforms to both root and
444 // non-root windows.
445 TEST_F(WindowTest, MoveCursorToWithComplexTransform) {
446 scoped_ptr<Window> w1(
447 CreateTestWindow(SK_ColorWHITE, 1, gfx::Rect(10, 10, 500, 500),
448 root_window()));
449 scoped_ptr<Window> w11(
450 CreateTestWindow(SK_ColorGREEN, 11, gfx::Rect(5, 5, 100, 100), w1.get()));
451 scoped_ptr<Window> w111(
452 CreateTestWindow(SK_ColorCYAN, 111, gfx::Rect(5, 5, 75, 75), w11.get()));
453 scoped_ptr<Window> w1111(
454 CreateTestWindow(SK_ColorRED, 1111, gfx::Rect(5, 5, 50, 50), w111.get()));
456 RootWindow* root = root_window();
458 // The root window expects transforms that produce integer rects.
459 gfx::Transform root_transform;
460 root_transform.Translate(60.0, 70.0);
461 root_transform.Rotate(-90.0);
462 root_transform.Translate(-50.0, -50.0);
463 root_transform.Scale(2.0, 3.0);
465 gfx::Transform transform;
466 transform.Translate(10.0, 20.0);
467 transform.Rotate(10.0);
468 transform.Scale(0.3, 0.5);
469 root->SetTransform(root_transform);
470 w1->SetTransform(transform);
471 w11->SetTransform(transform);
472 w111->SetTransform(transform);
473 w1111->SetTransform(transform);
475 w1111->MoveCursorTo(gfx::Point(10, 10));
477 #if !defined(OS_WIN)
478 // TODO(yoshiki): fix this to build on Windows. See crbug.com/133413.
479 gfx::Point mouse_location;
480 EXPECT_TRUE(root->QueryMouseLocationForTest(&mouse_location));
481 EXPECT_EQ("169,80", mouse_location.ToString());
482 #endif
483 EXPECT_EQ("20,53",
484 gfx::Screen::GetScreenFor(root)->GetCursorScreenPoint().ToString());
487 TEST_F(WindowTest, HitTest) {
488 Window w1(new ColorTestWindowDelegate(SK_ColorWHITE));
489 w1.set_id(1);
490 w1.Init(ui::LAYER_TEXTURED);
491 w1.SetBounds(gfx::Rect(10, 20, 50, 60));
492 w1.Show();
493 SetDefaultParentByPrimaryRootWindow(&w1);
495 // Points are in the Window's coordinates.
496 EXPECT_TRUE(w1.HitTest(gfx::Point(1, 1)));
497 EXPECT_FALSE(w1.HitTest(gfx::Point(-1, -1)));
499 // We can expand the bounds slightly to track events outside our border.
500 w1.SetHitTestBoundsOverrideOuter(gfx::Insets(-1, -1, -1, -1), 5);
501 EXPECT_TRUE(w1.HitTest(gfx::Point(-1, -1)));
502 EXPECT_FALSE(w1.HitTest(gfx::Point(-2, -2)));
504 ui::TouchEvent pressed(
505 ui::ET_TOUCH_PRESSED, gfx::Point(50, 50), 0, getTime());
506 root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&pressed);
507 EXPECT_TRUE(w1.HitTest(gfx::Point(-2, -2)));
508 EXPECT_TRUE(w1.HitTest(gfx::Point(-5, -5)));
509 EXPECT_FALSE(w1.HitTest(gfx::Point(-5, -6)));
510 ui::TouchEvent released(
511 ui::ET_TOUCH_RELEASED, gfx::Point(50, 50), 0, getTime());
512 root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&released);
513 EXPECT_FALSE(w1.HitTest(gfx::Point(-2, -2)));
515 // TODO(beng): clip Window to parent.
518 TEST_F(WindowTest, HitTestMask) {
519 MaskedWindowDelegate d1(gfx::Rect(5, 6, 20, 30));
520 Window w1(&d1);
521 w1.Init(ui::LAYER_NOT_DRAWN);
522 w1.SetBounds(gfx::Rect(10, 20, 50, 60));
523 w1.Show();
524 SetDefaultParentByPrimaryRootWindow(&w1);
526 // Points inside the mask.
527 EXPECT_TRUE(w1.HitTest(gfx::Point(5, 6))); // top-left
528 EXPECT_TRUE(w1.HitTest(gfx::Point(15, 21))); // center
529 EXPECT_TRUE(w1.HitTest(gfx::Point(24, 35))); // bottom-right
531 // Points outside the mask.
532 EXPECT_FALSE(w1.HitTest(gfx::Point(0, 0)));
533 EXPECT_FALSE(w1.HitTest(gfx::Point(60, 80)));
534 EXPECT_FALSE(w1.HitTest(gfx::Point(4, 6)));
535 EXPECT_FALSE(w1.HitTest(gfx::Point(5, 5)));
536 EXPECT_FALSE(w1.HitTest(gfx::Point(25, 36)));
539 TEST_F(WindowTest, GetEventHandlerForPoint) {
540 scoped_ptr<Window> w1(
541 CreateTestWindow(SK_ColorWHITE, 1, gfx::Rect(10, 10, 500, 500),
542 root_window()));
543 scoped_ptr<Window> w11(
544 CreateTestWindow(SK_ColorGREEN, 11, gfx::Rect(5, 5, 100, 100), w1.get()));
545 scoped_ptr<Window> w111(
546 CreateTestWindow(SK_ColorCYAN, 111, gfx::Rect(5, 5, 75, 75), w11.get()));
547 scoped_ptr<Window> w1111(
548 CreateTestWindow(SK_ColorRED, 1111, gfx::Rect(5, 5, 50, 50), w111.get()));
549 scoped_ptr<Window> w12(
550 CreateTestWindow(SK_ColorMAGENTA, 12, gfx::Rect(10, 420, 25, 25),
551 w1.get()));
552 scoped_ptr<Window> w121(
553 CreateTestWindow(SK_ColorYELLOW, 121, gfx::Rect(5, 5, 5, 5), w12.get()));
554 scoped_ptr<Window> w13(
555 CreateTestWindow(SK_ColorGRAY, 13, gfx::Rect(5, 470, 50, 50), w1.get()));
557 Window* root = root_window();
558 w1->parent()->SetBounds(gfx::Rect(500, 500));
559 EXPECT_EQ(NULL, root->GetEventHandlerForPoint(gfx::Point(5, 5)));
560 EXPECT_EQ(w1.get(), root->GetEventHandlerForPoint(gfx::Point(11, 11)));
561 EXPECT_EQ(w11.get(), root->GetEventHandlerForPoint(gfx::Point(16, 16)));
562 EXPECT_EQ(w111.get(), root->GetEventHandlerForPoint(gfx::Point(21, 21)));
563 EXPECT_EQ(w1111.get(), root->GetEventHandlerForPoint(gfx::Point(26, 26)));
564 EXPECT_EQ(w12.get(), root->GetEventHandlerForPoint(gfx::Point(21, 431)));
565 EXPECT_EQ(w121.get(), root->GetEventHandlerForPoint(gfx::Point(26, 436)));
566 EXPECT_EQ(w13.get(), root->GetEventHandlerForPoint(gfx::Point(26, 481)));
569 TEST_F(WindowTest, GetEventHandlerForPointWithOverride) {
570 // If our child is flush to our top-left corner he gets events just inside the
571 // window edges.
572 scoped_ptr<Window> parent(
573 CreateTestWindow(SK_ColorWHITE, 1, gfx::Rect(10, 20, 400, 500),
574 root_window()));
575 scoped_ptr<Window> child(
576 CreateTestWindow(SK_ColorRED, 2, gfx::Rect(0, 0, 60, 70), parent.get()));
577 EXPECT_EQ(child.get(), parent->GetEventHandlerForPoint(gfx::Point(0, 0)));
578 EXPECT_EQ(child.get(), parent->GetEventHandlerForPoint(gfx::Point(1, 1)));
580 // We can override the hit test bounds of the parent to make the parent grab
581 // events along that edge.
582 parent->set_hit_test_bounds_override_inner(gfx::Insets(1, 1, 1, 1));
583 EXPECT_EQ(parent.get(), parent->GetEventHandlerForPoint(gfx::Point(0, 0)));
584 EXPECT_EQ(child.get(), parent->GetEventHandlerForPoint(gfx::Point(1, 1)));
587 TEST_F(WindowTest, GetEventHandlerForPointWithOverrideDescendingOrder) {
588 scoped_ptr<SelfEventHandlingWindowDelegate> parent_delegate(
589 new SelfEventHandlingWindowDelegate);
590 scoped_ptr<Window> parent(CreateTestWindowWithDelegate(
591 parent_delegate.get(), 1, gfx::Rect(10, 20, 400, 500), root_window()));
592 scoped_ptr<Window> child(
593 CreateTestWindow(SK_ColorRED, 2, gfx::Rect(0, 0, 390, 480),
594 parent.get()));
596 // We can override ShouldDescendIntoChildForEventHandling to make the parent
597 // grab all events.
598 EXPECT_EQ(parent.get(), parent->GetEventHandlerForPoint(gfx::Point(0, 0)));
599 EXPECT_EQ(parent.get(), parent->GetEventHandlerForPoint(gfx::Point(50, 50)));
602 TEST_F(WindowTest, GetTopWindowContainingPoint) {
603 Window* root = root_window();
604 root->SetBounds(gfx::Rect(0, 0, 300, 300));
606 scoped_ptr<Window> w1(
607 CreateTestWindow(SK_ColorWHITE, 1, gfx::Rect(10, 10, 100, 100),
608 root_window()));
609 scoped_ptr<Window> w11(
610 CreateTestWindow(SK_ColorGREEN, 11, gfx::Rect(0, 0, 120, 120), w1.get()));
612 scoped_ptr<Window> w2(
613 CreateTestWindow(SK_ColorRED, 2, gfx::Rect(5, 5, 55, 55),
614 root_window()));
616 scoped_ptr<Window> w3(
617 CreateTestWindowWithDelegate(
618 NULL, 3, gfx::Rect(200, 200, 100, 100), root_window()));
619 scoped_ptr<Window> w31(
620 CreateTestWindow(SK_ColorCYAN, 31, gfx::Rect(0, 0, 50, 50), w3.get()));
621 scoped_ptr<Window> w311(
622 CreateTestWindow(SK_ColorBLUE, 311, gfx::Rect(0, 0, 10, 10), w31.get()));
624 EXPECT_EQ(NULL, root->GetTopWindowContainingPoint(gfx::Point(0, 0)));
625 EXPECT_EQ(w2.get(), root->GetTopWindowContainingPoint(gfx::Point(5, 5)));
626 EXPECT_EQ(w2.get(), root->GetTopWindowContainingPoint(gfx::Point(10, 10)));
627 EXPECT_EQ(w2.get(), root->GetTopWindowContainingPoint(gfx::Point(59, 59)));
628 EXPECT_EQ(w1.get(), root->GetTopWindowContainingPoint(gfx::Point(60, 60)));
629 EXPECT_EQ(w1.get(), root->GetTopWindowContainingPoint(gfx::Point(109, 109)));
630 EXPECT_EQ(NULL, root->GetTopWindowContainingPoint(gfx::Point(110, 110)));
631 EXPECT_EQ(w31.get(), root->GetTopWindowContainingPoint(gfx::Point(200, 200)));
632 EXPECT_EQ(w31.get(), root->GetTopWindowContainingPoint(gfx::Point(220, 220)));
633 EXPECT_EQ(NULL, root->GetTopWindowContainingPoint(gfx::Point(260, 260)));
636 TEST_F(WindowTest, GetToplevelWindow) {
637 const gfx::Rect kBounds(0, 0, 10, 10);
638 TestWindowDelegate delegate;
640 scoped_ptr<Window> w1(CreateTestWindowWithId(1, root_window()));
641 scoped_ptr<Window> w11(
642 CreateTestWindowWithDelegate(&delegate, 11, kBounds, w1.get()));
643 scoped_ptr<Window> w111(CreateTestWindowWithId(111, w11.get()));
644 scoped_ptr<Window> w1111(
645 CreateTestWindowWithDelegate(&delegate, 1111, kBounds, w111.get()));
647 EXPECT_TRUE(root_window()->GetToplevelWindow() == NULL);
648 EXPECT_TRUE(w1->GetToplevelWindow() == NULL);
649 EXPECT_EQ(w11.get(), w11->GetToplevelWindow());
650 EXPECT_EQ(w11.get(), w111->GetToplevelWindow());
651 EXPECT_EQ(w11.get(), w1111->GetToplevelWindow());
654 class AddedToRootWindowObserver : public WindowObserver {
655 public:
656 AddedToRootWindowObserver() : called_(false) {}
658 virtual void OnWindowAddedToRootWindow(Window* window) OVERRIDE {
659 called_ = true;
662 bool called() const { return called_; }
664 private:
665 bool called_;
667 DISALLOW_COPY_AND_ASSIGN(AddedToRootWindowObserver);
670 TEST_F(WindowTest, WindowAddedToRootWindowShouldNotifyChildAndNotParent) {
671 AddedToRootWindowObserver parent_observer;
672 AddedToRootWindowObserver child_observer;
673 scoped_ptr<Window> parent_window(CreateTestWindowWithId(1, root_window()));
674 scoped_ptr<Window> child_window(new Window(NULL));
675 child_window->Init(ui::LAYER_TEXTURED);
676 child_window->Show();
678 parent_window->AddObserver(&parent_observer);
679 child_window->AddObserver(&child_observer);
681 parent_window->AddChild(child_window.get());
683 EXPECT_FALSE(parent_observer.called());
684 EXPECT_TRUE(child_observer.called());
686 parent_window->RemoveObserver(&parent_observer);
687 child_window->RemoveObserver(&child_observer);
690 // Various destruction assertions.
691 TEST_F(WindowTest, DestroyTest) {
692 DestroyTrackingDelegateImpl parent_delegate;
693 ChildWindowDelegateImpl child_delegate(&parent_delegate);
695 scoped_ptr<Window> parent(
696 CreateTestWindowWithDelegate(&parent_delegate, 0, gfx::Rect(),
697 root_window()));
698 CreateTestWindowWithDelegate(&child_delegate, 0, gfx::Rect(), parent.get());
700 // Both the parent and child should have been destroyed.
701 EXPECT_EQ(1, parent_delegate.destroying_count());
702 EXPECT_EQ(1, parent_delegate.destroyed_count());
703 EXPECT_EQ(1, child_delegate.destroying_count());
704 EXPECT_EQ(1, child_delegate.destroyed_count());
707 // Tests that a window is orphaned before OnWindowDestroyed is called.
708 TEST_F(WindowTest, OrphanedBeforeOnDestroyed) {
709 TestWindowDelegate parent_delegate;
710 DestroyOrphanDelegate child_delegate;
712 scoped_ptr<Window> parent(
713 CreateTestWindowWithDelegate(&parent_delegate, 0, gfx::Rect(),
714 root_window()));
715 scoped_ptr<Window> child(CreateTestWindowWithDelegate(&child_delegate, 0,
716 gfx::Rect(), parent.get()));
717 child_delegate.set_window(child.get());
721 // Make sure StackChildAtTop moves both the window and layer to the front.
722 TEST_F(WindowTest, StackChildAtTop) {
723 Window parent(NULL);
724 parent.Init(ui::LAYER_NOT_DRAWN);
725 Window child1(NULL);
726 child1.Init(ui::LAYER_NOT_DRAWN);
727 Window child2(NULL);
728 child2.Init(ui::LAYER_NOT_DRAWN);
730 parent.AddChild(&child1);
731 parent.AddChild(&child2);
732 ASSERT_EQ(2u, parent.children().size());
733 EXPECT_EQ(&child1, parent.children()[0]);
734 EXPECT_EQ(&child2, parent.children()[1]);
735 ASSERT_EQ(2u, parent.layer()->children().size());
736 EXPECT_EQ(child1.layer(), parent.layer()->children()[0]);
737 EXPECT_EQ(child2.layer(), parent.layer()->children()[1]);
739 parent.StackChildAtTop(&child1);
740 ASSERT_EQ(2u, parent.children().size());
741 EXPECT_EQ(&child1, parent.children()[1]);
742 EXPECT_EQ(&child2, parent.children()[0]);
743 ASSERT_EQ(2u, parent.layer()->children().size());
744 EXPECT_EQ(child1.layer(), parent.layer()->children()[1]);
745 EXPECT_EQ(child2.layer(), parent.layer()->children()[0]);
748 // Make sure StackChildBelow works.
749 TEST_F(WindowTest, StackChildBelow) {
750 Window parent(NULL);
751 parent.Init(ui::LAYER_NOT_DRAWN);
752 Window child1(NULL);
753 child1.Init(ui::LAYER_NOT_DRAWN);
754 child1.set_id(1);
755 Window child2(NULL);
756 child2.Init(ui::LAYER_NOT_DRAWN);
757 child2.set_id(2);
758 Window child3(NULL);
759 child3.Init(ui::LAYER_NOT_DRAWN);
760 child3.set_id(3);
762 parent.AddChild(&child1);
763 parent.AddChild(&child2);
764 parent.AddChild(&child3);
765 EXPECT_EQ("1 2 3", ChildWindowIDsAsString(&parent));
767 parent.StackChildBelow(&child1, &child2);
768 EXPECT_EQ("1 2 3", ChildWindowIDsAsString(&parent));
770 parent.StackChildBelow(&child2, &child1);
771 EXPECT_EQ("2 1 3", ChildWindowIDsAsString(&parent));
773 parent.StackChildBelow(&child3, &child2);
774 EXPECT_EQ("3 2 1", ChildWindowIDsAsString(&parent));
776 parent.StackChildBelow(&child3, &child1);
777 EXPECT_EQ("2 3 1", ChildWindowIDsAsString(&parent));
780 // Various assertions for StackChildAbove.
781 TEST_F(WindowTest, StackChildAbove) {
782 Window parent(NULL);
783 parent.Init(ui::LAYER_NOT_DRAWN);
784 Window child1(NULL);
785 child1.Init(ui::LAYER_NOT_DRAWN);
786 Window child2(NULL);
787 child2.Init(ui::LAYER_NOT_DRAWN);
788 Window child3(NULL);
789 child3.Init(ui::LAYER_NOT_DRAWN);
791 parent.AddChild(&child1);
792 parent.AddChild(&child2);
794 // Move 1 in front of 2.
795 parent.StackChildAbove(&child1, &child2);
796 ASSERT_EQ(2u, parent.children().size());
797 EXPECT_EQ(&child2, parent.children()[0]);
798 EXPECT_EQ(&child1, parent.children()[1]);
799 ASSERT_EQ(2u, parent.layer()->children().size());
800 EXPECT_EQ(child2.layer(), parent.layer()->children()[0]);
801 EXPECT_EQ(child1.layer(), parent.layer()->children()[1]);
803 // Add 3, resulting in order [2, 1, 3], then move 2 in front of 1, resulting
804 // in [1, 2, 3].
805 parent.AddChild(&child3);
806 parent.StackChildAbove(&child2, &child1);
807 ASSERT_EQ(3u, parent.children().size());
808 EXPECT_EQ(&child1, parent.children()[0]);
809 EXPECT_EQ(&child2, parent.children()[1]);
810 EXPECT_EQ(&child3, parent.children()[2]);
811 ASSERT_EQ(3u, parent.layer()->children().size());
812 EXPECT_EQ(child1.layer(), parent.layer()->children()[0]);
813 EXPECT_EQ(child2.layer(), parent.layer()->children()[1]);
814 EXPECT_EQ(child3.layer(), parent.layer()->children()[2]);
816 // Move 1 in front of 3, resulting in [2, 3, 1].
817 parent.StackChildAbove(&child1, &child3);
818 ASSERT_EQ(3u, parent.children().size());
819 EXPECT_EQ(&child2, parent.children()[0]);
820 EXPECT_EQ(&child3, parent.children()[1]);
821 EXPECT_EQ(&child1, parent.children()[2]);
822 ASSERT_EQ(3u, parent.layer()->children().size());
823 EXPECT_EQ(child2.layer(), parent.layer()->children()[0]);
824 EXPECT_EQ(child3.layer(), parent.layer()->children()[1]);
825 EXPECT_EQ(child1.layer(), parent.layer()->children()[2]);
827 // Moving 1 in front of 2 should lower it, resulting in [2, 1, 3].
828 parent.StackChildAbove(&child1, &child2);
829 ASSERT_EQ(3u, parent.children().size());
830 EXPECT_EQ(&child2, parent.children()[0]);
831 EXPECT_EQ(&child1, parent.children()[1]);
832 EXPECT_EQ(&child3, parent.children()[2]);
833 ASSERT_EQ(3u, parent.layer()->children().size());
834 EXPECT_EQ(child2.layer(), parent.layer()->children()[0]);
835 EXPECT_EQ(child1.layer(), parent.layer()->children()[1]);
836 EXPECT_EQ(child3.layer(), parent.layer()->children()[2]);
839 // Various capture assertions.
840 TEST_F(WindowTest, CaptureTests) {
841 CaptureWindowDelegateImpl delegate;
842 scoped_ptr<Window> window(CreateTestWindowWithDelegate(
843 &delegate, 0, gfx::Rect(0, 0, 20, 20), root_window()));
844 EXPECT_FALSE(window->HasCapture());
846 delegate.ResetCounts();
848 // Do a capture.
849 window->SetCapture();
850 EXPECT_TRUE(window->HasCapture());
851 EXPECT_EQ(0, delegate.capture_lost_count());
852 EXPECT_EQ(0, delegate.capture_changed_event_count());
853 EventGenerator generator(root_window(), gfx::Point(50, 50));
854 generator.PressLeftButton();
855 EXPECT_EQ(1, delegate.mouse_event_count());
856 generator.ReleaseLeftButton();
858 EXPECT_EQ(2, delegate.mouse_event_count());
859 delegate.ResetCounts();
861 ui::TouchEvent touchev(
862 ui::ET_TOUCH_PRESSED, gfx::Point(50, 50), 0, getTime());
863 root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&touchev);
864 EXPECT_EQ(1, delegate.touch_event_count());
865 delegate.ResetCounts();
867 window->ReleaseCapture();
868 EXPECT_FALSE(window->HasCapture());
869 EXPECT_EQ(1, delegate.capture_lost_count());
870 EXPECT_EQ(1, delegate.capture_changed_event_count());
871 EXPECT_EQ(1, delegate.mouse_event_count());
872 EXPECT_EQ(1, delegate.touch_event_count());
874 generator.PressLeftButton();
875 EXPECT_EQ(1, delegate.mouse_event_count());
877 ui::TouchEvent touchev2(
878 ui::ET_TOUCH_PRESSED, gfx::Point(250, 250), 1, getTime());
879 root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&touchev2);
880 EXPECT_EQ(1, delegate.touch_event_count());
882 // Removing the capture window from parent should reset the capture window
883 // in the root window.
884 window->SetCapture();
885 EXPECT_EQ(window.get(), aura::client::GetCaptureWindow(root_window()));
886 window->parent()->RemoveChild(window.get());
887 EXPECT_FALSE(window->HasCapture());
888 EXPECT_EQ(NULL, aura::client::GetCaptureWindow(root_window()));
891 TEST_F(WindowTest, TouchCaptureCancelsOtherTouches) {
892 CaptureWindowDelegateImpl delegate1;
893 scoped_ptr<Window> w1(CreateTestWindowWithDelegate(
894 &delegate1, 0, gfx::Rect(0, 0, 20, 20), root_window()));
895 CaptureWindowDelegateImpl delegate2;
896 scoped_ptr<Window> w2(CreateTestWindowWithDelegate(
897 &delegate2, 0, gfx::Rect(20, 20, 20, 20), root_window()));
899 // Press on w1.
900 ui::TouchEvent press(
901 ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 0, getTime());
902 root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
903 // We will get both GESTURE_BEGIN and GESTURE_TAP_DOWN.
904 EXPECT_EQ(2, delegate1.gesture_event_count());
905 delegate1.ResetCounts();
906 w2->SetCapture();
908 // The touch was cancelled when the other window
909 // attained a touch lock.
910 EXPECT_EQ(1, delegate1.touch_event_count());
911 EXPECT_EQ(0, delegate2.touch_event_count());
913 delegate1.ResetCounts();
914 delegate2.ResetCounts();
916 ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(10, 10), 0, getTime());
917 root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move);
919 // This touch id is now ignored, no scroll fired.
920 EXPECT_EQ(0, delegate1.gesture_event_count());
921 EXPECT_EQ(0, delegate2.gesture_event_count());
923 ui::TouchEvent release(
924 ui::ET_TOUCH_RELEASED, gfx::Point(10, 10), 0, getTime());
925 root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
926 EXPECT_EQ(0, delegate1.gesture_event_count());
927 EXPECT_EQ(0, delegate2.gesture_event_count());
929 // A new press is captured by w2.
931 ui::TouchEvent press2(
932 ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 0, getTime());
933 root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
934 EXPECT_EQ(0, delegate1.gesture_event_count());
935 // We will get both GESTURE_BEGIN and GESTURE_TAP_DOWN.
936 EXPECT_EQ(2, delegate2.gesture_event_count());
939 TEST_F(WindowTest, TouchCaptureDoesntCancelCapturedTouches) {
940 CaptureWindowDelegateImpl delegate;
941 scoped_ptr<Window> window(CreateTestWindowWithDelegate(
942 &delegate, 0, gfx::Rect(0, 0, 20, 20), root_window()));
944 ui::TouchEvent press(
945 ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 0, getTime());
946 root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
948 // We will get both GESTURE_BEGIN and GESTURE_TAP_DOWN.
949 EXPECT_EQ(2, delegate.gesture_event_count());
950 delegate.ResetCounts();
952 window->SetCapture();
953 EXPECT_EQ(0, delegate.gesture_event_count());
954 delegate.ResetCounts();
956 // The move event should still create a gesture, as this touch was
957 // on the window which was captured.
958 ui::TouchEvent release(ui::ET_TOUCH_RELEASED,
959 gfx::Point(10, 10), 0, getTime() +
960 base::TimeDelta::FromMilliseconds(50));
961 root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
962 EXPECT_EQ(2, delegate.gesture_event_count());
965 // Assertions around SetCapture() and touch/gestures.
966 TEST_F(WindowTest, TransferCaptureTouchEvents) {
967 // Touch on |w1|.
968 CaptureWindowDelegateImpl d1;
969 scoped_ptr<Window> w1(CreateTestWindowWithDelegate(
970 &d1, 0, gfx::Rect(0, 0, 20, 20), root_window()));
971 ui::TouchEvent p1(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 0, getTime());
972 root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&p1);
973 // We will get both GESTURE_BEGIN and GESTURE_TAP_DOWN.
974 EXPECT_EQ(2, d1.gesture_event_count());
975 d1.ResetCounts();
977 // Touch on |w2| with a different id.
978 CaptureWindowDelegateImpl d2;
979 scoped_ptr<Window> w2(CreateTestWindowWithDelegate(
980 &d2, 0, gfx::Rect(40, 0, 40, 20), root_window()));
981 ui::TouchEvent p2(ui::ET_TOUCH_PRESSED, gfx::Point(41, 10), 1, getTime());
982 root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&p2);
983 EXPECT_EQ(0, d1.gesture_event_count());
984 // We will get both GESTURE_BEGIN and GESTURE_TAP_DOWN for new target window.
985 EXPECT_EQ(2, d2.gesture_event_count());
986 d1.ResetCounts();
987 d2.ResetCounts();
989 // Set capture on |w2|, this should send a cancel (TAP_CANCEL, END) to |w1|
990 // but not |w2|.
991 w2->SetCapture();
992 EXPECT_EQ(2, d1.gesture_event_count());
993 EXPECT_EQ(0, d2.gesture_event_count());
994 d1.ResetCounts();
995 d2.ResetCounts();
997 CaptureWindowDelegateImpl d3;
998 scoped_ptr<Window> w3(CreateTestWindowWithDelegate(
999 &d3, 0, gfx::Rect(0, 0, 100, 101), root_window()));
1000 // Set capture on w3. No new events should be received.
1001 w3->SetCapture();
1002 EXPECT_EQ(0, d1.gesture_event_count());
1003 EXPECT_EQ(0, d2.gesture_event_count());
1004 EXPECT_EQ(0, d3.gesture_event_count());
1006 // Move touch id originally associated with |w2|. Since capture was transfered
1007 // from 2 to 3 only |w3| should get the event.
1008 ui::TouchEvent m3(ui::ET_TOUCH_MOVED, gfx::Point(110, 105), 1, getTime());
1009 root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&m3);
1010 EXPECT_EQ(0, d1.gesture_event_count());
1011 EXPECT_EQ(0, d2.gesture_event_count());
1012 // |w3| gets a TAP_CANCEL and two scroll related events.
1013 EXPECT_EQ(3, d3.gesture_event_count());
1016 // Changes capture while capture is already ongoing.
1017 TEST_F(WindowTest, ChangeCaptureWhileMouseDown) {
1018 CaptureWindowDelegateImpl delegate;
1019 scoped_ptr<Window> window(CreateTestWindowWithDelegate(
1020 &delegate, 0, gfx::Rect(0, 0, 20, 20), root_window()));
1021 CaptureWindowDelegateImpl delegate2;
1022 scoped_ptr<Window> w2(CreateTestWindowWithDelegate(
1023 &delegate2, 0, gfx::Rect(20, 20, 20, 20), root_window()));
1025 // Execute the scheduled draws so that mouse events are not
1026 // aggregated.
1027 RunAllPendingInMessageLoop();
1029 EXPECT_FALSE(window->HasCapture());
1031 // Do a capture.
1032 delegate.ResetCounts();
1033 window->SetCapture();
1034 EXPECT_TRUE(window->HasCapture());
1035 EXPECT_EQ(0, delegate.capture_lost_count());
1036 EXPECT_EQ(0, delegate.capture_changed_event_count());
1037 EventGenerator generator(root_window(), gfx::Point(50, 50));
1038 generator.PressLeftButton();
1039 EXPECT_EQ(0, delegate.capture_lost_count());
1040 EXPECT_EQ(0, delegate.capture_changed_event_count());
1041 EXPECT_EQ(1, delegate.mouse_event_count());
1043 // Set capture to |w2|, should implicitly unset capture for |window|.
1044 delegate.ResetCounts();
1045 delegate2.ResetCounts();
1046 w2->SetCapture();
1048 generator.MoveMouseTo(gfx::Point(40, 40), 2);
1049 EXPECT_EQ(1, delegate.capture_lost_count());
1050 EXPECT_EQ(1, delegate.capture_changed_event_count());
1051 EXPECT_EQ(1, delegate.mouse_event_count());
1052 EXPECT_EQ(2, delegate2.mouse_event_count());
1055 // Verifies capture is reset when a window is destroyed.
1056 TEST_F(WindowTest, ReleaseCaptureOnDestroy) {
1057 CaptureWindowDelegateImpl delegate;
1058 scoped_ptr<Window> window(CreateTestWindowWithDelegate(
1059 &delegate, 0, gfx::Rect(0, 0, 20, 20), root_window()));
1060 EXPECT_FALSE(window->HasCapture());
1062 // Do a capture.
1063 window->SetCapture();
1064 EXPECT_TRUE(window->HasCapture());
1066 // Destroy the window.
1067 window.reset();
1069 // Make sure the root window doesn't reference the window anymore.
1070 EXPECT_EQ(NULL, root_window()->mouse_pressed_handler());
1071 EXPECT_EQ(NULL, aura::client::GetCaptureWindow(root_window()));
1074 TEST_F(WindowTest, GetBoundsInRootWindow) {
1075 scoped_ptr<Window> viewport(CreateTestWindowWithBounds(
1076 gfx::Rect(0, 0, 300, 300), root_window()));
1077 scoped_ptr<Window> child(CreateTestWindowWithBounds(
1078 gfx::Rect(0, 0, 100, 100), viewport.get()));
1079 // Sanity check.
1080 EXPECT_EQ("0,0 100x100", child->GetBoundsInRootWindow().ToString());
1082 // The |child| window's screen bounds should move along with the |viewport|.
1083 viewport->SetBounds(gfx::Rect(-100, -100, 300, 300));
1084 EXPECT_EQ("-100,-100 100x100", child->GetBoundsInRootWindow().ToString());
1086 // The |child| window is moved to the 0,0 in screen coordinates.
1087 // |GetBoundsInRootWindow()| should return 0,0.
1088 child->SetBounds(gfx::Rect(100, 100, 100, 100));
1089 EXPECT_EQ("0,0 100x100", child->GetBoundsInRootWindow().ToString());
1092 class MouseEnterExitWindowDelegate : public TestWindowDelegate {
1093 public:
1094 MouseEnterExitWindowDelegate() : entered_(false), exited_(false) {}
1096 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
1097 switch (event->type()) {
1098 case ui::ET_MOUSE_ENTERED:
1099 entered_ = true;
1100 break;
1101 case ui::ET_MOUSE_EXITED:
1102 exited_ = true;
1103 break;
1104 default:
1105 break;
1109 bool entered() const { return entered_; }
1110 bool exited() const { return exited_; }
1112 // Clear the entered / exited states.
1113 void ResetExpectations() {
1114 entered_ = false;
1115 exited_ = false;
1118 private:
1119 bool entered_;
1120 bool exited_;
1122 DISALLOW_COPY_AND_ASSIGN(MouseEnterExitWindowDelegate);
1126 // Verifies that the WindowDelegate receives MouseExit and MouseEnter events for
1127 // mouse transitions from window to window.
1128 TEST_F(WindowTest, MouseEnterExit) {
1129 MouseEnterExitWindowDelegate d1;
1130 scoped_ptr<Window> w1(
1131 CreateTestWindowWithDelegate(&d1, 1, gfx::Rect(10, 10, 50, 50),
1132 root_window()));
1133 MouseEnterExitWindowDelegate d2;
1134 scoped_ptr<Window> w2(
1135 CreateTestWindowWithDelegate(&d2, 2, gfx::Rect(70, 70, 50, 50),
1136 root_window()));
1138 test::EventGenerator generator(root_window());
1139 generator.MoveMouseToCenterOf(w1.get());
1140 EXPECT_TRUE(d1.entered());
1141 EXPECT_FALSE(d1.exited());
1142 EXPECT_FALSE(d2.entered());
1143 EXPECT_FALSE(d2.exited());
1145 generator.MoveMouseToCenterOf(w2.get());
1146 EXPECT_TRUE(d1.entered());
1147 EXPECT_TRUE(d1.exited());
1148 EXPECT_TRUE(d2.entered());
1149 EXPECT_FALSE(d2.exited());
1152 // Verifies that the WindowDelegate receives MouseExit from ET_MOUSE_EXITED.
1153 TEST_F(WindowTest, RootWindowHostExit) {
1154 MouseEnterExitWindowDelegate d1;
1155 scoped_ptr<Window> w1(
1156 CreateTestWindowWithDelegate(&d1, 1, gfx::Rect(10, 10, 50, 50),
1157 root_window()));
1159 test::EventGenerator generator(root_window());
1160 generator.MoveMouseToCenterOf(w1.get());
1161 EXPECT_TRUE(d1.entered());
1162 EXPECT_FALSE(d1.exited());
1163 d1.ResetExpectations();
1165 ui::MouseEvent exit_event(
1166 ui::ET_MOUSE_EXITED, gfx::Point(), gfx::Point(), 0);
1167 root_window()->AsRootWindowHostDelegate()->OnHostMouseEvent(&exit_event);
1168 EXPECT_FALSE(d1.entered());
1169 EXPECT_TRUE(d1.exited());
1172 // Verifies that the WindowDelegate receives MouseExit and MouseEnter events for
1173 // mouse transitions from window to window, even if the entered window sets
1174 // and releases capture.
1175 TEST_F(WindowTest, MouseEnterExitWithClick) {
1176 MouseEnterExitWindowDelegate d1;
1177 scoped_ptr<Window> w1(
1178 CreateTestWindowWithDelegate(&d1, 1, gfx::Rect(10, 10, 50, 50),
1179 root_window()));
1180 MouseEnterExitWindowDelegate d2;
1181 scoped_ptr<Window> w2(
1182 CreateTestWindowWithDelegate(&d2, 2, gfx::Rect(70, 70, 50, 50),
1183 root_window()));
1185 test::EventGenerator generator(root_window());
1186 generator.MoveMouseToCenterOf(w1.get());
1187 EXPECT_TRUE(d1.entered());
1188 EXPECT_FALSE(d1.exited());
1189 EXPECT_FALSE(d2.entered());
1190 EXPECT_FALSE(d2.exited());
1192 // Emmulate what Views does on a click by grabbing and releasing capture.
1193 generator.PressLeftButton();
1194 w1->SetCapture();
1195 w1->ReleaseCapture();
1196 generator.ReleaseLeftButton();
1198 generator.MoveMouseToCenterOf(w2.get());
1199 EXPECT_TRUE(d1.entered());
1200 EXPECT_TRUE(d1.exited());
1201 EXPECT_TRUE(d2.entered());
1202 EXPECT_FALSE(d2.exited());
1205 // Verifies that enter / exits are sent if windows appear and are deleted
1206 // under the current mouse position..
1207 TEST_F(WindowTest, MouseEnterExitWithDelete) {
1208 MouseEnterExitWindowDelegate d1;
1209 scoped_ptr<Window> w1(
1210 CreateTestWindowWithDelegate(&d1, 1, gfx::Rect(10, 10, 50, 50),
1211 root_window()));
1213 test::EventGenerator generator(root_window());
1214 generator.MoveMouseToCenterOf(w1.get());
1215 EXPECT_TRUE(d1.entered());
1216 EXPECT_FALSE(d1.exited());
1219 MouseEnterExitWindowDelegate d2;
1220 scoped_ptr<Window> w2(
1221 CreateTestWindowWithDelegate(&d2, 2, gfx::Rect(10, 10, 50, 50),
1222 root_window()));
1223 // Enters / exits can be send asynchronously.
1224 RunAllPendingInMessageLoop();
1225 EXPECT_TRUE(d1.entered());
1226 EXPECT_TRUE(d1.exited());
1227 EXPECT_TRUE(d2.entered());
1228 EXPECT_FALSE(d2.exited());
1229 d1.ResetExpectations();
1231 // Enters / exits can be send asynchronously.
1232 RunAllPendingInMessageLoop();
1233 EXPECT_TRUE(d1.entered());
1236 // Verifies that enter / exits are sent if windows appear and are hidden
1237 // under the current mouse position..
1238 TEST_F(WindowTest, MouseEnterExitWithHide) {
1239 MouseEnterExitWindowDelegate d1;
1240 scoped_ptr<Window> w1(
1241 CreateTestWindowWithDelegate(&d1, 1, gfx::Rect(10, 10, 50, 50),
1242 root_window()));
1244 test::EventGenerator generator(root_window());
1245 generator.MoveMouseToCenterOf(w1.get());
1246 EXPECT_TRUE(d1.entered());
1247 EXPECT_FALSE(d1.exited());
1249 MouseEnterExitWindowDelegate d2;
1250 scoped_ptr<Window> w2(
1251 CreateTestWindowWithDelegate(&d2, 2, gfx::Rect(10, 10, 50, 50),
1252 root_window()));
1253 // Enters / exits can be send asynchronously.
1254 RunAllPendingInMessageLoop();
1255 EXPECT_TRUE(d1.entered());
1256 EXPECT_TRUE(d1.exited());
1257 EXPECT_TRUE(d2.entered());
1258 EXPECT_FALSE(d2.exited());
1260 d1.ResetExpectations();
1261 w2->Hide();
1262 // Enters / exits can be send asynchronously.
1263 RunAllPendingInMessageLoop();
1264 EXPECT_TRUE(d1.entered());
1267 // Creates a window with a delegate (w111) that can handle events at a lower
1268 // z-index than a window without a delegate (w12). w12 is sized to fill the
1269 // entire bounds of the container. This test verifies that
1270 // GetEventHandlerForPoint() skips w12 even though its bounds contain the event,
1271 // because it has no children that can handle the event and it has no delegate
1272 // allowing it to handle the event itself.
1273 TEST_F(WindowTest, GetEventHandlerForPoint_NoDelegate) {
1274 TestWindowDelegate d111;
1275 scoped_ptr<Window> w1(CreateTestWindowWithDelegate(NULL, 1,
1276 gfx::Rect(0, 0, 500, 500), root_window()));
1277 scoped_ptr<Window> w11(CreateTestWindowWithDelegate(NULL, 11,
1278 gfx::Rect(0, 0, 500, 500), w1.get()));
1279 scoped_ptr<Window> w111(CreateTestWindowWithDelegate(&d111, 111,
1280 gfx::Rect(50, 50, 450, 450), w11.get()));
1281 scoped_ptr<Window> w12(CreateTestWindowWithDelegate(NULL, 12,
1282 gfx::Rect(0, 0, 500, 500), w1.get()));
1284 gfx::Point target_point = w111->bounds().CenterPoint();
1285 EXPECT_EQ(w111.get(), w1->GetEventHandlerForPoint(target_point));
1288 class VisibilityWindowDelegate : public TestWindowDelegate {
1289 public:
1290 VisibilityWindowDelegate()
1291 : shown_(0),
1292 hidden_(0) {
1295 int shown() const { return shown_; }
1296 int hidden() const { return hidden_; }
1297 void Clear() {
1298 shown_ = 0;
1299 hidden_ = 0;
1302 virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE {
1303 if (visible)
1304 shown_++;
1305 else
1306 hidden_++;
1309 private:
1310 int shown_;
1311 int hidden_;
1313 DISALLOW_COPY_AND_ASSIGN(VisibilityWindowDelegate);
1316 // Verifies show/hide propagate correctly to children and the layer.
1317 TEST_F(WindowTest, Visibility) {
1318 VisibilityWindowDelegate d;
1319 VisibilityWindowDelegate d2;
1320 scoped_ptr<Window> w1(CreateTestWindowWithDelegate(&d, 1, gfx::Rect(),
1321 root_window()));
1322 scoped_ptr<Window> w2(
1323 CreateTestWindowWithDelegate(&d2, 2, gfx::Rect(), w1.get()));
1324 scoped_ptr<Window> w3(CreateTestWindowWithId(3, w2.get()));
1326 // Create shows all the windows.
1327 EXPECT_TRUE(w1->IsVisible());
1328 EXPECT_TRUE(w2->IsVisible());
1329 EXPECT_TRUE(w3->IsVisible());
1330 EXPECT_EQ(1, d.shown());
1332 d.Clear();
1333 w1->Hide();
1334 EXPECT_FALSE(w1->IsVisible());
1335 EXPECT_FALSE(w2->IsVisible());
1336 EXPECT_FALSE(w3->IsVisible());
1337 EXPECT_EQ(1, d.hidden());
1338 EXPECT_EQ(0, d.shown());
1340 w2->Show();
1341 EXPECT_FALSE(w1->IsVisible());
1342 EXPECT_FALSE(w2->IsVisible());
1343 EXPECT_FALSE(w3->IsVisible());
1345 w3->Hide();
1346 EXPECT_FALSE(w1->IsVisible());
1347 EXPECT_FALSE(w2->IsVisible());
1348 EXPECT_FALSE(w3->IsVisible());
1350 d.Clear();
1351 w1->Show();
1352 EXPECT_TRUE(w1->IsVisible());
1353 EXPECT_TRUE(w2->IsVisible());
1354 EXPECT_FALSE(w3->IsVisible());
1355 EXPECT_EQ(0, d.hidden());
1356 EXPECT_EQ(1, d.shown());
1358 w3->Show();
1359 EXPECT_TRUE(w1->IsVisible());
1360 EXPECT_TRUE(w2->IsVisible());
1361 EXPECT_TRUE(w3->IsVisible());
1363 // Verify that if an ancestor isn't visible and we change the visibility of a
1364 // child window that OnChildWindowVisibilityChanged() is still invoked.
1365 w1->Hide();
1366 d2.Clear();
1367 w2->Hide();
1368 EXPECT_EQ(1, d2.hidden());
1369 EXPECT_EQ(0, d2.shown());
1370 d2.Clear();
1371 w2->Show();
1372 EXPECT_EQ(0, d2.hidden());
1373 EXPECT_EQ(1, d2.shown());
1376 TEST_F(WindowTest, IgnoreEventsTest) {
1377 TestWindowDelegate d11;
1378 TestWindowDelegate d12;
1379 TestWindowDelegate d111;
1380 TestWindowDelegate d121;
1381 scoped_ptr<Window> w1(CreateTestWindowWithDelegate(NULL, 1,
1382 gfx::Rect(0, 0, 500, 500), root_window()));
1383 scoped_ptr<Window> w11(CreateTestWindowWithDelegate(&d11, 11,
1384 gfx::Rect(0, 0, 500, 500), w1.get()));
1385 scoped_ptr<Window> w111(CreateTestWindowWithDelegate(&d111, 111,
1386 gfx::Rect(50, 50, 450, 450), w11.get()));
1387 scoped_ptr<Window> w12(CreateTestWindowWithDelegate(&d12, 12,
1388 gfx::Rect(0, 0, 500, 500), w1.get()));
1389 scoped_ptr<Window> w121(CreateTestWindowWithDelegate(&d121, 121,
1390 gfx::Rect(150, 150, 50, 50), w12.get()));
1392 EXPECT_EQ(w12.get(), w1->GetEventHandlerForPoint(gfx::Point(10, 10)));
1393 w12->set_ignore_events(true);
1394 EXPECT_EQ(w11.get(), w1->GetEventHandlerForPoint(gfx::Point(10, 10)));
1395 w12->set_ignore_events(false);
1397 EXPECT_EQ(w121.get(), w1->GetEventHandlerForPoint(gfx::Point(160, 160)));
1398 w121->set_ignore_events(true);
1399 EXPECT_EQ(w12.get(), w1->GetEventHandlerForPoint(gfx::Point(160, 160)));
1400 w12->set_ignore_events(true);
1401 EXPECT_EQ(w111.get(), w1->GetEventHandlerForPoint(gfx::Point(160, 160)));
1402 w111->set_ignore_events(true);
1403 EXPECT_EQ(w11.get(), w1->GetEventHandlerForPoint(gfx::Point(160, 160)));
1406 // Tests transformation on the root window.
1407 TEST_F(WindowTest, Transform) {
1408 gfx::Size size = root_window()->GetHostSize();
1409 EXPECT_EQ(gfx::Rect(size),
1410 gfx::Screen::GetScreenFor(root_window())->GetDisplayNearestPoint(
1411 gfx::Point()).bounds());
1413 // Rotate it clock-wise 90 degrees.
1414 gfx::Transform transform;
1415 transform.Translate(size.height(), 0);
1416 transform.Rotate(90.0);
1417 root_window()->SetTransform(transform);
1419 // The size should be the transformed size.
1420 gfx::Size transformed_size(size.height(), size.width());
1421 EXPECT_EQ(transformed_size.ToString(),
1422 root_window()->bounds().size().ToString());
1423 EXPECT_EQ(
1424 gfx::Rect(transformed_size).ToString(),
1425 gfx::Screen::GetScreenFor(root_window())->GetDisplayNearestPoint(
1426 gfx::Point()).bounds().ToString());
1428 // Host size shouldn't change.
1429 EXPECT_EQ(size.ToString(),
1430 root_window()->GetHostSize().ToString());
1433 TEST_F(WindowTest, TransformGesture) {
1434 gfx::Size size = root_window()->GetHostSize();
1436 scoped_ptr<GestureTrackPositionDelegate> delegate(
1437 new GestureTrackPositionDelegate);
1438 scoped_ptr<Window> window(CreateTestWindowWithDelegate(delegate.get(), -1234,
1439 gfx::Rect(0, 0, 20, 20), root_window()));
1441 // Rotate the root-window clock-wise 90 degrees.
1442 gfx::Transform transform;
1443 transform.Translate(size.height(), 0.0);
1444 transform.Rotate(90.0);
1445 root_window()->SetTransform(transform);
1447 ui::TouchEvent press(
1448 ui::ET_TOUCH_PRESSED, gfx::Point(size.height() - 10, 10), 0, getTime());
1449 root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
1450 EXPECT_EQ(gfx::Point(10, 10).ToString(), delegate->position().ToString());
1453 // Various assertions for transient children.
1454 TEST_F(WindowTest, TransientChildren) {
1455 scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
1456 scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
1457 scoped_ptr<Window> w3(CreateTestWindowWithId(3, parent.get()));
1458 Window* w2 = CreateTestWindowWithId(2, parent.get());
1459 w1->AddTransientChild(w2); // w2 is now owned by w1.
1460 // Stack w1 at the top (end), this should force w2 to be last (on top of w1).
1461 parent->StackChildAtTop(w1.get());
1462 ASSERT_EQ(3u, parent->children().size());
1463 EXPECT_EQ(w2, parent->children().back());
1465 // Destroy w1, which should also destroy w3 (since it's a transient child).
1466 w1.reset();
1467 w2 = NULL;
1468 ASSERT_EQ(1u, parent->children().size());
1469 EXPECT_EQ(w3.get(), parent->children()[0]);
1471 w1.reset(CreateTestWindowWithId(4, parent.get()));
1472 w2 = CreateTestWindowWithId(5, w3.get());
1473 w1->AddTransientChild(w2);
1474 parent->StackChildAtTop(w3.get());
1475 // Stack w1 at the top (end), this shouldn't affect w2 since it has a
1476 // different parent.
1477 parent->StackChildAtTop(w1.get());
1478 ASSERT_EQ(2u, parent->children().size());
1479 EXPECT_EQ(w3.get(), parent->children()[0]);
1480 EXPECT_EQ(w1.get(), parent->children()[1]);
1482 // Hiding parent should hide transient children.
1483 EXPECT_TRUE(w2->IsVisible());
1484 w1->Hide();
1485 EXPECT_FALSE(w2->IsVisible());
1488 // Tests that when a focused window is closed, its parent inherits the focus.
1489 TEST_F(WindowTest, FocusedWindowTest) {
1490 scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
1491 scoped_ptr<Window> child(CreateTestWindowWithId(1, parent.get()));
1493 parent->Show();
1495 child->Focus();
1496 EXPECT_TRUE(child->HasFocus());
1497 EXPECT_FALSE(parent->HasFocus());
1499 child.reset();
1500 EXPECT_TRUE(parent->HasFocus());
1503 // Tests that the previously-focused window is passed to OnWindowFocused.
1504 // TODO(beng): Remove once the FocusController lands.
1505 TEST_F(WindowTest, OldFocusedWindowTest) {
1506 const gfx::Rect kBounds(0, 0, 100, 100);
1508 FocusDelegate delegate1;
1509 scoped_ptr<Window> window1(
1510 CreateTestWindowWithDelegate(&delegate1, 0, kBounds, root_window()));
1511 client::SetFocusChangeObserver(window1.get(), &delegate1);
1512 window1->Focus();
1513 ASSERT_TRUE(window1->HasFocus());
1514 EXPECT_TRUE(delegate1.previous_focused_window() == NULL);
1516 FocusDelegate delegate2;
1517 scoped_ptr<Window> window2(
1518 CreateTestWindowWithDelegate(&delegate2, 1, kBounds, root_window()));
1519 client::SetFocusChangeObserver(window2.get(), &delegate2);
1520 window2->Focus();
1521 ASSERT_TRUE(window2->HasFocus());
1522 EXPECT_FALSE(window1->HasFocus());
1523 EXPECT_EQ(window1.get(), delegate2.previous_focused_window());
1526 namespace {
1527 DEFINE_WINDOW_PROPERTY_KEY(int, kIntKey, -2);
1528 DEFINE_WINDOW_PROPERTY_KEY(const char*, kStringKey, "squeamish");
1531 TEST_F(WindowTest, Property) {
1532 scoped_ptr<Window> w(CreateTestWindowWithId(0, root_window()));
1534 static const char native_prop_key[] = "fnord";
1536 // Non-existent properties should return the default values.
1537 EXPECT_EQ(-2, w->GetProperty(kIntKey));
1538 EXPECT_EQ(std::string("squeamish"), w->GetProperty(kStringKey));
1539 EXPECT_EQ(NULL, w->GetNativeWindowProperty(native_prop_key));
1541 // A set property value should be returned again (even if it's the default
1542 // value).
1543 w->SetProperty(kIntKey, INT_MAX);
1544 EXPECT_EQ(INT_MAX, w->GetProperty(kIntKey));
1545 w->SetProperty(kIntKey, -2);
1546 EXPECT_EQ(-2, w->GetProperty(kIntKey));
1547 w->SetProperty(kIntKey, INT_MIN);
1548 EXPECT_EQ(INT_MIN, w->GetProperty(kIntKey));
1550 w->SetProperty(kStringKey, static_cast<const char*>(NULL));
1551 EXPECT_EQ(NULL, w->GetProperty(kStringKey));
1552 w->SetProperty(kStringKey, "squeamish");
1553 EXPECT_EQ(std::string("squeamish"), w->GetProperty(kStringKey));
1554 w->SetProperty(kStringKey, "ossifrage");
1555 EXPECT_EQ(std::string("ossifrage"), w->GetProperty(kStringKey));
1557 w->SetNativeWindowProperty(native_prop_key, &*w);
1558 EXPECT_EQ(&*w, w->GetNativeWindowProperty(native_prop_key));
1559 w->SetNativeWindowProperty(native_prop_key, NULL);
1560 EXPECT_EQ(NULL, w->GetNativeWindowProperty(native_prop_key));
1562 // ClearProperty should restore the default value.
1563 w->ClearProperty(kIntKey);
1564 EXPECT_EQ(-2, w->GetProperty(kIntKey));
1565 w->ClearProperty(kStringKey);
1566 EXPECT_EQ(std::string("squeamish"), w->GetProperty(kStringKey));
1569 namespace {
1571 class TestProperty {
1572 public:
1573 TestProperty() {}
1574 virtual ~TestProperty() {
1575 last_deleted_ = this;
1577 static TestProperty* last_deleted() { return last_deleted_; }
1579 private:
1580 static TestProperty* last_deleted_;
1581 DISALLOW_COPY_AND_ASSIGN(TestProperty);
1584 TestProperty* TestProperty::last_deleted_ = NULL;
1586 DEFINE_OWNED_WINDOW_PROPERTY_KEY(TestProperty, kOwnedKey, NULL);
1588 } // namespace
1590 TEST_F(WindowTest, OwnedProperty) {
1591 scoped_ptr<Window> w(CreateTestWindowWithId(0, root_window()));
1592 EXPECT_EQ(NULL, w->GetProperty(kOwnedKey));
1593 TestProperty* p1 = new TestProperty();
1594 w->SetProperty(kOwnedKey, p1);
1595 EXPECT_EQ(p1, w->GetProperty(kOwnedKey));
1596 EXPECT_EQ(NULL, TestProperty::last_deleted());
1598 TestProperty* p2 = new TestProperty();
1599 w->SetProperty(kOwnedKey, p2);
1600 EXPECT_EQ(p2, w->GetProperty(kOwnedKey));
1601 EXPECT_EQ(p1, TestProperty::last_deleted());
1603 w->ClearProperty(kOwnedKey);
1604 EXPECT_EQ(NULL, w->GetProperty(kOwnedKey));
1605 EXPECT_EQ(p2, TestProperty::last_deleted());
1607 TestProperty* p3 = new TestProperty();
1608 w->SetProperty(kOwnedKey, p3);
1609 EXPECT_EQ(p3, w->GetProperty(kOwnedKey));
1610 EXPECT_EQ(p2, TestProperty::last_deleted());
1611 w.reset();
1612 EXPECT_EQ(p3, TestProperty::last_deleted());
1615 TEST_F(WindowTest, SetBoundsInternalShouldCheckTargetBounds) {
1616 // We cannot short-circuit animations in this test.
1617 ui::ScopedAnimationDurationScaleMode normal_duration_mode(
1618 ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
1620 scoped_ptr<Window> w1(
1621 CreateTestWindowWithBounds(gfx::Rect(0, 0, 100, 100), root_window()));
1623 EXPECT_FALSE(!w1->layer());
1624 w1->layer()->GetAnimator()->set_disable_timer_for_test(true);
1625 ui::AnimationContainerElement* element = w1->layer()->GetAnimator();
1627 EXPECT_EQ("0,0 100x100", w1->bounds().ToString());
1628 EXPECT_EQ("0,0 100x100", w1->layer()->GetTargetBounds().ToString());
1630 // Animate to a different position.
1632 ui::ScopedLayerAnimationSettings settings(w1->layer()->GetAnimator());
1633 w1->SetBounds(gfx::Rect(100, 100, 100, 100));
1636 EXPECT_EQ("0,0 100x100", w1->bounds().ToString());
1637 EXPECT_EQ("100,100 100x100", w1->layer()->GetTargetBounds().ToString());
1639 // Animate back to the first position. The animation hasn't started yet, so
1640 // the current bounds are still (0, 0, 100, 100), but the target bounds are
1641 // (100, 100, 100, 100). If we step the animator ahead, we should find that
1642 // we're at (0, 0, 100, 100). That is, the second animation should be applied.
1644 ui::ScopedLayerAnimationSettings settings(w1->layer()->GetAnimator());
1645 w1->SetBounds(gfx::Rect(0, 0, 100, 100));
1648 EXPECT_EQ("0,0 100x100", w1->bounds().ToString());
1649 EXPECT_EQ("0,0 100x100", w1->layer()->GetTargetBounds().ToString());
1651 // Confirm that the target bounds are reached.
1652 base::TimeTicks start_time =
1653 w1->layer()->GetAnimator()->last_step_time();
1655 element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
1657 EXPECT_EQ("0,0 100x100", w1->bounds().ToString());
1661 typedef std::pair<const void*, intptr_t> PropertyChangeInfo;
1663 class WindowObserverTest : public WindowTest,
1664 public WindowObserver {
1665 public:
1666 struct VisibilityInfo {
1667 bool window_visible;
1668 bool visible_param;
1671 WindowObserverTest()
1672 : added_count_(0),
1673 removed_count_(0),
1674 destroyed_count_(0),
1675 old_property_value_(-3) {
1678 virtual ~WindowObserverTest() {}
1680 const VisibilityInfo* GetVisibilityInfo() const {
1681 return visibility_info_.get();
1684 void ResetVisibilityInfo() {
1685 visibility_info_.reset();
1688 // Returns a description of the WindowObserver methods that have been invoked.
1689 std::string WindowObserverCountStateAndClear() {
1690 std::string result(
1691 base::StringPrintf("added=%d removed=%d",
1692 added_count_, removed_count_));
1693 added_count_ = removed_count_ = 0;
1694 return result;
1697 int DestroyedCountAndClear() {
1698 int result = destroyed_count_;
1699 destroyed_count_ = 0;
1700 return result;
1703 // Return a tuple of the arguments passed in OnPropertyChanged callback.
1704 PropertyChangeInfo PropertyChangeInfoAndClear() {
1705 PropertyChangeInfo result(property_key_, old_property_value_);
1706 property_key_ = NULL;
1707 old_property_value_ = -3;
1708 return result;
1711 private:
1712 virtual void OnWindowAdded(Window* new_window) OVERRIDE {
1713 added_count_++;
1716 virtual void OnWillRemoveWindow(Window* window) OVERRIDE {
1717 removed_count_++;
1720 virtual void OnWindowVisibilityChanged(Window* window,
1721 bool visible) OVERRIDE {
1722 visibility_info_.reset(new VisibilityInfo);
1723 visibility_info_->window_visible = window->IsVisible();
1724 visibility_info_->visible_param = visible;
1727 virtual void OnWindowDestroyed(Window* window) OVERRIDE {
1728 EXPECT_FALSE(window->parent());
1729 destroyed_count_++;
1732 virtual void OnWindowPropertyChanged(Window* window,
1733 const void* key,
1734 intptr_t old) OVERRIDE {
1735 property_key_ = key;
1736 old_property_value_ = old;
1739 int added_count_;
1740 int removed_count_;
1741 int destroyed_count_;
1742 scoped_ptr<VisibilityInfo> visibility_info_;
1743 const void* property_key_;
1744 intptr_t old_property_value_;
1746 DISALLOW_COPY_AND_ASSIGN(WindowObserverTest);
1749 // Various assertions for WindowObserver.
1750 TEST_F(WindowObserverTest, WindowObserver) {
1751 scoped_ptr<Window> w1(CreateTestWindowWithId(1, root_window()));
1752 w1->AddObserver(this);
1754 // Create a new window as a child of w1, our observer should be notified.
1755 scoped_ptr<Window> w2(CreateTestWindowWithId(2, w1.get()));
1756 EXPECT_EQ("added=1 removed=0", WindowObserverCountStateAndClear());
1758 // Delete w2, which should result in the remove notification.
1759 w2.reset();
1760 EXPECT_EQ("added=0 removed=1", WindowObserverCountStateAndClear());
1762 // Create a window that isn't parented to w1, we shouldn't get any
1763 // notification.
1764 scoped_ptr<Window> w3(CreateTestWindowWithId(3, root_window()));
1765 EXPECT_EQ("added=0 removed=0", WindowObserverCountStateAndClear());
1767 // Similarly destroying w3 shouldn't notify us either.
1768 w3.reset();
1769 EXPECT_EQ("added=0 removed=0", WindowObserverCountStateAndClear());
1770 w1->RemoveObserver(this);
1773 // Test if OnWindowVisibilityChagned is invoked with expected
1774 // parameters.
1775 TEST_F(WindowObserverTest, WindowVisibility) {
1776 scoped_ptr<Window> w1(CreateTestWindowWithId(1, root_window()));
1777 scoped_ptr<Window> w2(CreateTestWindowWithId(1, w1.get()));
1778 w2->AddObserver(this);
1780 // Hide should make the window invisible and the passed visible
1781 // parameter is false.
1782 w2->Hide();
1783 EXPECT_FALSE(!GetVisibilityInfo());
1784 EXPECT_FALSE(!GetVisibilityInfo());
1785 if (!GetVisibilityInfo())
1786 return;
1787 EXPECT_FALSE(GetVisibilityInfo()->window_visible);
1788 EXPECT_FALSE(GetVisibilityInfo()->visible_param);
1790 // If parent isn't visible, showing window won't make the window visible, but
1791 // passed visible value must be true.
1792 w1->Hide();
1793 ResetVisibilityInfo();
1794 EXPECT_TRUE(!GetVisibilityInfo());
1795 w2->Show();
1796 EXPECT_FALSE(!GetVisibilityInfo());
1797 if (!GetVisibilityInfo())
1798 return;
1799 EXPECT_FALSE(GetVisibilityInfo()->window_visible);
1800 EXPECT_TRUE(GetVisibilityInfo()->visible_param);
1802 // If parent is visible, showing window will make the window
1803 // visible and the passed visible value is true.
1804 w1->Show();
1805 w2->Hide();
1806 ResetVisibilityInfo();
1807 w2->Show();
1808 EXPECT_FALSE(!GetVisibilityInfo());
1809 if (!GetVisibilityInfo())
1810 return;
1811 EXPECT_TRUE(GetVisibilityInfo()->window_visible);
1812 EXPECT_TRUE(GetVisibilityInfo()->visible_param);
1815 // Test if OnWindowDestroyed is invoked as expected.
1816 TEST_F(WindowObserverTest, WindowDestroyed) {
1817 // Delete a window should fire a destroyed notification.
1818 scoped_ptr<Window> w1(CreateTestWindowWithId(1, root_window()));
1819 w1->AddObserver(this);
1820 w1.reset();
1821 EXPECT_EQ(1, DestroyedCountAndClear());
1823 // Observe on child and delete parent window should fire a notification.
1824 scoped_ptr<Window> parent(CreateTestWindowWithId(1, root_window()));
1825 Window* child = CreateTestWindowWithId(1, parent.get()); // owned by parent
1826 child->AddObserver(this);
1827 parent.reset();
1828 EXPECT_EQ(1, DestroyedCountAndClear());
1831 TEST_F(WindowObserverTest, PropertyChanged) {
1832 // Setting property should fire a property change notification.
1833 scoped_ptr<Window> w1(CreateTestWindowWithId(1, root_window()));
1834 w1->AddObserver(this);
1836 static const WindowProperty<int> prop = {-2};
1837 static const char native_prop_key[] = "fnord";
1839 w1->SetProperty(&prop, 1);
1840 EXPECT_EQ(PropertyChangeInfo(&prop, -2), PropertyChangeInfoAndClear());
1841 w1->SetProperty(&prop, -2);
1842 EXPECT_EQ(PropertyChangeInfo(&prop, 1), PropertyChangeInfoAndClear());
1843 w1->SetProperty(&prop, 3);
1844 EXPECT_EQ(PropertyChangeInfo(&prop, -2), PropertyChangeInfoAndClear());
1845 w1->ClearProperty(&prop);
1846 EXPECT_EQ(PropertyChangeInfo(&prop, 3), PropertyChangeInfoAndClear());
1848 w1->SetNativeWindowProperty(native_prop_key, &*w1);
1849 EXPECT_EQ(PropertyChangeInfo(native_prop_key, 0),
1850 PropertyChangeInfoAndClear());
1851 w1->SetNativeWindowProperty(native_prop_key, NULL);
1852 EXPECT_EQ(PropertyChangeInfo(native_prop_key,
1853 reinterpret_cast<intptr_t>(&*w1)),
1854 PropertyChangeInfoAndClear());
1856 // Sanity check to see if |PropertyChangeInfoAndClear| really clears.
1857 EXPECT_EQ(PropertyChangeInfo(
1858 reinterpret_cast<const void*>(NULL), -3), PropertyChangeInfoAndClear());
1861 TEST_F(WindowTest, AcquireLayer) {
1862 scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
1863 scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window()));
1864 ui::Layer* parent = window1->parent()->layer();
1865 EXPECT_EQ(2U, parent->children().size());
1867 WindowTestApi window1_test_api(window1.get());
1868 WindowTestApi window2_test_api(window2.get());
1870 EXPECT_TRUE(window1_test_api.OwnsLayer());
1871 EXPECT_TRUE(window2_test_api.OwnsLayer());
1873 // After acquisition, window1 should not own its layer, but it should still
1874 // be available to the window.
1875 scoped_ptr<ui::Layer> window1_layer(window1->AcquireLayer());
1876 EXPECT_FALSE(window1_test_api.OwnsLayer());
1877 EXPECT_TRUE(window1_layer.get() == window1->layer());
1879 // Upon destruction, window1's layer should still be valid, and in the layer
1880 // hierarchy, but window2's should be gone, and no longer in the hierarchy.
1881 window1.reset();
1882 window2.reset();
1884 // This should be set by the window's destructor.
1885 EXPECT_TRUE(window1_layer->delegate() == NULL);
1886 EXPECT_EQ(1U, parent->children().size());
1889 // Make sure that properties which should persist from the old layer to the new
1890 // layer actually do.
1891 TEST_F(WindowTest, RecreateLayer) {
1892 // Set properties to non default values.
1893 Window w(new ColorTestWindowDelegate(SK_ColorWHITE));
1894 w.set_id(1);
1895 w.Init(ui::LAYER_SOLID_COLOR);
1896 w.SetBounds(gfx::Rect(0, 0, 100, 100));
1898 ui::Layer* layer = w.layer();
1899 layer->set_scale_content(false);
1900 layer->SetVisible(false);
1901 layer->SetMasksToBounds(true);
1903 ui::Layer child_layer;
1904 layer->Add(&child_layer);
1906 scoped_ptr<ui::Layer> old_layer(w.RecreateLayer());
1907 layer = w.layer();
1908 EXPECT_EQ(ui::LAYER_SOLID_COLOR, layer->type());
1909 EXPECT_FALSE(layer->scale_content());
1910 EXPECT_FALSE(layer->visible());
1911 EXPECT_EQ(1u, layer->children().size());
1912 EXPECT_TRUE(layer->GetMasksToBounds());
1915 // Ensure that acquiring a layer then recreating a layer does not crash
1916 // and that RecreateLayer returns null.
1917 TEST_F(WindowTest, AcquireThenRecreateLayer) {
1918 scoped_ptr<Window> w(
1919 CreateTestWindow(SK_ColorWHITE, 1, gfx::Rect(0, 0, 100, 100),
1920 root_window()));
1921 scoped_ptr<ui::Layer>acquired_layer(w->AcquireLayer());
1922 scoped_ptr<ui::Layer>doubly_acquired_layer(w->RecreateLayer());
1923 EXPECT_EQ(NULL, doubly_acquired_layer.get());
1925 // Destroy window before layer gets destroyed.
1926 w.reset();
1929 TEST_F(WindowTest, StackWindowsWhoseLayersHaveNoDelegate) {
1930 scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
1931 scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window()));
1933 // This brings window1 (and its layer) to the front.
1934 root_window()->StackChildAbove(window1.get(), window2.get());
1935 EXPECT_EQ(root_window()->children().front(), window2.get());
1936 EXPECT_EQ(root_window()->children().back(), window1.get());
1937 EXPECT_EQ(root_window()->layer()->children().front(), window2->layer());
1938 EXPECT_EQ(root_window()->layer()->children().back(), window1->layer());
1940 // Since window1 does not have a delegate, window2 should not move in
1941 // front of it, nor should its layer.
1942 window1->layer()->set_delegate(NULL);
1943 root_window()->StackChildAbove(window2.get(), window1.get());
1944 EXPECT_EQ(root_window()->children().front(), window2.get());
1945 EXPECT_EQ(root_window()->children().back(), window1.get());
1946 EXPECT_EQ(root_window()->layer()->children().front(), window2->layer());
1947 EXPECT_EQ(root_window()->layer()->children().back(), window1->layer());
1950 TEST_F(WindowTest, StackTransientsWhoseLayersHaveNoDelegate) {
1951 RootWindow* root = root_window();
1953 // Create a window with several transients, then a couple windows on top.
1954 scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
1955 scoped_ptr<Window> window11(CreateTransientChild(11, window1.get()));
1956 scoped_ptr<Window> window12(CreateTransientChild(12, window1.get()));
1957 scoped_ptr<Window> window13(CreateTransientChild(13, window1.get()));
1958 scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window()));
1959 scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window()));
1961 EXPECT_EQ("1 11 12 13 2 3", ChildWindowIDsAsString(root));
1963 // Remove the delegates of a couple of transients, as if they are closing
1964 // and animating out.
1965 window11->layer()->set_delegate(NULL);
1966 window13->layer()->set_delegate(NULL);
1968 // Move window1 to the front. All transients should move with it, and their
1969 // order should be preserved.
1970 root->StackChildAtTop(window1.get());
1972 EXPECT_EQ("2 3 1 11 12 13", ChildWindowIDsAsString(root));
1975 class TestVisibilityClient : public client::VisibilityClient {
1976 public:
1977 explicit TestVisibilityClient(RootWindow* root_window)
1978 : ignore_visibility_changes_(false) {
1979 client::SetVisibilityClient(root_window, this);
1981 virtual ~TestVisibilityClient() {
1984 void set_ignore_visibility_changes(bool ignore_visibility_changes) {
1985 ignore_visibility_changes_ = ignore_visibility_changes;
1988 // Overridden from client::VisibilityClient:
1989 virtual void UpdateLayerVisibility(aura::Window* window,
1990 bool visible) OVERRIDE {
1991 if (!ignore_visibility_changes_)
1992 window->layer()->SetVisible(visible);
1995 private:
1996 bool ignore_visibility_changes_;
1997 DISALLOW_COPY_AND_ASSIGN(TestVisibilityClient);
2000 TEST_F(WindowTest, VisibilityClientIsVisible) {
2001 TestVisibilityClient client(root_window());
2003 scoped_ptr<Window> window(CreateTestWindowWithId(1, root_window()));
2004 EXPECT_TRUE(window->IsVisible());
2005 EXPECT_TRUE(window->layer()->visible());
2007 window->Hide();
2008 EXPECT_FALSE(window->IsVisible());
2009 EXPECT_FALSE(window->layer()->visible());
2010 window->Show();
2012 client.set_ignore_visibility_changes(true);
2013 window->Hide();
2014 EXPECT_FALSE(window->IsVisible());
2015 EXPECT_TRUE(window->layer()->visible());
2018 // Tests mouse events on window change.
2019 TEST_F(WindowTest, MouseEventsOnWindowChange) {
2020 gfx::Size size = root_window()->GetHostSize();
2022 EventGenerator generator(root_window());
2023 generator.MoveMouseTo(50, 50);
2025 EventCountDelegate d1;
2026 scoped_ptr<Window> w1(CreateTestWindowWithDelegate(&d1, 1,
2027 gfx::Rect(0, 0, 100, 100), root_window()));
2028 RunAllPendingInMessageLoop();
2029 // The format of result is "Enter/Mouse/Leave".
2030 EXPECT_EQ("1 1 0", d1.GetMouseMotionCountsAndReset());
2032 // Adding new window.
2033 EventCountDelegate d11;
2034 scoped_ptr<Window> w11(CreateTestWindowWithDelegate(
2035 &d11, 1, gfx::Rect(0, 0, 100, 100), w1.get()));
2036 RunAllPendingInMessageLoop();
2037 EXPECT_EQ("0 0 1", d1.GetMouseMotionCountsAndReset());
2038 EXPECT_EQ("1 1 0", d11.GetMouseMotionCountsAndReset());
2040 // Move bounds.
2041 w11->SetBounds(gfx::Rect(0, 0, 10, 10));
2042 RunAllPendingInMessageLoop();
2043 EXPECT_EQ("1 1 0", d1.GetMouseMotionCountsAndReset());
2044 EXPECT_EQ("0 0 1", d11.GetMouseMotionCountsAndReset());
2046 w11->SetBounds(gfx::Rect(0, 0, 60, 60));
2047 RunAllPendingInMessageLoop();
2048 EXPECT_EQ("0 0 1", d1.GetMouseMotionCountsAndReset());
2049 EXPECT_EQ("1 1 0", d11.GetMouseMotionCountsAndReset());
2051 // Detach, then re-attach.
2052 w1->RemoveChild(w11.get());
2053 RunAllPendingInMessageLoop();
2054 EXPECT_EQ("1 1 0", d1.GetMouseMotionCountsAndReset());
2055 // Window is detached, so no event is set.
2056 EXPECT_EQ("0 0 0", d11.GetMouseMotionCountsAndReset());
2058 w1->AddChild(w11.get());
2059 RunAllPendingInMessageLoop();
2060 EXPECT_EQ("0 0 1", d1.GetMouseMotionCountsAndReset());
2061 // Window is detached, so no event is set.
2062 EXPECT_EQ("1 1 0", d11.GetMouseMotionCountsAndReset());
2064 // Visibility Change
2065 w11->Hide();
2066 RunAllPendingInMessageLoop();
2067 EXPECT_EQ("1 1 0", d1.GetMouseMotionCountsAndReset());
2068 EXPECT_EQ("0 0 0", d11.GetMouseMotionCountsAndReset());
2070 w11->Show();
2071 RunAllPendingInMessageLoop();
2072 EXPECT_EQ("0 0 1", d1.GetMouseMotionCountsAndReset());
2073 EXPECT_EQ("1 1 0", d11.GetMouseMotionCountsAndReset());
2075 // Transform: move d11 by 100 100.
2076 gfx::Transform transform;
2077 transform.Translate(100, 100);
2078 w11->SetTransform(transform);
2079 RunAllPendingInMessageLoop();
2080 EXPECT_EQ("1 1 0", d1.GetMouseMotionCountsAndReset());
2081 EXPECT_EQ("0 0 1", d11.GetMouseMotionCountsAndReset());
2083 w11->SetTransform(gfx::Transform());
2084 RunAllPendingInMessageLoop();
2085 EXPECT_EQ("0 0 1", d1.GetMouseMotionCountsAndReset());
2086 EXPECT_EQ("1 1 0", d11.GetMouseMotionCountsAndReset());
2088 // Closing a window.
2089 w11.reset();
2090 RunAllPendingInMessageLoop();
2091 EXPECT_EQ("1 1 0", d1.GetMouseMotionCountsAndReset());
2093 // Make sure we don't synthesize events if the mouse
2094 // is outside of the root window.
2095 generator.MoveMouseTo(-10, -10);
2096 EXPECT_EQ("0 0 1", d1.GetMouseMotionCountsAndReset());
2098 // Adding new windows.
2099 w11.reset(CreateTestWindowWithDelegate(
2100 &d11, 1, gfx::Rect(0, 0, 100, 100), w1.get()));
2101 RunAllPendingInMessageLoop();
2102 EXPECT_EQ("0 0 0", d1.GetMouseMotionCountsAndReset());
2103 EXPECT_EQ("0 0 0", d11.GetMouseMotionCountsAndReset());
2105 // Closing windows
2106 w11.reset();
2107 RunAllPendingInMessageLoop();
2108 EXPECT_EQ("0 0 0", d1.GetMouseMotionCountsAndReset());
2109 EXPECT_EQ("0 0 0", d11.GetMouseMotionCountsAndReset());
2112 class StackingMadrigalLayoutManager : public LayoutManager {
2113 public:
2114 explicit StackingMadrigalLayoutManager(RootWindow* root_window)
2115 : root_window_(root_window) {
2116 root_window_->SetLayoutManager(this);
2118 virtual ~StackingMadrigalLayoutManager() {
2121 private:
2122 // Overridden from LayoutManager:
2123 virtual void OnWindowResized() OVERRIDE {}
2124 virtual void OnWindowAddedToLayout(Window* child) OVERRIDE {}
2125 virtual void OnWillRemoveWindowFromLayout(Window* child) OVERRIDE {}
2126 virtual void OnWindowRemovedFromLayout(Window* child) OVERRIDE {}
2127 virtual void OnChildWindowVisibilityChanged(Window* child,
2128 bool visible) OVERRIDE {
2129 Window::Windows::const_iterator it = root_window_->children().begin();
2130 Window* last_window = NULL;
2131 for (; it != root_window_->children().end(); ++it) {
2132 if (*it == child && last_window) {
2133 if (!visible)
2134 root_window_->StackChildAbove(last_window, *it);
2135 else
2136 root_window_->StackChildAbove(*it, last_window);
2137 break;
2139 last_window = *it;
2142 virtual void SetChildBounds(Window* child,
2143 const gfx::Rect& requested_bounds) OVERRIDE {
2144 SetChildBoundsDirect(child, requested_bounds);
2147 RootWindow* root_window_;
2149 DISALLOW_COPY_AND_ASSIGN(StackingMadrigalLayoutManager);
2152 class StackingMadrigalVisibilityClient : public client::VisibilityClient {
2153 public:
2154 explicit StackingMadrigalVisibilityClient(RootWindow* root_window)
2155 : ignored_window_(NULL) {
2156 client::SetVisibilityClient(root_window, this);
2158 virtual ~StackingMadrigalVisibilityClient() {
2161 void set_ignored_window(Window* ignored_window) {
2162 ignored_window_ = ignored_window;
2165 private:
2166 // Overridden from client::VisibilityClient:
2167 virtual void UpdateLayerVisibility(Window* window, bool visible) OVERRIDE {
2168 if (!visible) {
2169 if (window == ignored_window_)
2170 window->layer()->set_delegate(NULL);
2171 else
2172 window->layer()->SetVisible(visible);
2173 } else {
2174 window->layer()->SetVisible(visible);
2178 Window* ignored_window_;
2180 DISALLOW_COPY_AND_ASSIGN(StackingMadrigalVisibilityClient);
2183 // This test attempts to reconstruct a circumstance that can happen when the
2184 // aura client attempts to manipulate the visibility and delegate of a layer
2185 // independent of window visibility.
2186 // A use case is where the client attempts to keep a window visible onscreen
2187 // even after code has called Hide() on the window. The use case for this would
2188 // be that window hides are animated (e.g. the window fades out). To prevent
2189 // spurious updating the client code may also clear window's layer's delegate,
2190 // so that the window cannot attempt to paint or update it further. The window
2191 // uses the presence of a NULL layer delegate as a signal in stacking to note
2192 // that the window is being manipulated by such a use case and its stacking
2193 // should not be adjusted.
2194 // One issue that can arise when a window opens two transient children, and the
2195 // first is hidden. Subsequent attempts to activate the transient parent can
2196 // result in the transient parent being stacked above the second transient
2197 // child. A fix is made to Window::StackAbove to prevent this, and this test
2198 // verifies this fix.
2199 TEST_F(WindowTest, StackingMadrigal) {
2200 new StackingMadrigalLayoutManager(root_window());
2201 StackingMadrigalVisibilityClient visibility_client(root_window());
2203 scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
2204 scoped_ptr<Window> window11(CreateTransientChild(11, window1.get()));
2206 visibility_client.set_ignored_window(window11.get());
2208 window11->Show();
2209 window11->Hide();
2211 // As a transient, window11 should still be stacked above window1, even when
2212 // hidden.
2213 EXPECT_TRUE(WindowIsAbove(window11.get(), window1.get()));
2214 EXPECT_TRUE(LayerIsAbove(window11.get(), window1.get()));
2216 // A new transient should still be above window1. It will appear behind
2217 // window11 because we don't stack windows on top of targets with NULL
2218 // delegates.
2219 scoped_ptr<Window> window12(CreateTransientChild(12, window1.get()));
2220 window12->Show();
2222 EXPECT_TRUE(WindowIsAbove(window12.get(), window1.get()));
2223 EXPECT_TRUE(LayerIsAbove(window12.get(), window1.get()));
2225 // In earlier versions of the StackChildAbove() method, attempting to stack
2226 // window1 above window12 at this point would actually restack the layers
2227 // resulting in window12's layer being below window1's layer (though the
2228 // windows themselves would still be correctly stacked, so events would pass
2229 // through.)
2230 root_window()->StackChildAbove(window1.get(), window12.get());
2232 // Both window12 and its layer should be stacked above window1.
2233 EXPECT_TRUE(WindowIsAbove(window12.get(), window1.get()));
2234 EXPECT_TRUE(LayerIsAbove(window12.get(), window1.get()));
2237 // Test for an issue where attempting to stack a primary window on top of a
2238 // transient with a NULL layer delegate causes that primary window to be moved,
2239 // but the layer order not changed to match. http://crbug.com/112562
2240 TEST_F(WindowTest, StackOverClosingTransient) {
2241 scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
2242 scoped_ptr<Window> transient1(CreateTransientChild(11, window1.get()));
2243 scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window()));
2244 scoped_ptr<Window> transient2(CreateTransientChild(21, window2.get()));
2246 // Both windows and layers are stacked in creation order.
2247 RootWindow* root = root_window();
2248 ASSERT_EQ(4u, root->children().size());
2249 EXPECT_EQ(root->children()[0], window1.get());
2250 EXPECT_EQ(root->children()[1], transient1.get());
2251 EXPECT_EQ(root->children()[2], window2.get());
2252 EXPECT_EQ(root->children()[3], transient2.get());
2253 ASSERT_EQ(4u, root->layer()->children().size());
2254 EXPECT_EQ(root->layer()->children()[0], window1->layer());
2255 EXPECT_EQ(root->layer()->children()[1], transient1->layer());
2256 EXPECT_EQ(root->layer()->children()[2], window2->layer());
2257 EXPECT_EQ(root->layer()->children()[3], transient2->layer());
2259 // This brings window1 and its transient to the front.
2260 // root_window()->StackChildAbove(window1.get(), window2.get());
2261 root->StackChildAtTop(window1.get());
2263 EXPECT_EQ(root->children()[0], window2.get());
2264 EXPECT_EQ(root->children()[1], transient2.get());
2265 EXPECT_EQ(root->children()[2], window1.get());
2266 EXPECT_EQ(root->children()[3], transient1.get());
2267 EXPECT_EQ(root->layer()->children()[0], window2->layer());
2268 EXPECT_EQ(root->layer()->children()[1], transient2->layer());
2269 EXPECT_EQ(root->layer()->children()[2], window1->layer());
2270 EXPECT_EQ(root->layer()->children()[3], transient1->layer());
2272 // Pretend we're closing the top-most transient, then bring window2 to the
2273 // front. This mimics activating a browser window while the status bubble
2274 // is fading out. The transient should stay topmost.
2275 transient1->layer()->set_delegate(NULL);
2276 root->StackChildAtTop(window2.get());
2278 EXPECT_EQ(root->children()[0], window1.get());
2279 EXPECT_EQ(root->children()[1], window2.get());
2280 EXPECT_EQ(root->children()[2], transient2.get());
2281 EXPECT_EQ(root->children()[3], transient1.get());
2282 EXPECT_EQ(root->layer()->children()[0], window1->layer());
2283 EXPECT_EQ(root->layer()->children()[1], window2->layer());
2284 EXPECT_EQ(root->layer()->children()[2], transient2->layer());
2285 EXPECT_EQ(root->layer()->children()[3], transient1->layer());
2287 // Close the transient. Remaining windows are stable.
2288 transient1.reset();
2290 ASSERT_EQ(3u, root->children().size());
2291 EXPECT_EQ(root->children()[0], window1.get());
2292 EXPECT_EQ(root->children()[1], window2.get());
2293 EXPECT_EQ(root->children()[2], transient2.get());
2294 ASSERT_EQ(3u, root->layer()->children().size());
2295 EXPECT_EQ(root->layer()->children()[0], window1->layer());
2296 EXPECT_EQ(root->layer()->children()[1], window2->layer());
2297 EXPECT_EQ(root->layer()->children()[2], transient2->layer());
2299 // Open another window on top.
2300 scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window()));
2302 ASSERT_EQ(4u, root->children().size());
2303 EXPECT_EQ(root->children()[0], window1.get());
2304 EXPECT_EQ(root->children()[1], window2.get());
2305 EXPECT_EQ(root->children()[2], transient2.get());
2306 EXPECT_EQ(root->children()[3], window3.get());
2307 ASSERT_EQ(4u, root->layer()->children().size());
2308 EXPECT_EQ(root->layer()->children()[0], window1->layer());
2309 EXPECT_EQ(root->layer()->children()[1], window2->layer());
2310 EXPECT_EQ(root->layer()->children()[2], transient2->layer());
2311 EXPECT_EQ(root->layer()->children()[3], window3->layer());
2313 // Pretend we're closing the topmost non-transient window, then bring
2314 // window2 to the top. It should not move.
2315 window3->layer()->set_delegate(NULL);
2316 root->StackChildAtTop(window2.get());
2318 ASSERT_EQ(4u, root->children().size());
2319 EXPECT_EQ(root->children()[0], window1.get());
2320 EXPECT_EQ(root->children()[1], window2.get());
2321 EXPECT_EQ(root->children()[2], transient2.get());
2322 EXPECT_EQ(root->children()[3], window3.get());
2323 ASSERT_EQ(4u, root->layer()->children().size());
2324 EXPECT_EQ(root->layer()->children()[0], window1->layer());
2325 EXPECT_EQ(root->layer()->children()[1], window2->layer());
2326 EXPECT_EQ(root->layer()->children()[2], transient2->layer());
2327 EXPECT_EQ(root->layer()->children()[3], window3->layer());
2329 // Bring window1 to the top. It should move ahead of window2, but not
2330 // ahead of window3 (with NULL delegate).
2331 root->StackChildAtTop(window1.get());
2333 ASSERT_EQ(4u, root->children().size());
2334 EXPECT_EQ(root->children()[0], window2.get());
2335 EXPECT_EQ(root->children()[1], transient2.get());
2336 EXPECT_EQ(root->children()[2], window1.get());
2337 EXPECT_EQ(root->children()[3], window3.get());
2338 ASSERT_EQ(4u, root->layer()->children().size());
2339 EXPECT_EQ(root->layer()->children()[0], window2->layer());
2340 EXPECT_EQ(root->layer()->children()[1], transient2->layer());
2341 EXPECT_EQ(root->layer()->children()[2], window1->layer());
2342 EXPECT_EQ(root->layer()->children()[3], window3->layer());
2345 class RootWindowAttachmentObserver : public WindowObserver {
2346 public:
2347 RootWindowAttachmentObserver() : added_count_(0), removed_count_(0) {}
2348 virtual ~RootWindowAttachmentObserver() {}
2350 int added_count() const { return added_count_; }
2351 int removed_count() const { return removed_count_; }
2353 void Clear() {
2354 added_count_ = 0;
2355 removed_count_ = 0;
2358 // Overridden from WindowObserver:
2359 virtual void OnWindowAddedToRootWindow(Window* window) OVERRIDE {
2360 ++added_count_;
2362 virtual void OnWindowRemovingFromRootWindow(Window* window) OVERRIDE {
2363 ++removed_count_;
2366 private:
2367 int added_count_;
2368 int removed_count_;
2370 DISALLOW_COPY_AND_ASSIGN(RootWindowAttachmentObserver);
2373 TEST_F(WindowTest, RootWindowAttachment) {
2374 RootWindowAttachmentObserver observer;
2376 // Test a direct add/remove from the RootWindow.
2377 scoped_ptr<Window> w1(new Window(NULL));
2378 w1->Init(ui::LAYER_NOT_DRAWN);
2379 w1->AddObserver(&observer);
2381 SetDefaultParentByPrimaryRootWindow(w1.get());
2382 EXPECT_EQ(1, observer.added_count());
2383 EXPECT_EQ(0, observer.removed_count());
2385 w1.reset();
2386 EXPECT_EQ(1, observer.added_count());
2387 EXPECT_EQ(1, observer.removed_count());
2389 observer.Clear();
2391 // Test an indirect add/remove from the RootWindow.
2392 w1.reset(new Window(NULL));
2393 w1->Init(ui::LAYER_NOT_DRAWN);
2394 Window* w11 = new Window(NULL);
2395 w11->Init(ui::LAYER_NOT_DRAWN);
2396 w11->AddObserver(&observer);
2397 w1->AddChild(w11);
2398 EXPECT_EQ(0, observer.added_count());
2399 EXPECT_EQ(0, observer.removed_count());
2401 SetDefaultParentByPrimaryRootWindow(w1.get());
2402 EXPECT_EQ(1, observer.added_count());
2403 EXPECT_EQ(0, observer.removed_count());
2405 w1.reset(); // Deletes w11.
2406 w11 = NULL;
2407 EXPECT_EQ(1, observer.added_count());
2408 EXPECT_EQ(1, observer.removed_count());
2410 observer.Clear();
2412 // Test an indirect add/remove with nested observers.
2413 w1.reset(new Window(NULL));
2414 w1->Init(ui::LAYER_NOT_DRAWN);
2415 w11 = new Window(NULL);
2416 w11->Init(ui::LAYER_NOT_DRAWN);
2417 w11->AddObserver(&observer);
2418 w1->AddChild(w11);
2419 Window* w111 = new Window(NULL);
2420 w111->Init(ui::LAYER_NOT_DRAWN);
2421 w111->AddObserver(&observer);
2422 w11->AddChild(w111);
2424 EXPECT_EQ(0, observer.added_count());
2425 EXPECT_EQ(0, observer.removed_count());
2427 SetDefaultParentByPrimaryRootWindow(w1.get());
2428 EXPECT_EQ(2, observer.added_count());
2429 EXPECT_EQ(0, observer.removed_count());
2431 w1.reset(); // Deletes w11 and w111.
2432 w11 = NULL;
2433 w111 = NULL;
2434 EXPECT_EQ(2, observer.added_count());
2435 EXPECT_EQ(2, observer.removed_count());
2438 TEST_F(WindowTest, OwnedByParentFalse) {
2439 // By default, a window is owned by its parent. If this is set to false, the
2440 // window will not be destroyed when its parent is.
2442 scoped_ptr<Window> w1(new Window(NULL));
2443 w1->Init(ui::LAYER_NOT_DRAWN);
2444 scoped_ptr<Window> w2(new Window(NULL));
2445 w2->set_owned_by_parent(false);
2446 w2->Init(ui::LAYER_NOT_DRAWN);
2447 w1->AddChild(w2.get());
2449 w1.reset();
2451 // We should be able to deref w2 still, but its parent should now be NULL.
2452 EXPECT_EQ(NULL, w2->parent());
2455 namespace {
2457 // Used By DeleteWindowFromOnWindowDestroyed. Destroys a Window from
2458 // OnWindowDestroyed().
2459 class OwningWindowDelegate : public TestWindowDelegate {
2460 public:
2461 OwningWindowDelegate() {}
2463 void SetOwnedWindow(Window* window) {
2464 owned_window_.reset(window);
2467 virtual void OnWindowDestroyed() OVERRIDE {
2468 owned_window_.reset(NULL);
2471 private:
2472 scoped_ptr<Window> owned_window_;
2474 DISALLOW_COPY_AND_ASSIGN(OwningWindowDelegate);
2477 } // namespace
2479 // Creates a window with two child windows. When the first child window is
2480 // destroyed (WindowDelegate::OnWindowDestroyed) it deletes the second child.
2481 // This synthesizes BrowserView and the status bubble. Both are children of the
2482 // same parent and destroying BrowserView triggers it destroying the status
2483 // bubble.
2484 TEST_F(WindowTest, DeleteWindowFromOnWindowDestroyed) {
2485 scoped_ptr<Window> parent(new Window(NULL));
2486 parent->Init(ui::LAYER_NOT_DRAWN);
2487 OwningWindowDelegate delegate;
2488 Window* c1 = new Window(&delegate);
2489 c1->Init(ui::LAYER_NOT_DRAWN);
2490 parent->AddChild(c1);
2491 Window* c2 = new Window(NULL);
2492 c2->Init(ui::LAYER_NOT_DRAWN);
2493 parent->AddChild(c2);
2494 delegate.SetOwnedWindow(c2);
2495 parent.reset();
2498 namespace {
2500 // Used by DelegateNotifiedAsBoundsChange to verify OnBoundsChanged() is
2501 // invoked.
2502 class BoundsChangeDelegate : public TestWindowDelegate {
2503 public:
2504 BoundsChangeDelegate() : bounds_changed_(false) {}
2506 void clear_bounds_changed() { bounds_changed_ = false; }
2507 bool bounds_changed() const {
2508 return bounds_changed_;
2511 // Window
2512 virtual void OnBoundsChanged(const gfx::Rect& old_bounds,
2513 const gfx::Rect& new_bounds) OVERRIDE {
2514 bounds_changed_ = true;
2517 private:
2518 // Was OnBoundsChanged() invoked?
2519 bool bounds_changed_;
2521 DISALLOW_COPY_AND_ASSIGN(BoundsChangeDelegate);
2524 } // namespace
2526 // Verifies the delegate is notified when the actual bounds of the layer
2527 // change.
2528 TEST_F(WindowTest, DelegateNotifiedAsBoundsChange) {
2529 BoundsChangeDelegate delegate;
2531 // We cannot short-circuit animations in this test.
2532 ui::ScopedAnimationDurationScaleMode normal_duration_mode(
2533 ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
2535 scoped_ptr<Window> window(
2536 CreateTestWindowWithDelegate(&delegate, 1,
2537 gfx::Rect(0, 0, 100, 100), root_window()));
2538 window->layer()->GetAnimator()->set_disable_timer_for_test(true);
2540 delegate.clear_bounds_changed();
2542 // Animate to a different position.
2544 ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
2545 window->SetBounds(gfx::Rect(100, 100, 100, 100));
2548 // Bounds shouldn't immediately have changed.
2549 EXPECT_EQ("0,0 100x100", window->bounds().ToString());
2550 EXPECT_FALSE(delegate.bounds_changed());
2552 // Animate to the end, which should notify of the change.
2553 base::TimeTicks start_time =
2554 window->layer()->GetAnimator()->last_step_time();
2555 ui::AnimationContainerElement* element = window->layer()->GetAnimator();
2556 element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
2557 EXPECT_TRUE(delegate.bounds_changed());
2558 EXPECT_NE("0,0 100x100", window->bounds().ToString());
2561 // Verifies the delegate is notified when the actual bounds of the layer
2562 // change even when the window is not the layer's delegate
2563 TEST_F(WindowTest, DelegateNotifiedAsBoundsChangeInHiddenLayer) {
2564 BoundsChangeDelegate delegate;
2566 // We cannot short-circuit animations in this test.
2567 ui::ScopedAnimationDurationScaleMode normal_duration_mode(
2568 ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
2570 scoped_ptr<Window> window(
2571 CreateTestWindowWithDelegate(&delegate, 1,
2572 gfx::Rect(0, 0, 100, 100), root_window()));
2573 window->layer()->GetAnimator()->set_disable_timer_for_test(true);
2575 delegate.clear_bounds_changed();
2577 // Suppress paint on the window since it is hidden (should reset the layer's
2578 // delegate to NULL)
2579 window->SuppressPaint();
2580 EXPECT_EQ(NULL, window->layer()->delegate());
2582 // Animate to a different position.
2584 ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
2585 window->SetBounds(gfx::Rect(100, 100, 110, 100));
2588 // Layer delegate is NULL but we should still get bounds changed notification.
2589 EXPECT_EQ("100,100 110x100", window->GetTargetBounds().ToString());
2590 EXPECT_TRUE(delegate.bounds_changed());
2592 delegate.clear_bounds_changed();
2594 // Animate to the end: will *not* notify of the change since we are hidden.
2595 base::TimeTicks start_time =
2596 window->layer()->GetAnimator()->last_step_time();
2597 ui::AnimationContainerElement* element = window->layer()->GetAnimator();
2598 element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
2600 // No bounds changed notification at the end of animation since layer
2601 // delegate is NULL.
2602 EXPECT_FALSE(delegate.bounds_changed());
2603 EXPECT_NE("0,0 100x100", window->bounds().ToString());
2606 namespace {
2608 // Used by AddChildNotifications to track notification counts.
2609 class AddChildNotificationsObserver : public WindowObserver {
2610 public:
2611 AddChildNotificationsObserver() : added_count_(0), removed_count_(0) {}
2613 std::string CountStringAndReset() {
2614 std::string result = base::IntToString(added_count_) + " " +
2615 base::IntToString(removed_count_);
2616 added_count_ = removed_count_ = 0;
2617 return result;
2620 // WindowObserver overrides:
2621 virtual void OnWindowAddedToRootWindow(Window* window) OVERRIDE {
2622 added_count_++;
2624 virtual void OnWindowRemovingFromRootWindow(Window* window) OVERRIDE {
2625 removed_count_++;
2628 private:
2629 int added_count_;
2630 int removed_count_;
2632 DISALLOW_COPY_AND_ASSIGN(AddChildNotificationsObserver);
2635 } // namespace
2637 // Assertions around when root window notifications are sent.
2638 TEST_F(WindowTest, AddChildNotifications) {
2639 AddChildNotificationsObserver observer;
2640 scoped_ptr<Window> w1(CreateTestWindowWithId(1, root_window()));
2641 scoped_ptr<Window> w2(CreateTestWindowWithId(1, root_window()));
2642 w2->AddObserver(&observer);
2643 w2->Focus();
2644 EXPECT_TRUE(w2->HasFocus());
2646 // Move |w2| to be a child of |w1|.
2647 w1->AddChild(w2.get());
2648 // Sine we moved in the same root, observer shouldn't be notified.
2649 EXPECT_EQ("0 0", observer.CountStringAndReset());
2650 // |w2| should still have focus after moving.
2651 EXPECT_TRUE(w2->HasFocus());
2654 // Tests that a delegate that destroys itself when the window is destroyed does
2655 // not break.
2656 TEST_F(WindowTest, DelegateDestroysSelfOnWindowDestroy) {
2657 scoped_ptr<Window> w1(CreateTestWindowWithDelegate(
2658 new DestroyWindowDelegate(),
2660 gfx::Rect(10, 20, 30, 40),
2661 root_window()));
2664 class HierarchyObserver : public WindowObserver {
2665 public:
2666 HierarchyObserver(Window* target) : target_(target) {
2667 target_->AddObserver(this);
2669 virtual ~HierarchyObserver() {
2670 target_->RemoveObserver(this);
2673 void ValidateState(
2674 int index,
2675 const WindowObserver::HierarchyChangeParams& params) const {
2676 ParamsMatch(params_[index], params);
2679 void Reset() {
2680 params_.clear();
2683 private:
2684 // Overridden from WindowObserver:
2685 virtual void OnWindowHierarchyChanging(
2686 const HierarchyChangeParams& params) OVERRIDE {
2687 params_.push_back(params);
2689 virtual void OnWindowHierarchyChanged(
2690 const HierarchyChangeParams& params) OVERRIDE {
2691 params_.push_back(params);
2694 void ParamsMatch(const WindowObserver::HierarchyChangeParams& p1,
2695 const WindowObserver::HierarchyChangeParams& p2) const {
2696 EXPECT_EQ(p1.phase, p2.phase);
2697 EXPECT_EQ(p1.target, p2.target);
2698 EXPECT_EQ(p1.new_parent, p2.new_parent);
2699 EXPECT_EQ(p1.old_parent, p2.old_parent);
2700 EXPECT_EQ(p1.receiver, p2.receiver);
2703 Window* target_;
2704 std::vector<WindowObserver::HierarchyChangeParams> params_;
2706 DISALLOW_COPY_AND_ASSIGN(HierarchyObserver);
2709 // Tests hierarchy change notifications.
2710 TEST_F(WindowTest, OnWindowHierarchyChange) {
2712 // Simple add & remove.
2713 HierarchyObserver oroot(root_window());
2715 scoped_ptr<Window> w1(CreateTestWindowWithId(1, NULL));
2716 HierarchyObserver o1(w1.get());
2718 // Add.
2719 root_window()->AddChild(w1.get());
2721 WindowObserver::HierarchyChangeParams params;
2722 params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING;
2723 params.target = w1.get();
2724 params.old_parent = NULL;
2725 params.new_parent = root_window();
2726 params.receiver = w1.get();
2727 o1.ValidateState(0, params);
2729 params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED;
2730 params.receiver = w1.get();
2731 o1.ValidateState(1, params);
2733 params.receiver = root_window();
2734 oroot.ValidateState(0, params);
2736 // Remove.
2737 o1.Reset();
2738 oroot.Reset();
2740 root_window()->RemoveChild(w1.get());
2742 params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING;
2743 params.old_parent = root_window();
2744 params.new_parent = NULL;
2745 params.receiver = w1.get();
2747 o1.ValidateState(0, params);
2749 params.receiver = root_window();
2750 oroot.ValidateState(0, params);
2752 params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED;
2753 params.receiver = w1.get();
2754 o1.ValidateState(1, params);
2758 // Add & remove of hierarchy. Tests notification order per documentation in
2759 // WindowObserver.
2760 HierarchyObserver o(root_window());
2761 scoped_ptr<Window> w1(CreateTestWindowWithId(1, NULL));
2762 Window* w11 = CreateTestWindowWithId(11, w1.get());
2763 w1->AddObserver(&o);
2764 w11->AddObserver(&o);
2766 // Add.
2767 root_window()->AddChild(w1.get());
2769 // Dispatched to target first.
2770 int index = 0;
2771 WindowObserver::HierarchyChangeParams params;
2772 params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING;
2773 params.target = w1.get();
2774 params.old_parent = NULL;
2775 params.new_parent = root_window();
2776 params.receiver = w1.get();
2777 o.ValidateState(index++, params);
2779 // Dispatched to target's children.
2780 params.receiver = w11;
2781 o.ValidateState(index++, params);
2783 params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED;
2785 // Now process the "changed" phase.
2786 params.receiver = w1.get();
2787 o.ValidateState(index++, params);
2788 params.receiver = w11;
2789 o.ValidateState(index++, params);
2790 params.receiver = root_window();
2791 o.ValidateState(index++, params);
2793 // Remove.
2794 root_window()->RemoveChild(w1.get());
2795 params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING;
2796 params.old_parent = root_window();
2797 params.new_parent = NULL;
2798 params.receiver = w1.get();
2799 o.ValidateState(index++, params);
2800 params.receiver = w11;
2801 o.ValidateState(index++, params);
2802 params.receiver = root_window();
2803 o.ValidateState(index++, params);
2804 params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED;
2805 params.receiver = w1.get();
2806 o.ValidateState(index++, params);
2807 params.receiver = w11;
2808 o.ValidateState(index++, params);
2810 w1.reset();
2814 // Reparent. Tests notification order per documentation in WindowObserver.
2815 scoped_ptr<Window> w1(CreateTestWindowWithId(1, root_window()));
2816 Window* w11 = CreateTestWindowWithId(11, w1.get());
2817 Window* w111 = CreateTestWindowWithId(111, w11);
2818 scoped_ptr<Window> w2(CreateTestWindowWithId(2, root_window()));
2820 HierarchyObserver o(root_window());
2821 w1->AddObserver(&o);
2822 w11->AddObserver(&o);
2823 w111->AddObserver(&o);
2824 w2->AddObserver(&o);
2826 w2->AddChild(w11);
2828 // Dispatched to target first.
2829 int index = 0;
2830 WindowObserver::HierarchyChangeParams params;
2831 params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING;
2832 params.target = w11;
2833 params.old_parent = w1.get();
2834 params.new_parent = w2.get();
2835 params.receiver = w11;
2836 o.ValidateState(index++, params);
2838 // Then to target's children.
2839 params.receiver = w111;
2840 o.ValidateState(index++, params);
2842 // Then to target's old parent chain.
2843 params.receiver = w1.get();
2844 o.ValidateState(index++, params);
2845 params.receiver = root_window();
2846 o.ValidateState(index++, params);
2848 // "Changed" phase.
2849 params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED;
2850 params.receiver = w11;
2851 o.ValidateState(index++, params);
2852 params.receiver = w111;
2853 o.ValidateState(index++, params);
2854 params.receiver = w2.get();
2855 o.ValidateState(index++, params);
2856 params.receiver = root_window();
2857 o.ValidateState(index++, params);
2859 w1.reset();
2860 w2.reset();
2865 } // namespace test
2866 } // namespace aura