Add ability for NetLogLogger to gather data from more than just NetLog
[chromium-blink-merge.git] / ui / views / widget / widget_unittest.cc
blobe3265493c042fe458e63f8d3d19130f2273dc823
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 <algorithm>
6 #include <set>
8 #include "base/basictypes.h"
9 #include "base/bind.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "ui/base/hit_test.h"
16 #include "ui/compositor/layer_animation_observer.h"
17 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
18 #include "ui/compositor/scoped_layer_animation_settings.h"
19 #include "ui/events/event_utils.h"
20 #include "ui/events/test/event_generator.h"
21 #include "ui/gfx/geometry/point.h"
22 #include "ui/gfx/native_widget_types.h"
23 #include "ui/views/bubble/bubble_delegate.h"
24 #include "ui/views/controls/textfield/textfield.h"
25 #include "ui/views/test/test_views.h"
26 #include "ui/views/test/test_views_delegate.h"
27 #include "ui/views/test/test_widget_observer.h"
28 #include "ui/views/test/widget_test.h"
29 #include "ui/views/views_delegate.h"
30 #include "ui/views/widget/native_widget_delegate.h"
31 #include "ui/views/widget/root_view.h"
32 #include "ui/views/widget/widget_deletion_observer.h"
33 #include "ui/views/window/dialog_delegate.h"
34 #include "ui/views/window/native_frame_view.h"
36 #if defined(OS_WIN)
37 #include "ui/aura/window.h"
38 #include "ui/aura/window_tree_host.h"
39 #include "ui/base/view_prop.h"
40 #include "ui/base/win/window_event_target.h"
41 #include "ui/views/win/hwnd_util.h"
42 #endif
44 #if defined(OS_MACOSX)
45 #include "base/mac/mac_util.h"
46 #endif
48 namespace views {
49 namespace test {
51 namespace {
53 // TODO(tdanderson): This utility function is used in different unittest
54 // files. Move to a common location to avoid
55 // repeated code.
56 gfx::Point ConvertPointFromWidgetToView(View* view, const gfx::Point& p) {
57 gfx::Point tmp(p);
58 View::ConvertPointToTarget(view->GetWidget()->GetRootView(), view, &tmp);
59 return tmp;
62 // Helper function for Snow Leopard special cases to avoid #ifdef litter.
63 bool IsTestingSnowLeopard() {
64 #if defined(OS_MACOSX)
65 return base::mac::IsOSSnowLeopard();
66 #else
67 return false;
68 #endif
71 } // namespace
73 // A view that keeps track of the events it receives, optionally consuming them.
74 class EventCountView : public View {
75 public:
76 // Whether to call SetHandled() on events as they are received. For some event
77 // types, this will allow EventCountView to receives future events in the
78 // event sequence, such as a drag.
79 enum HandleMode {
80 PROPAGATE_EVENTS,
81 CONSUME_EVENTS
84 EventCountView()
85 : last_flags_(0),
86 handle_mode_(PROPAGATE_EVENTS) {}
88 ~EventCountView() override {}
90 int GetEventCount(ui::EventType type) {
91 return event_count_[type];
94 void ResetCounts() {
95 event_count_.clear();
98 int last_flags() const {
99 return last_flags_;
102 void set_handle_mode(HandleMode handle_mode) {
103 handle_mode_ = handle_mode;
106 protected:
107 // Overridden from View:
108 void OnMouseMoved(const ui::MouseEvent& event) override {
109 // MouseMove events are not re-dispatched from the RootView.
110 ++event_count_[ui::ET_MOUSE_MOVED];
111 last_flags_ = 0;
114 // Overridden from ui::EventHandler:
115 void OnKeyEvent(ui::KeyEvent* event) override { RecordEvent(event); }
116 void OnMouseEvent(ui::MouseEvent* event) override { RecordEvent(event); }
117 void OnScrollEvent(ui::ScrollEvent* event) override { RecordEvent(event); }
118 void OnGestureEvent(ui::GestureEvent* event) override { RecordEvent(event); }
120 private:
121 void RecordEvent(ui::Event* event) {
122 ++event_count_[event->type()];
123 last_flags_ = event->flags();
124 if (handle_mode_ == CONSUME_EVENTS)
125 event->SetHandled();
128 std::map<ui::EventType, int> event_count_;
129 int last_flags_;
130 HandleMode handle_mode_;
132 DISALLOW_COPY_AND_ASSIGN(EventCountView);
135 // A view that keeps track of the events it receives, and consumes all scroll
136 // gesture events and ui::ET_SCROLL events.
137 class ScrollableEventCountView : public EventCountView {
138 public:
139 ScrollableEventCountView() {}
140 ~ScrollableEventCountView() override {}
142 private:
143 // Overridden from ui::EventHandler:
144 void OnGestureEvent(ui::GestureEvent* event) override {
145 EventCountView::OnGestureEvent(event);
146 switch (event->type()) {
147 case ui::ET_GESTURE_SCROLL_BEGIN:
148 case ui::ET_GESTURE_SCROLL_UPDATE:
149 case ui::ET_GESTURE_SCROLL_END:
150 case ui::ET_SCROLL_FLING_START:
151 event->SetHandled();
152 break;
153 default:
154 break;
158 void OnScrollEvent(ui::ScrollEvent* event) override {
159 EventCountView::OnScrollEvent(event);
160 if (event->type() == ui::ET_SCROLL)
161 event->SetHandled();
164 DISALLOW_COPY_AND_ASSIGN(ScrollableEventCountView);
167 // A view that implements GetMinimumSize.
168 class MinimumSizeFrameView : public NativeFrameView {
169 public:
170 explicit MinimumSizeFrameView(Widget* frame): NativeFrameView(frame) {}
171 ~MinimumSizeFrameView() override {}
173 private:
174 // Overridden from View:
175 gfx::Size GetMinimumSize() const override { return gfx::Size(300, 400); }
177 DISALLOW_COPY_AND_ASSIGN(MinimumSizeFrameView);
180 // An event handler that simply keeps a count of the different types of events
181 // it receives.
182 class EventCountHandler : public ui::EventHandler {
183 public:
184 EventCountHandler() {}
185 ~EventCountHandler() override {}
187 int GetEventCount(ui::EventType type) {
188 return event_count_[type];
191 void ResetCounts() {
192 event_count_.clear();
195 protected:
196 // Overridden from ui::EventHandler:
197 void OnEvent(ui::Event* event) override {
198 RecordEvent(*event);
199 ui::EventHandler::OnEvent(event);
202 private:
203 void RecordEvent(const ui::Event& event) {
204 ++event_count_[event.type()];
207 std::map<ui::EventType, int> event_count_;
209 DISALLOW_COPY_AND_ASSIGN(EventCountHandler);
212 TEST_F(WidgetTest, WidgetInitParams) {
213 // Widgets are not transparent by default.
214 Widget::InitParams init1;
215 EXPECT_EQ(Widget::InitParams::INFER_OPACITY, init1.opacity);
218 TEST_F(WidgetTest, NativeWindowProperty) {
219 const char* key = "foo";
220 int value = 3;
222 Widget* widget = CreateTopLevelPlatformWidget();
223 EXPECT_EQ(nullptr, widget->GetNativeWindowProperty(key));
225 widget->SetNativeWindowProperty(key, &value);
226 EXPECT_EQ(&value, widget->GetNativeWindowProperty(key));
228 widget->SetNativeWindowProperty(key, nullptr);
229 EXPECT_EQ(nullptr, widget->GetNativeWindowProperty(key));
231 widget->CloseNow();
234 ////////////////////////////////////////////////////////////////////////////////
235 // Widget::GetTopLevelWidget tests.
237 TEST_F(WidgetTest, GetTopLevelWidget_Native) {
238 // Create a hierarchy of native widgets.
239 Widget* toplevel = CreateTopLevelPlatformWidget();
240 gfx::NativeView parent = toplevel->GetNativeView();
241 Widget* child = CreateChildPlatformWidget(parent);
243 EXPECT_EQ(toplevel, toplevel->GetTopLevelWidget());
244 EXPECT_EQ(toplevel, child->GetTopLevelWidget());
246 toplevel->CloseNow();
247 // |child| should be automatically destroyed with |toplevel|.
250 // Test if a focus manager and an inputmethod work without CHECK failure
251 // when window activation changes.
252 TEST_F(WidgetTest, ChangeActivation) {
253 Widget* top1 = CreateTopLevelPlatformWidget();
254 // CreateInputMethod before activated
255 top1->GetInputMethod();
256 top1->Show();
257 RunPendingMessages();
259 Widget* top2 = CreateTopLevelPlatformWidget();
260 top2->Show();
261 RunPendingMessages();
263 top1->Activate();
264 RunPendingMessages();
266 // Create InputMethod after deactivated.
267 top2->GetInputMethod();
268 top2->Activate();
269 RunPendingMessages();
271 top1->Activate();
272 RunPendingMessages();
274 top1->CloseNow();
275 top2->CloseNow();
278 // Tests visibility of child widgets.
279 TEST_F(WidgetTest, Visibility) {
280 Widget* toplevel = CreateTopLevelPlatformWidget();
281 gfx::NativeView parent = toplevel->GetNativeView();
282 Widget* child = CreateChildPlatformWidget(parent);
284 EXPECT_FALSE(toplevel->IsVisible());
285 EXPECT_FALSE(child->IsVisible());
287 // Showing a child with a hidden parent keeps the child hidden.
288 child->Show();
289 EXPECT_FALSE(toplevel->IsVisible());
290 EXPECT_FALSE(child->IsVisible());
292 // Showing a hidden parent with a visible child shows both.
293 toplevel->Show();
294 EXPECT_TRUE(toplevel->IsVisible());
295 EXPECT_TRUE(child->IsVisible());
297 // Hiding a parent hides both parent and child.
298 toplevel->Hide();
299 EXPECT_FALSE(toplevel->IsVisible());
300 EXPECT_FALSE(child->IsVisible());
302 // Hiding a child while the parent is hidden keeps the child hidden when the
303 // parent is shown.
304 child->Hide();
305 toplevel->Show();
306 EXPECT_TRUE(toplevel->IsVisible());
307 EXPECT_FALSE(child->IsVisible());
309 toplevel->CloseNow();
310 // |child| should be automatically destroyed with |toplevel|.
313 // Test that child widgets are positioned relative to their parent.
314 TEST_F(WidgetTest, ChildBoundsRelativeToParent) {
315 Widget* toplevel = CreateTopLevelPlatformWidget();
316 Widget* child = CreateChildPlatformWidget(toplevel->GetNativeView());
318 toplevel->SetBounds(gfx::Rect(160, 100, 320, 200));
319 child->SetBounds(gfx::Rect(0, 0, 320, 200));
321 child->Show();
322 toplevel->Show();
324 gfx::Rect toplevel_bounds = toplevel->GetWindowBoundsInScreen();
326 // Check the parent origin. If it was (0, 0) the test wouldn't be interesting.
327 EXPECT_NE(gfx::Vector2d(0, 0), toplevel_bounds.OffsetFromOrigin());
329 // The child's origin is at (0, 0), but the same size, so bounds should match.
330 EXPECT_EQ(toplevel_bounds, child->GetWindowBoundsInScreen());
332 toplevel->CloseNow();
335 // Test z-order of child widgets relative to their parent.
336 TEST_F(WidgetTest, ChildStackedRelativeToParent) {
337 Widget* parent = CreateTopLevelPlatformWidget();
338 Widget* child = CreateChildPlatformWidget(parent->GetNativeView());
340 parent->SetBounds(gfx::Rect(160, 100, 320, 200));
341 child->SetBounds(gfx::Rect(50, 50, 30, 20));
343 // Child shown first. Initially not visible, but on top of parent when shown.
344 // Use ShowInactive whenever showing the child, otherwise the usual activation
345 // logic will just put it on top anyway. Here, we want to ensure it is on top
346 // of its parent regardless.
347 child->ShowInactive();
348 EXPECT_FALSE(child->IsVisible());
350 parent->Show();
351 EXPECT_TRUE(child->IsVisible());
352 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
353 EXPECT_FALSE(IsWindowStackedAbove(parent, child)); // Sanity check.
355 Widget* popover = CreateTopLevelPlatformWidget();
356 popover->SetBounds(gfx::Rect(150, 90, 340, 240));
357 popover->Show();
359 EXPECT_TRUE(IsWindowStackedAbove(popover, child));
360 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
362 // Showing the parent again should raise it and its child above the popover.
363 parent->Show();
364 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
365 EXPECT_TRUE(IsWindowStackedAbove(parent, popover));
367 // Test grandchildren.
368 Widget* grandchild = CreateChildPlatformWidget(child->GetNativeView());
369 grandchild->SetBounds(gfx::Rect(5, 5, 15, 10));
370 grandchild->ShowInactive();
371 EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
372 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
373 EXPECT_TRUE(IsWindowStackedAbove(parent, popover));
375 popover->Show();
376 EXPECT_TRUE(IsWindowStackedAbove(popover, grandchild));
377 EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
379 parent->Show();
380 EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
381 EXPECT_TRUE(IsWindowStackedAbove(child, popover));
383 // Test hiding and reshowing.
384 parent->Hide();
385 EXPECT_FALSE(grandchild->IsVisible());
386 parent->Show();
388 EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
389 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
390 EXPECT_TRUE(IsWindowStackedAbove(parent, popover));
392 grandchild->Hide();
393 EXPECT_FALSE(grandchild->IsVisible());
394 grandchild->ShowInactive();
396 EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
397 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
398 EXPECT_TRUE(IsWindowStackedAbove(parent, popover));
400 popover->CloseNow();
401 parent->CloseNow();
404 ////////////////////////////////////////////////////////////////////////////////
405 // Widget ownership tests.
407 // Tests various permutations of Widget ownership specified in the
408 // InitParams::Ownership param.
410 // A WidgetTest that supplies a toplevel widget for NativeWidget to parent to.
411 class WidgetOwnershipTest : public WidgetTest {
412 public:
413 WidgetOwnershipTest() {}
414 ~WidgetOwnershipTest() override {}
416 void SetUp() override {
417 WidgetTest::SetUp();
418 desktop_widget_ = CreateTopLevelPlatformWidget();
421 void TearDown() override {
422 desktop_widget_->CloseNow();
423 WidgetTest::TearDown();
426 private:
427 Widget* desktop_widget_;
429 DISALLOW_COPY_AND_ASSIGN(WidgetOwnershipTest);
432 // A bag of state to monitor destructions.
433 struct OwnershipTestState {
434 OwnershipTestState() : widget_deleted(false), native_widget_deleted(false) {}
436 bool widget_deleted;
437 bool native_widget_deleted;
440 // A platform NativeWidget subclass that updates a bag of state when it is
441 // destroyed.
442 class OwnershipTestNativeWidget : public PlatformNativeWidget {
443 public:
444 OwnershipTestNativeWidget(internal::NativeWidgetDelegate* delegate,
445 OwnershipTestState* state)
446 : PlatformNativeWidget(delegate),
447 state_(state) {
449 ~OwnershipTestNativeWidget() override {
450 state_->native_widget_deleted = true;
453 private:
454 OwnershipTestState* state_;
456 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidget);
459 // A views NativeWidget subclass that updates a bag of state when it is
460 // destroyed.
461 class OwnershipTestNativeWidgetAura : public NativeWidgetCapture {
462 public:
463 OwnershipTestNativeWidgetAura(internal::NativeWidgetDelegate* delegate,
464 OwnershipTestState* state)
465 : NativeWidgetCapture(delegate),
466 state_(state) {
468 ~OwnershipTestNativeWidgetAura() override {
469 state_->native_widget_deleted = true;
472 private:
473 OwnershipTestState* state_;
475 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetAura);
478 // A Widget subclass that updates a bag of state when it is destroyed.
479 class OwnershipTestWidget : public Widget {
480 public:
481 explicit OwnershipTestWidget(OwnershipTestState* state) : state_(state) {}
482 ~OwnershipTestWidget() override { state_->widget_deleted = true; }
484 private:
485 OwnershipTestState* state_;
487 DISALLOW_COPY_AND_ASSIGN(OwnershipTestWidget);
490 // Widget owns its NativeWidget, part 1: NativeWidget is a platform-native
491 // widget.
492 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsPlatformNativeWidget) {
493 OwnershipTestState state;
495 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
496 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
497 params.native_widget =
498 new OwnershipTestNativeWidgetAura(widget.get(), &state);
499 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
500 widget->Init(params);
502 // Now delete the Widget, which should delete the NativeWidget.
503 widget.reset();
505 EXPECT_TRUE(state.widget_deleted);
506 EXPECT_TRUE(state.native_widget_deleted);
508 // TODO(beng): write test for this ownership scenario and the NativeWidget
509 // being deleted out from under the Widget.
512 // Widget owns its NativeWidget, part 2: NativeWidget is a NativeWidget.
513 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsViewsNativeWidget) {
514 OwnershipTestState state;
516 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
517 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
518 params.native_widget =
519 new OwnershipTestNativeWidgetAura(widget.get(), &state);
520 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
521 widget->Init(params);
523 // Now delete the Widget, which should delete the NativeWidget.
524 widget.reset();
526 EXPECT_TRUE(state.widget_deleted);
527 EXPECT_TRUE(state.native_widget_deleted);
529 // TODO(beng): write test for this ownership scenario and the NativeWidget
530 // being deleted out from under the Widget.
533 // Widget owns its NativeWidget, part 3: NativeWidget is a NativeWidget,
534 // destroy the parent view.
535 TEST_F(WidgetOwnershipTest,
536 Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView) {
537 OwnershipTestState state;
539 Widget* toplevel = CreateTopLevelPlatformWidget();
541 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
542 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
543 params.native_widget =
544 new OwnershipTestNativeWidgetAura(widget.get(), &state);
545 params.parent = toplevel->GetNativeView();
546 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
547 widget->Init(params);
549 // Now close the toplevel, which deletes the view hierarchy.
550 toplevel->CloseNow();
552 RunPendingMessages();
554 // This shouldn't delete the widget because it shouldn't be deleted
555 // from the native side.
556 EXPECT_FALSE(state.widget_deleted);
557 EXPECT_FALSE(state.native_widget_deleted);
559 // Now delete it explicitly.
560 widget.reset();
562 EXPECT_TRUE(state.widget_deleted);
563 EXPECT_TRUE(state.native_widget_deleted);
566 // NativeWidget owns its Widget, part 1: NativeWidget is a platform-native
567 // widget.
568 TEST_F(WidgetOwnershipTest, Ownership_PlatformNativeWidgetOwnsWidget) {
569 OwnershipTestState state;
571 Widget* widget = new OwnershipTestWidget(&state);
572 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
573 params.native_widget =
574 new OwnershipTestNativeWidgetAura(widget, &state);
575 widget->Init(params);
577 // Now destroy the native widget.
578 widget->CloseNow();
580 EXPECT_TRUE(state.widget_deleted);
581 EXPECT_TRUE(state.native_widget_deleted);
584 // NativeWidget owns its Widget, part 2: NativeWidget is a NativeWidget.
585 TEST_F(WidgetOwnershipTest, Ownership_ViewsNativeWidgetOwnsWidget) {
586 OwnershipTestState state;
588 Widget* toplevel = CreateTopLevelPlatformWidget();
590 Widget* widget = new OwnershipTestWidget(&state);
591 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
592 params.native_widget =
593 new OwnershipTestNativeWidgetAura(widget, &state);
594 params.parent = toplevel->GetNativeView();
595 widget->Init(params);
597 // Now destroy the native widget. This is achieved by closing the toplevel.
598 toplevel->CloseNow();
600 // The NativeWidget won't be deleted until after a return to the message loop
601 // so we have to run pending messages before testing the destruction status.
602 RunPendingMessages();
604 EXPECT_TRUE(state.widget_deleted);
605 EXPECT_TRUE(state.native_widget_deleted);
608 // NativeWidget owns its Widget, part 3: NativeWidget is a platform-native
609 // widget, destroyed out from under it by the OS.
610 TEST_F(WidgetOwnershipTest,
611 Ownership_PlatformNativeWidgetOwnsWidget_NativeDestroy) {
612 OwnershipTestState state;
614 Widget* widget = new OwnershipTestWidget(&state);
615 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
616 params.native_widget =
617 new OwnershipTestNativeWidgetAura(widget, &state);
618 widget->Init(params);
620 // Now simulate a destroy of the platform native widget from the OS:
621 SimulateNativeDestroy(widget);
623 EXPECT_TRUE(state.widget_deleted);
624 EXPECT_TRUE(state.native_widget_deleted);
627 // NativeWidget owns its Widget, part 4: NativeWidget is a NativeWidget,
628 // destroyed by the view hierarchy that contains it.
629 TEST_F(WidgetOwnershipTest,
630 Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy) {
631 OwnershipTestState state;
633 Widget* toplevel = CreateTopLevelPlatformWidget();
635 Widget* widget = new OwnershipTestWidget(&state);
636 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
637 params.native_widget =
638 new OwnershipTestNativeWidgetAura(widget, &state);
639 params.parent = toplevel->GetNativeView();
640 widget->Init(params);
642 // Destroy the widget (achieved by closing the toplevel).
643 toplevel->CloseNow();
645 // The NativeWidget won't be deleted until after a return to the message loop
646 // so we have to run pending messages before testing the destruction status.
647 RunPendingMessages();
649 EXPECT_TRUE(state.widget_deleted);
650 EXPECT_TRUE(state.native_widget_deleted);
653 // NativeWidget owns its Widget, part 5: NativeWidget is a NativeWidget,
654 // we close it directly.
655 TEST_F(WidgetOwnershipTest,
656 Ownership_ViewsNativeWidgetOwnsWidget_Close) {
657 OwnershipTestState state;
659 Widget* toplevel = CreateTopLevelPlatformWidget();
661 Widget* widget = new OwnershipTestWidget(&state);
662 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
663 params.native_widget =
664 new OwnershipTestNativeWidgetAura(widget, &state);
665 params.parent = toplevel->GetNativeView();
666 widget->Init(params);
668 // Destroy the widget.
669 widget->Close();
670 toplevel->CloseNow();
672 // The NativeWidget won't be deleted until after a return to the message loop
673 // so we have to run pending messages before testing the destruction status.
674 RunPendingMessages();
676 EXPECT_TRUE(state.widget_deleted);
677 EXPECT_TRUE(state.native_widget_deleted);
680 // Widget owns its NativeWidget and has a WidgetDelegateView as its contents.
681 TEST_F(WidgetOwnershipTest,
682 Ownership_WidgetOwnsNativeWidgetWithWithWidgetDelegateView) {
683 OwnershipTestState state;
685 WidgetDelegateView* delegate_view = new WidgetDelegateView;
687 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
688 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
689 params.native_widget =
690 new OwnershipTestNativeWidgetAura(widget.get(), &state);
691 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
692 params.delegate = delegate_view;
693 widget->Init(params);
694 widget->SetContentsView(delegate_view);
696 // Now delete the Widget. There should be no crash or use-after-free.
697 widget.reset();
699 EXPECT_TRUE(state.widget_deleted);
700 EXPECT_TRUE(state.native_widget_deleted);
703 ////////////////////////////////////////////////////////////////////////////////
704 // Test to verify using various Widget methods doesn't crash when the underlying
705 // NativeView is destroyed.
707 class WidgetWithDestroyedNativeViewTest : public ViewsTestBase {
708 public:
709 WidgetWithDestroyedNativeViewTest() {}
710 ~WidgetWithDestroyedNativeViewTest() override {}
712 void InvokeWidgetMethods(Widget* widget) {
713 widget->GetNativeView();
714 widget->GetNativeWindow();
715 ui::Accelerator accelerator;
716 widget->GetAccelerator(0, &accelerator);
717 widget->GetTopLevelWidget();
718 widget->GetWindowBoundsInScreen();
719 widget->GetClientAreaBoundsInScreen();
720 widget->SetBounds(gfx::Rect(0, 0, 100, 80));
721 widget->SetSize(gfx::Size(10, 11));
722 widget->SetBoundsConstrained(gfx::Rect(0, 0, 120, 140));
723 widget->SetVisibilityChangedAnimationsEnabled(false);
724 widget->StackAtTop();
725 widget->IsClosed();
726 widget->Close();
727 widget->Hide();
728 widget->Activate();
729 widget->Deactivate();
730 widget->IsActive();
731 widget->DisableInactiveRendering();
732 widget->SetAlwaysOnTop(true);
733 widget->IsAlwaysOnTop();
734 widget->Maximize();
735 widget->Minimize();
736 widget->Restore();
737 widget->IsMaximized();
738 widget->IsFullscreen();
739 widget->SetOpacity(0);
740 widget->SetUseDragFrame(true);
741 widget->FlashFrame(true);
742 widget->IsVisible();
743 widget->GetThemeProvider();
744 widget->GetNativeTheme();
745 widget->GetFocusManager();
746 widget->GetInputMethod();
747 widget->SchedulePaintInRect(gfx::Rect(0, 0, 1, 2));
748 widget->IsMouseEventsEnabled();
749 widget->SetNativeWindowProperty("xx", widget);
750 widget->GetNativeWindowProperty("xx");
751 widget->GetFocusTraversable();
752 widget->GetLayer();
753 widget->ReorderNativeViews();
754 widget->SetCapture(widget->GetRootView());
755 widget->ReleaseCapture();
756 widget->HasCapture();
757 widget->GetWorkAreaBoundsInScreen();
758 widget->IsTranslucentWindowOpacitySupported();
761 private:
762 DISALLOW_COPY_AND_ASSIGN(WidgetWithDestroyedNativeViewTest);
765 TEST_F(WidgetWithDestroyedNativeViewTest, Test) {
767 Widget widget;
768 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
769 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
770 widget.Init(params);
771 widget.Show();
773 widget.native_widget_private()->CloseNow();
774 InvokeWidgetMethods(&widget);
776 #if !defined(OS_CHROMEOS)
778 Widget widget;
779 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
780 params.native_widget = new PlatformDesktopNativeWidget(&widget);
781 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
782 widget.Init(params);
783 widget.Show();
785 widget.native_widget_private()->CloseNow();
786 InvokeWidgetMethods(&widget);
788 #endif
791 ////////////////////////////////////////////////////////////////////////////////
792 // Widget observer tests.
795 class WidgetObserverTest : public WidgetTest, public WidgetObserver {
796 public:
797 WidgetObserverTest()
798 : active_(nullptr),
799 widget_closed_(nullptr),
800 widget_activated_(nullptr),
801 widget_shown_(nullptr),
802 widget_hidden_(nullptr),
803 widget_bounds_changed_(nullptr),
804 widget_to_close_on_hide_(nullptr) {
807 ~WidgetObserverTest() override {}
809 // Set a widget to Close() the next time the Widget being observed is hidden.
810 void CloseOnNextHide(Widget* widget) {
811 widget_to_close_on_hide_ = widget;
814 // Overridden from WidgetObserver:
815 void OnWidgetDestroying(Widget* widget) override {
816 if (active_ == widget)
817 active_ = nullptr;
818 widget_closed_ = widget;
821 void OnWidgetActivationChanged(Widget* widget, bool active) override {
822 if (active) {
823 if (widget_activated_)
824 widget_activated_->Deactivate();
825 widget_activated_ = widget;
826 active_ = widget;
827 } else {
828 if (widget_activated_ == widget)
829 widget_activated_ = nullptr;
830 widget_deactivated_ = widget;
834 void OnWidgetVisibilityChanged(Widget* widget, bool visible) override {
835 if (visible) {
836 widget_shown_ = widget;
837 return;
839 widget_hidden_ = widget;
840 if (widget_to_close_on_hide_) {
841 widget_to_close_on_hide_->Close();
842 widget_to_close_on_hide_ = nullptr;
846 void OnWidgetBoundsChanged(Widget* widget,
847 const gfx::Rect& new_bounds) override {
848 widget_bounds_changed_ = widget;
851 void reset() {
852 active_ = nullptr;
853 widget_closed_ = nullptr;
854 widget_activated_ = nullptr;
855 widget_deactivated_ = nullptr;
856 widget_shown_ = nullptr;
857 widget_hidden_ = nullptr;
858 widget_bounds_changed_ = nullptr;
861 Widget* NewWidget() {
862 Widget* widget = CreateTopLevelNativeWidget();
863 widget->AddObserver(this);
864 return widget;
867 const Widget* active() const { return active_; }
868 const Widget* widget_closed() const { return widget_closed_; }
869 const Widget* widget_activated() const { return widget_activated_; }
870 const Widget* widget_deactivated() const { return widget_deactivated_; }
871 const Widget* widget_shown() const { return widget_shown_; }
872 const Widget* widget_hidden() const { return widget_hidden_; }
873 const Widget* widget_bounds_changed() const { return widget_bounds_changed_; }
875 private:
876 Widget* active_;
878 Widget* widget_closed_;
879 Widget* widget_activated_;
880 Widget* widget_deactivated_;
881 Widget* widget_shown_;
882 Widget* widget_hidden_;
883 Widget* widget_bounds_changed_;
885 Widget* widget_to_close_on_hide_;
888 TEST_F(WidgetObserverTest, DISABLED_ActivationChange) {
889 Widget* toplevel = CreateTopLevelPlatformWidget();
891 Widget* toplevel1 = NewWidget();
892 Widget* toplevel2 = NewWidget();
894 toplevel1->Show();
895 toplevel2->Show();
897 reset();
899 toplevel1->Activate();
901 RunPendingMessages();
902 EXPECT_EQ(toplevel1, widget_activated());
904 toplevel2->Activate();
905 RunPendingMessages();
906 EXPECT_EQ(toplevel1, widget_deactivated());
907 EXPECT_EQ(toplevel2, widget_activated());
908 EXPECT_EQ(toplevel2, active());
910 toplevel->CloseNow();
913 TEST_F(WidgetObserverTest, DISABLED_VisibilityChange) {
914 Widget* toplevel = CreateTopLevelPlatformWidget();
916 Widget* child1 = NewWidget();
917 Widget* child2 = NewWidget();
919 toplevel->Show();
920 child1->Show();
921 child2->Show();
923 reset();
925 child1->Hide();
926 EXPECT_EQ(child1, widget_hidden());
928 child2->Hide();
929 EXPECT_EQ(child2, widget_hidden());
931 child1->Show();
932 EXPECT_EQ(child1, widget_shown());
934 child2->Show();
935 EXPECT_EQ(child2, widget_shown());
937 toplevel->CloseNow();
940 TEST_F(WidgetObserverTest, DestroyBubble) {
941 Widget* anchor = CreateTopLevelPlatformWidget();
942 anchor->Show();
944 BubbleDelegateView* bubble_delegate =
945 new BubbleDelegateView(anchor->client_view(), BubbleBorder::NONE);
946 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
947 bubble_widget->Show();
948 bubble_widget->CloseNow();
950 anchor->Hide();
951 anchor->CloseNow();
954 TEST_F(WidgetObserverTest, WidgetBoundsChanged) {
955 Widget* child1 = NewWidget();
956 Widget* child2 = NewWidget();
958 child1->OnNativeWidgetMove();
959 EXPECT_EQ(child1, widget_bounds_changed());
961 child2->OnNativeWidgetMove();
962 EXPECT_EQ(child2, widget_bounds_changed());
964 child1->OnNativeWidgetSizeChanged(gfx::Size());
965 EXPECT_EQ(child1, widget_bounds_changed());
967 child2->OnNativeWidgetSizeChanged(gfx::Size());
968 EXPECT_EQ(child2, widget_bounds_changed());
971 // An extension to WidgetBoundsChanged to ensure notifications are forwarded
972 // by the NativeWidget implementation.
973 TEST_F(WidgetObserverTest, WidgetBoundsChangedNative) {
974 // Don't use NewWidget(), so that the Init() flow can be observed to ensure
975 // consistency across platforms.
976 Widget* widget = new Widget(); // Note: owned by NativeWidget.
977 widget->AddObserver(this);
979 EXPECT_FALSE(widget_bounds_changed());
981 // Init causes a bounds change, even while not showing. Note some platforms
982 // cause a bounds change even when the bounds are empty. Mac does not.
983 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
984 params.bounds = gfx::Rect(0, 0, 100, 100);
985 widget->Init(params);
986 EXPECT_TRUE(widget_bounds_changed());
987 reset();
989 // Resizing while hidden, triggers a change.
990 widget->SetSize(gfx::Size(160, 100));
991 EXPECT_FALSE(widget->IsVisible());
992 EXPECT_TRUE(widget_bounds_changed());
993 reset();
995 // Setting the same size does nothing.
996 widget->SetSize(gfx::Size(160, 100));
997 EXPECT_FALSE(widget_bounds_changed());
998 reset();
1000 // Showing does nothing to the bounds.
1001 widget->Show();
1002 EXPECT_TRUE(widget->IsVisible());
1003 EXPECT_FALSE(widget_bounds_changed());
1004 reset();
1006 // Resizing while shown.
1007 widget->SetSize(gfx::Size(170, 100));
1008 EXPECT_TRUE(widget_bounds_changed());
1009 reset();
1011 // Resize to the same thing while shown does nothing.
1012 widget->SetSize(gfx::Size(170, 100));
1013 EXPECT_FALSE(widget_bounds_changed());
1014 reset();
1016 // No bounds change when closing.
1017 widget->CloseNow();
1018 EXPECT_FALSE(widget_bounds_changed());
1021 // Test correct behavior when widgets close themselves in response to visibility
1022 // changes.
1023 TEST_F(WidgetObserverTest, ClosingOnHiddenParent) {
1024 Widget* parent = NewWidget();
1025 Widget* child = CreateChildPlatformWidget(parent->GetNativeView());
1027 TestWidgetObserver child_observer(child);
1029 EXPECT_FALSE(parent->IsVisible());
1030 EXPECT_FALSE(child->IsVisible());
1032 // Note |child| is TYPE_CONTROL, which start shown. So no need to show the
1033 // child separately.
1034 parent->Show();
1035 EXPECT_TRUE(parent->IsVisible());
1036 EXPECT_TRUE(child->IsVisible());
1038 // Simulate a child widget that closes itself when the parent is hidden.
1039 CloseOnNextHide(child);
1040 EXPECT_FALSE(child_observer.widget_closed());
1041 parent->Hide();
1042 RunPendingMessages();
1043 EXPECT_TRUE(child_observer.widget_closed());
1045 parent->CloseNow();
1048 // Tests that SetBounds() and GetWindowBoundsInScreen() is symmetric when the
1049 // widget is visible and not maximized or fullscreen.
1050 TEST_F(WidgetTest, GetWindowBoundsInScreen) {
1051 // Choose test coordinates away from edges and dimensions that are "small"
1052 // (but not too small) to ensure the OS doesn't try to adjust them.
1053 const gfx::Rect kTestBounds(150, 150, 400, 300);
1054 const gfx::Size kTestSize(200, 180);
1056 // First test a toplevel widget.
1057 Widget* widget = CreateTopLevelPlatformWidget();
1058 widget->Show();
1060 EXPECT_NE(kTestSize.ToString(),
1061 widget->GetWindowBoundsInScreen().size().ToString());
1062 widget->SetSize(kTestSize);
1063 EXPECT_EQ(kTestSize.ToString(),
1064 widget->GetWindowBoundsInScreen().size().ToString());
1066 EXPECT_NE(kTestBounds.ToString(),
1067 widget->GetWindowBoundsInScreen().ToString());
1068 widget->SetBounds(kTestBounds);
1069 EXPECT_EQ(kTestBounds.ToString(),
1070 widget->GetWindowBoundsInScreen().ToString());
1072 // Changing just the size should not change the origin.
1073 widget->SetSize(kTestSize);
1074 EXPECT_EQ(kTestBounds.origin().ToString(),
1075 widget->GetWindowBoundsInScreen().origin().ToString());
1077 widget->CloseNow();
1079 // Same tests with a frameless window.
1080 widget = CreateTopLevelFramelessPlatformWidget();
1081 widget->Show();
1083 EXPECT_NE(kTestSize.ToString(),
1084 widget->GetWindowBoundsInScreen().size().ToString());
1085 widget->SetSize(kTestSize);
1086 EXPECT_EQ(kTestSize.ToString(),
1087 widget->GetWindowBoundsInScreen().size().ToString());
1089 EXPECT_NE(kTestBounds.ToString(),
1090 widget->GetWindowBoundsInScreen().ToString());
1091 widget->SetBounds(kTestBounds);
1092 EXPECT_EQ(kTestBounds.ToString(),
1093 widget->GetWindowBoundsInScreen().ToString());
1095 // For a frameless widget, the client bounds should also match.
1096 EXPECT_EQ(kTestBounds.ToString(),
1097 widget->GetClientAreaBoundsInScreen().ToString());
1099 // Verify origin is stable for a frameless window as well.
1100 widget->SetSize(kTestSize);
1101 EXPECT_EQ(kTestBounds.origin().ToString(),
1102 widget->GetWindowBoundsInScreen().origin().ToString());
1104 widget->CloseNow();
1107 // Before being enabled on Mac, this was #ifdef(false).
1108 // TODO(tapted): Fix this for DesktopNativeWidgets on other platforms.
1109 #if defined(OS_MACOSX)
1110 // Aura needs shell to maximize/fullscreen window.
1111 // NativeWidgetGtk doesn't implement GetRestoredBounds.
1112 TEST_F(WidgetTest, GetRestoredBounds) {
1113 Widget* toplevel = CreateTopLevelPlatformWidget();
1114 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
1115 toplevel->GetRestoredBounds().ToString());
1116 toplevel->Show();
1117 toplevel->Maximize();
1118 RunPendingMessages();
1119 #if defined(OS_MACOSX)
1120 // Current expectation on Mac is to do nothing on Maximize.
1121 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
1122 toplevel->GetRestoredBounds().ToString());
1123 #else
1124 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
1125 toplevel->GetRestoredBounds().ToString());
1126 #endif
1127 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
1128 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
1130 toplevel->Restore();
1131 RunPendingMessages();
1132 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
1133 toplevel->GetRestoredBounds().ToString());
1135 toplevel->SetFullscreen(true);
1136 RunPendingMessages();
1138 if (IsTestingSnowLeopard()) {
1139 // Fullscreen not implemented for Snow Leopard.
1140 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
1141 toplevel->GetRestoredBounds().ToString());
1142 } else {
1143 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
1144 toplevel->GetRestoredBounds().ToString());
1146 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
1147 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
1149 #endif
1151 // The key-event propagation from Widget happens differently on aura and
1152 // non-aura systems because of the difference in IME. So this test works only on
1153 // aura.
1154 TEST_F(WidgetTest, KeyboardInputEvent) {
1155 Widget* toplevel = CreateTopLevelPlatformWidget();
1156 View* container = toplevel->client_view();
1158 Textfield* textfield = new Textfield();
1159 textfield->SetText(base::ASCIIToUTF16("some text"));
1160 container->AddChildView(textfield);
1161 toplevel->Show();
1162 textfield->RequestFocus();
1164 // The press gets handled. The release doesn't have an effect.
1165 ui::KeyEvent backspace_p(ui::ET_KEY_PRESSED, ui::VKEY_DELETE, ui::EF_NONE);
1166 toplevel->OnKeyEvent(&backspace_p);
1167 EXPECT_TRUE(backspace_p.stopped_propagation());
1168 ui::KeyEvent backspace_r(ui::ET_KEY_RELEASED, ui::VKEY_DELETE, ui::EF_NONE);
1169 toplevel->OnKeyEvent(&backspace_r);
1170 EXPECT_FALSE(backspace_r.handled());
1172 toplevel->Close();
1175 // Verifies bubbles result in a focus lost when shown.
1176 // TODO(msw): this tests relies on focus, it needs to be in
1177 // interactive_ui_tests.
1178 TEST_F(WidgetTest, DISABLED_FocusChangesOnBubble) {
1179 // Create a widget, show and activate it and focus the contents view.
1180 View* contents_view = new View;
1181 contents_view->SetFocusable(true);
1182 Widget widget;
1183 Widget::InitParams init_params =
1184 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1185 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1186 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1187 #if !defined(OS_CHROMEOS)
1188 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1189 #endif
1190 widget.Init(init_params);
1191 widget.SetContentsView(contents_view);
1192 widget.Show();
1193 widget.Activate();
1194 contents_view->RequestFocus();
1195 EXPECT_TRUE(contents_view->HasFocus());
1197 // Show a bubble.
1198 BubbleDelegateView* bubble_delegate_view =
1199 new BubbleDelegateView(contents_view, BubbleBorder::TOP_LEFT);
1200 bubble_delegate_view->SetFocusable(true);
1201 BubbleDelegateView::CreateBubble(bubble_delegate_view)->Show();
1202 bubble_delegate_view->RequestFocus();
1204 // |contents_view_| should no longer have focus.
1205 EXPECT_FALSE(contents_view->HasFocus());
1206 EXPECT_TRUE(bubble_delegate_view->HasFocus());
1208 bubble_delegate_view->GetWidget()->CloseNow();
1210 // Closing the bubble should result in focus going back to the contents view.
1211 EXPECT_TRUE(contents_view->HasFocus());
1214 class TestBubbleDelegateView : public BubbleDelegateView {
1215 public:
1216 TestBubbleDelegateView(View* anchor)
1217 : BubbleDelegateView(anchor, BubbleBorder::NONE),
1218 reset_controls_called_(false) {}
1219 ~TestBubbleDelegateView() override {}
1221 bool ShouldShowCloseButton() const override {
1222 reset_controls_called_ = true;
1223 return true;
1226 mutable bool reset_controls_called_;
1229 TEST_F(WidgetTest, BubbleControlsResetOnInit) {
1230 Widget* anchor = CreateTopLevelPlatformWidget();
1231 anchor->Show();
1233 TestBubbleDelegateView* bubble_delegate =
1234 new TestBubbleDelegateView(anchor->client_view());
1235 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
1236 EXPECT_TRUE(bubble_delegate->reset_controls_called_);
1237 bubble_widget->Show();
1238 bubble_widget->CloseNow();
1240 anchor->Hide();
1241 anchor->CloseNow();
1244 #if defined(OS_WIN)
1245 // Test to ensure that after minimize, view width is set to zero. This is only
1246 // the case for desktop widgets on Windows. Other platforms retain the window
1247 // size while minimized.
1248 TEST_F(WidgetTest, TestViewWidthAfterMinimizingWidget) {
1249 // Create a widget.
1250 Widget widget;
1251 Widget::InitParams init_params =
1252 CreateParams(Widget::InitParams::TYPE_WINDOW);
1253 init_params.show_state = ui::SHOW_STATE_NORMAL;
1254 gfx::Rect initial_bounds(0, 0, 300, 400);
1255 init_params.bounds = initial_bounds;
1256 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1257 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1258 widget.Init(init_params);
1259 NonClientView* non_client_view = widget.non_client_view();
1260 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1261 non_client_view->SetFrameView(frame_view);
1262 // Setting the frame view doesn't do a layout, so force one.
1263 non_client_view->Layout();
1264 widget.Show();
1265 EXPECT_NE(0, frame_view->width());
1266 widget.Minimize();
1267 EXPECT_EQ(0, frame_view->width());
1269 #endif
1271 // Desktop native widget Aura tests are for non Chrome OS platforms.
1272 #if !defined(OS_CHROMEOS)
1273 // This class validates whether paints are received for a visible Widget.
1274 // To achieve this it overrides the Show and Close methods on the Widget class
1275 // and sets state whether subsequent paints are expected.
1276 class DesktopAuraTestValidPaintWidget : public views::Widget {
1277 public:
1278 DesktopAuraTestValidPaintWidget()
1279 : received_paint_(false),
1280 expect_paint_(true),
1281 received_paint_while_hidden_(false) {}
1283 ~DesktopAuraTestValidPaintWidget() override {}
1285 void InitForTest(Widget::InitParams create_params);
1287 void Show() override {
1288 expect_paint_ = true;
1289 views::Widget::Show();
1292 void Close() override {
1293 expect_paint_ = false;
1294 views::Widget::Close();
1297 void Hide() {
1298 expect_paint_ = false;
1299 views::Widget::Hide();
1302 void OnNativeWidgetPaint(gfx::Canvas* canvas) override {
1303 received_paint_ = true;
1304 EXPECT_TRUE(expect_paint_);
1305 if (!expect_paint_)
1306 received_paint_while_hidden_ = true;
1307 views::Widget::OnNativeWidgetPaint(canvas);
1310 bool ReadReceivedPaintAndReset() {
1311 bool result = received_paint_;
1312 received_paint_ = false;
1313 return result;
1316 bool received_paint_while_hidden() const {
1317 return received_paint_while_hidden_;
1320 private:
1321 bool received_paint_;
1322 bool expect_paint_;
1323 bool received_paint_while_hidden_;
1325 DISALLOW_COPY_AND_ASSIGN(DesktopAuraTestValidPaintWidget);
1328 void DesktopAuraTestValidPaintWidget::InitForTest(InitParams init_params) {
1329 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1330 init_params.ownership = InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1331 init_params.native_widget = new PlatformDesktopNativeWidget(this);
1332 Init(init_params);
1334 View* contents_view = new View;
1335 contents_view->SetFocusable(true);
1336 SetContentsView(contents_view);
1338 Show();
1339 Activate();
1342 TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterCloseTest) {
1343 DesktopAuraTestValidPaintWidget widget;
1344 widget.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS));
1345 RunPendingMessages();
1346 EXPECT_TRUE(widget.ReadReceivedPaintAndReset());
1347 widget.SchedulePaintInRect(widget.GetRestoredBounds());
1348 widget.Close();
1349 RunPendingMessages();
1350 EXPECT_FALSE(widget.ReadReceivedPaintAndReset());
1351 EXPECT_FALSE(widget.received_paint_while_hidden());
1354 TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterHideTest) {
1355 DesktopAuraTestValidPaintWidget widget;
1356 widget.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS));
1357 RunPendingMessages();
1358 EXPECT_TRUE(widget.ReadReceivedPaintAndReset());
1359 widget.SchedulePaintInRect(widget.GetRestoredBounds());
1360 widget.Hide();
1361 RunPendingMessages();
1362 EXPECT_FALSE(widget.ReadReceivedPaintAndReset());
1363 EXPECT_FALSE(widget.received_paint_while_hidden());
1364 widget.Close();
1367 // Test to ensure that the aura Window's visiblity state is set to visible if
1368 // the underlying widget is hidden and then shown.
1369 TEST_F(WidgetTest, TestWindowVisibilityAfterHide) {
1370 // Create a widget.
1371 Widget widget;
1372 Widget::InitParams init_params =
1373 CreateParams(Widget::InitParams::TYPE_WINDOW);
1374 init_params.show_state = ui::SHOW_STATE_NORMAL;
1375 gfx::Rect initial_bounds(0, 0, 300, 400);
1376 init_params.bounds = initial_bounds;
1377 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1378 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1379 widget.Init(init_params);
1380 NonClientView* non_client_view = widget.non_client_view();
1381 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1382 non_client_view->SetFrameView(frame_view);
1384 widget.Show();
1385 EXPECT_TRUE(IsNativeWindowVisible(widget.GetNativeWindow()));
1386 widget.Hide();
1387 EXPECT_FALSE(IsNativeWindowVisible(widget.GetNativeWindow()));
1388 widget.Show();
1389 EXPECT_TRUE(IsNativeWindowVisible(widget.GetNativeWindow()));
1392 #endif // !defined(OS_CHROMEOS)
1394 // Tests that wheel events generated from scroll events are targetted to the
1395 // views under the cursor when the focused view does not processed them.
1396 TEST_F(WidgetTest, WheelEventsFromScrollEventTarget) {
1397 EventCountView* cursor_view = new EventCountView;
1398 cursor_view->SetBounds(60, 0, 50, 40);
1400 Widget* widget = CreateTopLevelPlatformWidget();
1401 widget->GetRootView()->AddChildView(cursor_view);
1403 // Generate a scroll event on the cursor view.
1404 ui::ScrollEvent scroll(ui::ET_SCROLL,
1405 gfx::Point(65, 5),
1406 ui::EventTimeForNow(),
1408 0, 20,
1409 0, 20,
1411 widget->OnScrollEvent(&scroll);
1413 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_SCROLL));
1414 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1416 cursor_view->ResetCounts();
1418 ui::ScrollEvent scroll2(ui::ET_SCROLL,
1419 gfx::Point(5, 5),
1420 ui::EventTimeForNow(),
1422 0, 20,
1423 0, 20,
1425 widget->OnScrollEvent(&scroll2);
1427 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_SCROLL));
1428 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1430 widget->CloseNow();
1433 // Tests that if a scroll-begin gesture is not handled, then subsequent scroll
1434 // events are not dispatched to any view.
1435 TEST_F(WidgetTest, GestureScrollEventDispatching) {
1436 EventCountView* noscroll_view = new EventCountView;
1437 EventCountView* scroll_view = new ScrollableEventCountView;
1439 noscroll_view->SetBounds(0, 0, 50, 40);
1440 scroll_view->SetBounds(60, 0, 40, 40);
1442 Widget* widget = CreateTopLevelPlatformWidget();
1443 widget->GetRootView()->AddChildView(noscroll_view);
1444 widget->GetRootView()->AddChildView(scroll_view);
1447 ui::GestureEvent begin(
1451 base::TimeDelta(),
1452 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
1453 widget->OnGestureEvent(&begin);
1454 ui::GestureEvent update(
1458 base::TimeDelta(),
1459 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10));
1460 widget->OnGestureEvent(&update);
1461 ui::GestureEvent end(25,
1464 base::TimeDelta(),
1465 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
1466 widget->OnGestureEvent(&end);
1468 EXPECT_EQ(1, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1469 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1470 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1474 ui::GestureEvent begin(
1478 base::TimeDelta(),
1479 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
1480 widget->OnGestureEvent(&begin);
1481 ui::GestureEvent update(
1485 base::TimeDelta(),
1486 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10));
1487 widget->OnGestureEvent(&update);
1488 ui::GestureEvent end(85,
1491 base::TimeDelta(),
1492 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
1493 widget->OnGestureEvent(&end);
1495 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1496 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1497 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1500 widget->CloseNow();
1503 // Tests that event-handlers installed on the RootView get triggered correctly.
1504 // TODO(tdanderson): Clean up this test as part of crbug.com/355680.
1505 TEST_F(WidgetTest, EventHandlersOnRootView) {
1506 Widget* widget = CreateTopLevelNativeWidget();
1507 View* root_view = widget->GetRootView();
1509 scoped_ptr<EventCountView> view(new EventCountView());
1510 view->set_owned_by_client();
1511 view->SetBounds(0, 0, 20, 20);
1512 root_view->AddChildView(view.get());
1514 EventCountHandler h1;
1515 root_view->AddPreTargetHandler(&h1);
1517 EventCountHandler h2;
1518 root_view->AddPostTargetHandler(&h2);
1520 widget->SetBounds(gfx::Rect(0, 0, 100, 100));
1521 widget->Show();
1523 // Dispatch a ui::ET_SCROLL event. The event remains unhandled and should
1524 // bubble up the views hierarchy to be re-dispatched on the root view.
1525 ui::ScrollEvent scroll(ui::ET_SCROLL,
1526 gfx::Point(5, 5),
1527 ui::EventTimeForNow(),
1529 0, 20,
1530 0, 20,
1532 widget->OnScrollEvent(&scroll);
1533 EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL));
1534 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1535 EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL));
1537 // Unhandled scroll events are turned into wheel events and re-dispatched.
1538 EXPECT_EQ(1, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1539 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSEWHEEL));
1540 EXPECT_EQ(1, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1542 h1.ResetCounts();
1543 view->ResetCounts();
1544 h2.ResetCounts();
1546 // Dispatch a ui::ET_SCROLL_FLING_START event. The event remains unhandled and
1547 // should bubble up the views hierarchy to be re-dispatched on the root view.
1548 ui::ScrollEvent fling(ui::ET_SCROLL_FLING_START,
1549 gfx::Point(5, 5),
1550 ui::EventTimeForNow(),
1552 0, 20,
1553 0, 20,
1555 widget->OnScrollEvent(&fling);
1556 EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL_FLING_START));
1557 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL_FLING_START));
1558 EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL_FLING_START));
1560 // Unhandled scroll events which are not of type ui::ET_SCROLL should not
1561 // be turned into wheel events and re-dispatched.
1562 EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1563 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
1564 EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1566 h1.ResetCounts();
1567 view->ResetCounts();
1568 h2.ResetCounts();
1570 // Change the handle mode of |view| so that events are marked as handled at
1571 // the target phase.
1572 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
1574 // Dispatch a ui::ET_GESTURE_TAP_DOWN and a ui::ET_GESTURE_TAP_CANCEL event.
1575 // The events are handled at the target phase and should not reach the
1576 // post-target handler.
1577 ui::GestureEvent tap_down(5,
1580 ui::EventTimeForNow(),
1581 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
1582 widget->OnGestureEvent(&tap_down);
1583 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1584 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1585 EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1587 ui::GestureEvent tap_cancel(
1591 ui::EventTimeForNow(),
1592 ui::GestureEventDetails(ui::ET_GESTURE_TAP_CANCEL));
1593 widget->OnGestureEvent(&tap_cancel);
1594 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1595 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1596 EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1598 h1.ResetCounts();
1599 view->ResetCounts();
1600 h2.ResetCounts();
1602 // Dispatch a ui::ET_SCROLL event. The event is handled at the target phase
1603 // and should not reach the post-target handler.
1604 ui::ScrollEvent consumed_scroll(ui::ET_SCROLL,
1605 gfx::Point(5, 5),
1606 ui::EventTimeForNow(),
1608 0, 20,
1609 0, 20,
1611 widget->OnScrollEvent(&consumed_scroll);
1612 EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL));
1613 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1614 EXPECT_EQ(0, h2.GetEventCount(ui::ET_SCROLL));
1616 // Handled scroll events are not turned into wheel events and re-dispatched.
1617 EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1618 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
1619 EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1621 widget->CloseNow();
1624 TEST_F(WidgetTest, SynthesizeMouseMoveEvent) {
1625 Widget* widget = CreateTopLevelNativeWidget();
1626 View* root_view = widget->GetRootView();
1628 EventCountView* v1 = new EventCountView();
1629 v1->SetBounds(0, 0, 10, 10);
1630 root_view->AddChildView(v1);
1631 EventCountView* v2 = new EventCountView();
1632 v2->SetBounds(0, 10, 10, 10);
1633 root_view->AddChildView(v2);
1635 gfx::Point cursor_location(5, 5);
1636 ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
1637 ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
1638 widget->OnMouseEvent(&move);
1640 EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
1641 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1643 delete v1;
1644 v2->SetBounds(0, 0, 10, 10);
1645 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1647 widget->SynthesizeMouseMoveEvent();
1648 EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1651 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
1652 #if !defined(OS_MACOSX) || defined(USE_AURA)
1654 namespace {
1656 // ui::EventHandler which handles all mouse press events.
1657 class MousePressEventConsumer : public ui::EventHandler {
1658 public:
1659 MousePressEventConsumer() {}
1661 private:
1662 // ui::EventHandler:
1663 void OnMouseEvent(ui::MouseEvent* event) override {
1664 if (event->type() == ui::ET_MOUSE_PRESSED)
1665 event->SetHandled();
1668 DISALLOW_COPY_AND_ASSIGN(MousePressEventConsumer);
1671 } // namespace
1673 // Test that mouse presses and mouse releases are dispatched normally when a
1674 // touch is down.
1675 TEST_F(WidgetTest, MouseEventDispatchWhileTouchIsDown) {
1676 Widget* widget = CreateTopLevelNativeWidget();
1677 widget->Show();
1678 widget->SetSize(gfx::Size(300, 300));
1680 EventCountView* event_count_view = new EventCountView();
1681 event_count_view->SetBounds(0, 0, 300, 300);
1682 widget->GetRootView()->AddChildView(event_count_view);
1684 MousePressEventConsumer consumer;
1685 event_count_view->AddPostTargetHandler(&consumer);
1687 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1688 generator.PressTouch();
1689 generator.ClickLeftButton();
1691 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_PRESSED));
1692 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_RELEASED));
1694 widget->CloseNow();
1697 #endif // !defined(OS_MACOSX) || defined(USE_AURA)
1699 // Used by SingleWindowClosing to count number of times WindowClosing() has
1700 // been invoked.
1701 class ClosingDelegate : public WidgetDelegate {
1702 public:
1703 ClosingDelegate() : count_(0), widget_(NULL) {}
1705 int count() const { return count_; }
1707 void set_widget(views::Widget* widget) { widget_ = widget; }
1709 // WidgetDelegate overrides:
1710 Widget* GetWidget() override { return widget_; }
1711 const Widget* GetWidget() const override { return widget_; }
1712 void WindowClosing() override { count_++; }
1714 private:
1715 int count_;
1716 views::Widget* widget_;
1718 DISALLOW_COPY_AND_ASSIGN(ClosingDelegate);
1721 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget
1722 // is closed.
1723 TEST_F(WidgetTest, SingleWindowClosing) {
1724 scoped_ptr<ClosingDelegate> delegate(new ClosingDelegate());
1725 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1726 Widget::InitParams init_params =
1727 CreateParams(Widget::InitParams::TYPE_WINDOW);
1728 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1729 init_params.delegate = delegate.get();
1730 #if !defined(OS_CHROMEOS)
1731 init_params.native_widget = new PlatformDesktopNativeWidget(widget);
1732 #endif
1733 widget->Init(init_params);
1734 EXPECT_EQ(0, delegate->count());
1735 widget->CloseNow();
1736 EXPECT_EQ(1, delegate->count());
1739 class WidgetWindowTitleTest : public WidgetTest {
1740 protected:
1741 void RunTest(bool desktop_native_widget) {
1742 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1743 Widget::InitParams init_params =
1744 CreateParams(Widget::InitParams::TYPE_WINDOW);
1745 widget->Init(init_params);
1747 #if !defined(OS_CHROMEOS)
1748 if (desktop_native_widget)
1749 init_params.native_widget = new PlatformDesktopNativeWidget(widget);
1750 #else
1751 DCHECK(!desktop_native_widget)
1752 << "DesktopNativeWidget does not exist on non-Aura or on ChromeOS.";
1753 #endif
1755 internal::NativeWidgetPrivate* native_widget =
1756 widget->native_widget_private();
1758 base::string16 empty;
1759 base::string16 s1(base::UTF8ToUTF16("Title1"));
1760 base::string16 s2(base::UTF8ToUTF16("Title2"));
1761 base::string16 s3(base::UTF8ToUTF16("TitleLong"));
1763 // The widget starts with no title, setting empty should not change
1764 // anything.
1765 EXPECT_FALSE(native_widget->SetWindowTitle(empty));
1766 // Setting the title to something non-empty should cause a change.
1767 EXPECT_TRUE(native_widget->SetWindowTitle(s1));
1768 // Setting the title to something else with the same length should cause a
1769 // change.
1770 EXPECT_TRUE(native_widget->SetWindowTitle(s2));
1771 // Setting the title to something else with a different length should cause
1772 // a change.
1773 EXPECT_TRUE(native_widget->SetWindowTitle(s3));
1774 // Setting the title to the same thing twice should not cause a change.
1775 EXPECT_FALSE(native_widget->SetWindowTitle(s3));
1777 widget->CloseNow();
1781 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_NativeWidget) {
1782 // Use the default NativeWidget.
1783 bool desktop_native_widget = false;
1784 RunTest(desktop_native_widget);
1787 // DesktopNativeWidget does not exist on non-Aura or on ChromeOS.
1788 #if !defined(OS_CHROMEOS)
1789 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_DesktopNativeWidget) {
1790 // Override to use a DesktopNativeWidget.
1791 bool desktop_native_widget = true;
1792 RunTest(desktop_native_widget);
1794 #endif // !OS_CHROMEOS
1796 TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) {
1797 Widget* widget = new Widget;
1798 Widget::InitParams params =
1799 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1800 widget->Init(params);
1802 widget->SetContentsView(new CloseWidgetView(ui::ET_MOUSE_PRESSED));
1804 widget->SetSize(gfx::Size(100, 100));
1805 widget->Show();
1807 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1809 WidgetDeletionObserver deletion_observer(widget);
1810 generator.ClickLeftButton();
1811 EXPECT_FALSE(deletion_observer.IsWidgetAlive());
1813 // Yay we did not crash!
1816 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
1817 #if !defined(OS_MACOSX) || defined(USE_AURA)
1819 TEST_F(WidgetTest, WidgetDeleted_InDispatchGestureEvent) {
1820 Widget* widget = new Widget;
1821 Widget::InitParams params =
1822 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1823 widget->Init(params);
1825 widget->SetContentsView(new CloseWidgetView(ui::ET_GESTURE_TAP_DOWN));
1827 widget->SetSize(gfx::Size(100, 100));
1828 widget->Show();
1830 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1832 WidgetDeletionObserver deletion_observer(widget);
1833 generator.GestureTapAt(widget->GetWindowBoundsInScreen().CenterPoint());
1834 EXPECT_FALSE(deletion_observer.IsWidgetAlive());
1836 // Yay we did not crash!
1839 #endif // !defined(OS_MACOSX) || defined(USE_AURA)
1841 // See description of RunGetNativeThemeFromDestructor() for details.
1842 class GetNativeThemeFromDestructorView : public WidgetDelegateView {
1843 public:
1844 GetNativeThemeFromDestructorView() {}
1845 ~GetNativeThemeFromDestructorView() override { VerifyNativeTheme(); }
1847 View* GetContentsView() override { return this; }
1849 private:
1850 void VerifyNativeTheme() {
1851 ASSERT_TRUE(GetNativeTheme() != NULL);
1854 DISALLOW_COPY_AND_ASSIGN(GetNativeThemeFromDestructorView);
1857 // Verifies GetNativeTheme() from the destructor of a WidgetDelegateView doesn't
1858 // crash. |is_first_run| is true if this is the first call. A return value of
1859 // true indicates this should be run again with a value of false.
1860 // First run uses DesktopNativeWidgetAura (if possible). Second run doesn't.
1861 bool RunGetNativeThemeFromDestructor(const Widget::InitParams& in_params,
1862 bool is_first_run) {
1863 bool needs_second_run = false;
1864 // Destroyed by CloseNow() below.
1865 Widget* widget = new Widget;
1866 Widget::InitParams params(in_params);
1867 // Deletes itself when the Widget is destroyed.
1868 params.delegate = new GetNativeThemeFromDestructorView;
1869 #if !defined(OS_CHROMEOS)
1870 if (is_first_run) {
1871 params.native_widget = new PlatformDesktopNativeWidget(widget);
1872 needs_second_run = true;
1874 #endif
1875 widget->Init(params);
1876 widget->CloseNow();
1877 return needs_second_run;
1880 // See description of RunGetNativeThemeFromDestructor() for details.
1881 TEST_F(WidgetTest, GetNativeThemeFromDestructor) {
1882 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1883 if (RunGetNativeThemeFromDestructor(params, true))
1884 RunGetNativeThemeFromDestructor(params, false);
1887 // Used by HideCloseDestroy. Allows setting a boolean when the widget is
1888 // destroyed.
1889 class CloseDestroysWidget : public Widget {
1890 public:
1891 explicit CloseDestroysWidget(bool* destroyed)
1892 : destroyed_(destroyed) {
1895 ~CloseDestroysWidget() override {
1896 if (destroyed_) {
1897 *destroyed_ = true;
1898 base::MessageLoop::current()->QuitNow();
1902 void Detach() { destroyed_ = NULL; }
1904 private:
1905 // If non-null set to true from destructor.
1906 bool* destroyed_;
1908 DISALLOW_COPY_AND_ASSIGN(CloseDestroysWidget);
1911 // An observer that registers that an animation has ended.
1912 class AnimationEndObserver : public ui::ImplicitAnimationObserver {
1913 public:
1914 AnimationEndObserver() : animation_completed_(false) {}
1915 ~AnimationEndObserver() override {}
1917 bool animation_completed() const { return animation_completed_; }
1919 // ui::ImplicitAnimationObserver:
1920 void OnImplicitAnimationsCompleted() override { animation_completed_ = true; }
1922 private:
1923 bool animation_completed_;
1925 DISALLOW_COPY_AND_ASSIGN(AnimationEndObserver);
1928 // An observer that registers the bounds of a widget on destruction.
1929 class WidgetBoundsObserver : public WidgetObserver {
1930 public:
1931 WidgetBoundsObserver() {}
1932 ~WidgetBoundsObserver() override {}
1934 gfx::Rect bounds() { return bounds_; }
1936 // WidgetObserver:
1937 void OnWidgetDestroying(Widget* widget) override {
1938 bounds_ = widget->GetWindowBoundsInScreen();
1941 private:
1942 gfx::Rect bounds_;
1944 DISALLOW_COPY_AND_ASSIGN(WidgetBoundsObserver);
1947 // Verifies Close() results in destroying.
1948 TEST_F(WidgetTest, CloseDestroys) {
1949 bool destroyed = false;
1950 CloseDestroysWidget* widget = new CloseDestroysWidget(&destroyed);
1951 Widget::InitParams params =
1952 CreateParams(views::Widget::InitParams::TYPE_MENU);
1953 params.opacity = Widget::InitParams::OPAQUE_WINDOW;
1954 #if !defined(OS_CHROMEOS)
1955 params.native_widget = new PlatformDesktopNativeWidget(widget);
1956 #endif
1957 widget->Init(params);
1958 widget->Show();
1959 widget->Hide();
1960 widget->Close();
1961 EXPECT_FALSE(destroyed);
1962 // Run the message loop as Close() asynchronously deletes.
1963 base::RunLoop().Run();
1964 EXPECT_TRUE(destroyed);
1965 // Close() should destroy the widget. If not we'll cleanup to avoid leaks.
1966 if (!destroyed) {
1967 widget->Detach();
1968 widget->CloseNow();
1972 // Tests that killing a widget while animating it does not crash.
1973 TEST_F(WidgetTest, CloseWidgetWhileAnimating) {
1974 scoped_ptr<Widget> widget(new Widget);
1975 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1976 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1977 params.bounds = gfx::Rect(50, 50, 250, 250);
1978 widget->Init(params);
1979 AnimationEndObserver animation_observer;
1980 WidgetBoundsObserver widget_observer;
1981 gfx::Rect bounds(0, 0, 50, 50);
1983 // Normal animations for tests have ZERO_DURATION, make sure we are actually
1984 // animating the movement.
1985 ui::ScopedAnimationDurationScaleMode animation_scale_mode(
1986 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
1987 ui::ScopedLayerAnimationSettings animation_settings(
1988 widget->GetLayer()->GetAnimator());
1989 animation_settings.AddObserver(&animation_observer);
1990 widget->AddObserver(&widget_observer);
1991 widget->Show();
1993 // Animate the bounds change.
1994 widget->SetBounds(bounds);
1995 widget.reset();
1996 EXPECT_FALSE(animation_observer.animation_completed());
1998 EXPECT_TRUE(animation_observer.animation_completed());
1999 EXPECT_EQ(widget_observer.bounds(), bounds);
2002 // Tests that we do not crash when a Widget is destroyed by going out of
2003 // scope (as opposed to being explicitly deleted by its NativeWidget).
2004 TEST_F(WidgetTest, NoCrashOnWidgetDelete) {
2005 scoped_ptr<Widget> widget(new Widget);
2006 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2007 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2008 widget->Init(params);
2011 // Tests that we do not crash when a Widget is destroyed before it finishes
2012 // processing of pending input events in the message loop.
2013 TEST_F(WidgetTest, NoCrashOnWidgetDeleteWithPendingEvents) {
2014 scoped_ptr<Widget> widget(new Widget);
2015 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
2016 params.bounds = gfx::Rect(0, 0, 200, 200);
2017 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2018 widget->Init(params);
2019 widget->Show();
2021 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
2022 generator.MoveMouseTo(10, 10);
2024 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
2025 #if defined(OS_MACOSX) && !defined(USE_AURA)
2026 generator.ClickLeftButton();
2027 #else
2028 generator.PressTouch();
2029 #endif
2030 widget.reset();
2033 // A view that consumes mouse-pressed event and gesture-tap-down events.
2034 class RootViewTestView : public View {
2035 public:
2036 RootViewTestView(): View() {}
2038 private:
2039 bool OnMousePressed(const ui::MouseEvent& event) override { return true; }
2041 void OnGestureEvent(ui::GestureEvent* event) override {
2042 if (event->type() == ui::ET_GESTURE_TAP_DOWN)
2043 event->SetHandled();
2047 // Checks if RootView::*_handler_ fields are unset when widget is hidden.
2048 // Fails on chromium.webkit Windows bot, see crbug.com/264872.
2049 #if defined(OS_WIN)
2050 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
2051 DISABLED_TestRootViewHandlersWhenHidden
2052 #else
2053 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
2054 TestRootViewHandlersWhenHidden
2055 #endif
2056 TEST_F(WidgetTest, MAYBE_DisableTestRootViewHandlersWhenHidden) {
2057 Widget* widget = CreateTopLevelNativeWidget();
2058 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2059 View* view = new RootViewTestView();
2060 view->SetBounds(0, 0, 300, 300);
2061 internal::RootView* root_view =
2062 static_cast<internal::RootView*>(widget->GetRootView());
2063 root_view->AddChildView(view);
2065 // Check RootView::mouse_pressed_handler_.
2066 widget->Show();
2067 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
2068 gfx::Point click_location(45, 15);
2069 ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
2070 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
2071 ui::EF_LEFT_MOUSE_BUTTON);
2072 widget->OnMouseEvent(&press);
2073 EXPECT_EQ(view, GetMousePressedHandler(root_view));
2074 widget->Hide();
2075 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
2077 // Check RootView::mouse_move_handler_.
2078 widget->Show();
2079 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
2080 gfx::Point move_location(45, 15);
2081 ui::MouseEvent move(ui::ET_MOUSE_MOVED, move_location, move_location,
2082 ui::EventTimeForNow(), 0, 0);
2083 widget->OnMouseEvent(&move);
2084 EXPECT_EQ(view, GetMouseMoveHandler(root_view));
2085 widget->Hide();
2086 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
2088 // Check RootView::gesture_handler_.
2089 widget->Show();
2090 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2091 ui::GestureEvent tap_down(15,
2094 base::TimeDelta(),
2095 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
2096 widget->OnGestureEvent(&tap_down);
2097 EXPECT_EQ(view, GetGestureHandler(root_view));
2098 widget->Hide();
2099 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2101 widget->Close();
2104 // Convenience to make constructing a GestureEvent simpler.
2105 class GestureEventForTest : public ui::GestureEvent {
2106 public:
2107 GestureEventForTest(ui::EventType type, int x, int y)
2108 : GestureEvent(x,
2111 base::TimeDelta(),
2112 ui::GestureEventDetails(type)) {}
2114 GestureEventForTest(ui::GestureEventDetails details, int x, int y)
2115 : GestureEvent(x, y, 0, base::TimeDelta(), details) {}
2118 // Tests that the |gesture_handler_| member in RootView is always NULL
2119 // after the dispatch of a ui::ET_GESTURE_END event corresponding to
2120 // the release of the final touch point on the screen, but that
2121 // ui::ET_GESTURE_END events corresponding to the removal of any other touch
2122 // point do not modify |gesture_handler_|.
2123 TEST_F(WidgetTest, GestureEndEvents) {
2124 Widget* widget = CreateTopLevelNativeWidget();
2125 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2126 EventCountView* view = new EventCountView();
2127 view->SetBounds(0, 0, 300, 300);
2128 internal::RootView* root_view =
2129 static_cast<internal::RootView*>(widget->GetRootView());
2130 root_view->AddChildView(view);
2131 widget->Show();
2133 // If no gesture handler is set, a ui::ET_GESTURE_END event should not set
2134 // the gesture handler.
2135 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2136 GestureEventForTest end(ui::ET_GESTURE_END, 15, 15);
2137 widget->OnGestureEvent(&end);
2138 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2140 // Change the handle mode of |view| to indicate that it would like
2141 // to handle all events, then send a GESTURE_TAP to set the gesture handler.
2142 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
2143 GestureEventForTest tap(ui::ET_GESTURE_TAP, 15, 15);
2144 widget->OnGestureEvent(&tap);
2145 EXPECT_TRUE(tap.handled());
2146 EXPECT_EQ(view, GetGestureHandler(root_view));
2148 // The gesture handler should remain unchanged on a ui::ET_GESTURE_END
2149 // corresponding to a second touch point, but should be reset to NULL by a
2150 // ui::ET_GESTURE_END corresponding to the final touch point.
2151 ui::GestureEventDetails details(ui::ET_GESTURE_END);
2152 details.set_touch_points(2);
2153 GestureEventForTest end_second_touch_point(details, 15, 15);
2154 widget->OnGestureEvent(&end_second_touch_point);
2155 EXPECT_EQ(view, GetGestureHandler(root_view));
2157 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15);
2158 widget->OnGestureEvent(&end);
2159 EXPECT_TRUE(end.handled());
2160 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2162 // Send a GESTURE_TAP to set the gesture handler, then change the handle
2163 // mode of |view| to indicate that it does not want to handle any
2164 // further events.
2165 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 15, 15);
2166 widget->OnGestureEvent(&tap);
2167 EXPECT_TRUE(tap.handled());
2168 EXPECT_EQ(view, GetGestureHandler(root_view));
2169 view->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2171 // The gesture handler should remain unchanged on a ui::ET_GESTURE_END
2172 // corresponding to a second touch point, but should be reset to NULL by a
2173 // ui::ET_GESTURE_END corresponding to the final touch point.
2174 end_second_touch_point = GestureEventForTest(details, 15, 15);
2175 widget->OnGestureEvent(&end_second_touch_point);
2176 EXPECT_EQ(view, GetGestureHandler(root_view));
2178 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15);
2179 widget->OnGestureEvent(&end);
2180 EXPECT_FALSE(end.handled());
2181 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2183 widget->Close();
2186 // Tests that gesture events which should not be processed (because
2187 // RootView::OnEventProcessingStarted() has marked them as handled) are not
2188 // dispatched to any views.
2189 TEST_F(WidgetTest, GestureEventsNotProcessed) {
2190 Widget* widget = CreateTopLevelNativeWidget();
2191 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2193 // Define a hierarchy of four views (coordinates are in
2194 // their parent coordinate space).
2195 // v1 (0, 0, 300, 300)
2196 // v2 (0, 0, 100, 100)
2197 // v3 (0, 0, 50, 50)
2198 // v4(0, 0, 10, 10)
2199 EventCountView* v1 = new EventCountView();
2200 v1->SetBounds(0, 0, 300, 300);
2201 EventCountView* v2 = new EventCountView();
2202 v2->SetBounds(0, 0, 100, 100);
2203 EventCountView* v3 = new EventCountView();
2204 v3->SetBounds(0, 0, 50, 50);
2205 EventCountView* v4 = new EventCountView();
2206 v4->SetBounds(0, 0, 10, 10);
2207 internal::RootView* root_view =
2208 static_cast<internal::RootView*>(widget->GetRootView());
2209 root_view->AddChildView(v1);
2210 v1->AddChildView(v2);
2211 v2->AddChildView(v3);
2212 v3->AddChildView(v4);
2214 widget->Show();
2216 // ui::ET_GESTURE_BEGIN events should never be seen by any view, but
2217 // they should be marked as handled by OnEventProcessingStarted().
2218 GestureEventForTest begin(ui::ET_GESTURE_BEGIN, 5, 5);
2219 widget->OnGestureEvent(&begin);
2220 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_BEGIN));
2221 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_BEGIN));
2222 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_BEGIN));
2223 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_BEGIN));
2224 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2225 EXPECT_TRUE(begin.handled());
2226 v1->ResetCounts();
2227 v2->ResetCounts();
2228 v3->ResetCounts();
2229 v4->ResetCounts();
2231 // ui::ET_GESTURE_END events should not be seen by any view when there is
2232 // no default gesture handler set, but they should be marked as handled by
2233 // OnEventProcessingStarted().
2234 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2235 widget->OnGestureEvent(&end);
2236 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2237 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2238 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2239 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2240 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2241 EXPECT_TRUE(end.handled());
2242 v1->ResetCounts();
2243 v2->ResetCounts();
2244 v3->ResetCounts();
2245 v4->ResetCounts();
2247 // ui::ET_GESTURE_END events not corresponding to the release of the
2248 // final touch point should never be seen by any view, but they should
2249 // be marked as handled by OnEventProcessingStarted().
2250 ui::GestureEventDetails details(ui::ET_GESTURE_END);
2251 details.set_touch_points(2);
2252 GestureEventForTest end_second_touch_point(details, 5, 5);
2253 widget->OnGestureEvent(&end_second_touch_point);
2254 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2255 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2256 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2257 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2258 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2259 EXPECT_TRUE(end_second_touch_point.handled());
2260 v1->ResetCounts();
2261 v2->ResetCounts();
2262 v3->ResetCounts();
2263 v4->ResetCounts();
2265 // ui::ET_GESTURE_SCROLL_UPDATE events should never be seen by any view when
2266 // there is no default gesture handler set, but they should be marked as
2267 // handled by OnEventProcessingStarted().
2268 GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, 5, 5);
2269 widget->OnGestureEvent(&scroll_update);
2270 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2271 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2272 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2273 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2274 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2275 EXPECT_TRUE(scroll_update.handled());
2276 v1->ResetCounts();
2277 v2->ResetCounts();
2278 v3->ResetCounts();
2279 v4->ResetCounts();
2281 // ui::ET_GESTURE_SCROLL_END events should never be seen by any view when
2282 // there is no default gesture handler set, but they should be marked as
2283 // handled by OnEventProcessingStarted().
2284 GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, 5, 5);
2285 widget->OnGestureEvent(&scroll_end);
2286 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2287 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2288 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2289 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2290 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2291 EXPECT_TRUE(scroll_end.handled());
2292 v1->ResetCounts();
2293 v2->ResetCounts();
2294 v3->ResetCounts();
2295 v4->ResetCounts();
2297 // ui::ET_SCROLL_FLING_START events should never be seen by any view when
2298 // there is no default gesture handler set, but they should be marked as
2299 // handled by OnEventProcessingStarted().
2300 GestureEventForTest scroll_fling_start(ui::ET_SCROLL_FLING_START, 5, 5);
2301 widget->OnGestureEvent(&scroll_fling_start);
2302 EXPECT_EQ(0, v1->GetEventCount(ui::ET_SCROLL_FLING_START));
2303 EXPECT_EQ(0, v2->GetEventCount(ui::ET_SCROLL_FLING_START));
2304 EXPECT_EQ(0, v3->GetEventCount(ui::ET_SCROLL_FLING_START));
2305 EXPECT_EQ(0, v4->GetEventCount(ui::ET_SCROLL_FLING_START));
2306 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2307 EXPECT_TRUE(scroll_fling_start.handled());
2308 v1->ResetCounts();
2309 v2->ResetCounts();
2310 v3->ResetCounts();
2311 v4->ResetCounts();
2313 widget->Close();
2316 // Tests that a (non-scroll) gesture event is dispatched to the correct views
2317 // in a view hierarchy and that the default gesture handler in RootView is set
2318 // correctly.
2319 TEST_F(WidgetTest, GestureEventDispatch) {
2320 Widget* widget = CreateTopLevelNativeWidget();
2321 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2323 // Define a hierarchy of four views (coordinates are in
2324 // their parent coordinate space).
2325 // v1 (0, 0, 300, 300)
2326 // v2 (0, 0, 100, 100)
2327 // v3 (0, 0, 50, 50)
2328 // v4(0, 0, 10, 10)
2329 EventCountView* v1 = new EventCountView();
2330 v1->SetBounds(0, 0, 300, 300);
2331 EventCountView* v2 = new EventCountView();
2332 v2->SetBounds(0, 0, 100, 100);
2333 EventCountView* v3 = new EventCountView();
2334 v3->SetBounds(0, 0, 50, 50);
2335 EventCountView* v4 = new EventCountView();
2336 v4->SetBounds(0, 0, 10, 10);
2337 internal::RootView* root_view =
2338 static_cast<internal::RootView*>(widget->GetRootView());
2339 root_view->AddChildView(v1);
2340 v1->AddChildView(v2);
2341 v2->AddChildView(v3);
2342 v3->AddChildView(v4);
2344 widget->Show();
2346 // No gesture handler is set in the root view and none of the views in the
2347 // view hierarchy handle a ui::ET_GESTURE_TAP event. In this case the tap
2348 // event should be dispatched to all views in the hierarchy, the gesture
2349 // handler should remain unset, and the event should remain unhandled.
2350 GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5);
2351 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2352 widget->OnGestureEvent(&tap);
2353 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_TAP));
2354 EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_TAP));
2355 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2356 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2357 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2358 EXPECT_FALSE(tap.handled());
2360 // No gesture handler is set in the root view and |v1|, |v2|, and |v3| all
2361 // handle a ui::ET_GESTURE_TAP event. In this case the tap event should be
2362 // dispatched to |v4| and |v3|, the gesture handler should be set to |v3|,
2363 // and the event should be marked as handled.
2364 v1->ResetCounts();
2365 v2->ResetCounts();
2366 v3->ResetCounts();
2367 v4->ResetCounts();
2368 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2369 v2->set_handle_mode(EventCountView::CONSUME_EVENTS);
2370 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2371 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2372 widget->OnGestureEvent(&tap);
2373 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2374 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2375 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2376 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2377 EXPECT_EQ(v3, GetGestureHandler(root_view));
2378 EXPECT_TRUE(tap.handled());
2380 // The gesture handler is set to |v3| and all views handle all gesture event
2381 // types. In this case subsequent gesture events should only be dispatched to
2382 // |v3| and marked as handled. The gesture handler should remain as |v3|.
2383 v1->ResetCounts();
2384 v2->ResetCounts();
2385 v3->ResetCounts();
2386 v4->ResetCounts();
2387 v4->set_handle_mode(EventCountView::CONSUME_EVENTS);
2388 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2389 widget->OnGestureEvent(&tap);
2390 EXPECT_TRUE(tap.handled());
2391 GestureEventForTest show_press(ui::ET_GESTURE_SHOW_PRESS, 5, 5);
2392 widget->OnGestureEvent(&show_press);
2393 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2394 widget->OnGestureEvent(&tap);
2395 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2396 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2397 EXPECT_EQ(2, v3->GetEventCount(ui::ET_GESTURE_TAP));
2398 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2399 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2400 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2401 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2402 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2403 EXPECT_TRUE(tap.handled());
2404 EXPECT_TRUE(show_press.handled());
2405 EXPECT_EQ(v3, GetGestureHandler(root_view));
2407 // The gesture handler is set to |v3|, but |v3| does not handle
2408 // ui::ET_GESTURE_TAP events. In this case a tap gesture should be dispatched
2409 // only to |v3|, but the event should remain unhandled. The gesture handler
2410 // should remain as |v3|.
2411 v1->ResetCounts();
2412 v2->ResetCounts();
2413 v3->ResetCounts();
2414 v4->ResetCounts();
2415 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2416 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2417 widget->OnGestureEvent(&tap);
2418 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2419 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2420 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2421 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2422 EXPECT_FALSE(tap.handled());
2423 EXPECT_EQ(v3, GetGestureHandler(root_view));
2425 widget->Close();
2428 // Tests that gesture scroll events will change the default gesture handler in
2429 // RootView if the current handler to which they are dispatched does not handle
2430 // gesture scroll events.
2431 TEST_F(WidgetTest, ScrollGestureEventDispatch) {
2432 Widget* widget = CreateTopLevelNativeWidget();
2433 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2435 // Define a hierarchy of four views (coordinates are in
2436 // their parent coordinate space).
2437 // v1 (0, 0, 300, 300)
2438 // v2 (0, 0, 100, 100)
2439 // v3 (0, 0, 50, 50)
2440 // v4(0, 0, 10, 10)
2441 EventCountView* v1 = new EventCountView();
2442 v1->SetBounds(0, 0, 300, 300);
2443 EventCountView* v2 = new EventCountView();
2444 v2->SetBounds(0, 0, 100, 100);
2445 EventCountView* v3 = new EventCountView();
2446 v3->SetBounds(0, 0, 50, 50);
2447 EventCountView* v4 = new EventCountView();
2448 v4->SetBounds(0, 0, 10, 10);
2449 internal::RootView* root_view =
2450 static_cast<internal::RootView*>(widget->GetRootView());
2451 root_view->AddChildView(v1);
2452 v1->AddChildView(v2);
2453 v2->AddChildView(v3);
2454 v3->AddChildView(v4);
2456 widget->Show();
2458 // Change the handle mode of |v3| to indicate that it would like to handle
2459 // gesture events.
2460 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2462 // When no gesture handler is set, dispatching a ui::ET_GESTURE_TAP_DOWN
2463 // should bubble up the views hierarchy until it reaches the first view
2464 // that will handle it (|v3|) and then sets the handler to |v3|.
2465 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2466 GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, 5, 5);
2467 widget->OnGestureEvent(&tap_down);
2468 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2469 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2470 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2471 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2472 EXPECT_EQ(v3, GetGestureHandler(root_view));
2473 EXPECT_TRUE(tap_down.handled());
2474 v1->ResetCounts();
2475 v2->ResetCounts();
2476 v3->ResetCounts();
2477 v4->ResetCounts();
2479 // A ui::ET_GESTURE_TAP_CANCEL event should be dispatched to |v3| directly.
2480 GestureEventForTest tap_cancel(ui::ET_GESTURE_TAP_CANCEL, 5, 5);
2481 widget->OnGestureEvent(&tap_cancel);
2482 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2483 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2484 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2485 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2486 EXPECT_EQ(v3, GetGestureHandler(root_view));
2487 EXPECT_TRUE(tap_cancel.handled());
2488 v1->ResetCounts();
2489 v2->ResetCounts();
2490 v3->ResetCounts();
2491 v4->ResetCounts();
2493 // Change the handle mode of |v3| to indicate that it would no longer like
2494 // to handle events, and change the mode of |v1| to indicate that it would
2495 // like to handle events.
2496 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2497 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2499 // Dispatch a ui::ET_GESTURE_SCROLL_BEGIN event. Because the current gesture
2500 // handler (|v3|) does not handle scroll events, the event should bubble up
2501 // the views hierarchy until it reaches the first view that will handle
2502 // it (|v1|) and then sets the handler to |v1|.
2503 GestureEventForTest scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN, 5, 5);
2504 widget->OnGestureEvent(&scroll_begin);
2505 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2506 EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2507 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2508 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2509 EXPECT_EQ(v1, GetGestureHandler(root_view));
2510 EXPECT_TRUE(scroll_begin.handled());
2511 v1->ResetCounts();
2512 v2->ResetCounts();
2513 v3->ResetCounts();
2514 v4->ResetCounts();
2516 // A ui::ET_GESTURE_SCROLL_UPDATE event should be dispatched to |v1|
2517 // directly.
2518 GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, 5, 5);
2519 widget->OnGestureEvent(&scroll_update);
2520 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2521 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2522 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2523 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2524 EXPECT_EQ(v1, GetGestureHandler(root_view));
2525 EXPECT_TRUE(scroll_update.handled());
2526 v1->ResetCounts();
2527 v2->ResetCounts();
2528 v3->ResetCounts();
2529 v4->ResetCounts();
2531 // A ui::ET_GESTURE_SCROLL_END event should be dispatched to |v1|
2532 // directly and should not reset the gesture handler.
2533 GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, 5, 5);
2534 widget->OnGestureEvent(&scroll_end);
2535 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2536 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2537 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2538 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2539 EXPECT_EQ(v1, GetGestureHandler(root_view));
2540 EXPECT_TRUE(scroll_end.handled());
2541 v1->ResetCounts();
2542 v2->ResetCounts();
2543 v3->ResetCounts();
2544 v4->ResetCounts();
2546 // A ui::ET_GESTURE_PINCH_BEGIN event (which is a non-scroll event) should
2547 // still be dispatched to |v1| directly.
2548 GestureEventForTest pinch_begin(ui::ET_GESTURE_PINCH_BEGIN, 5, 5);
2549 widget->OnGestureEvent(&pinch_begin);
2550 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2551 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2552 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2553 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2554 EXPECT_EQ(v1, GetGestureHandler(root_view));
2555 EXPECT_TRUE(pinch_begin.handled());
2556 v1->ResetCounts();
2557 v2->ResetCounts();
2558 v3->ResetCounts();
2559 v4->ResetCounts();
2561 // A ui::ET_GESTURE_END event should be dispatched to |v1| and should
2562 // set the gesture handler to NULL.
2563 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2564 widget->OnGestureEvent(&end);
2565 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_END));
2566 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2567 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2568 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2569 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2570 EXPECT_TRUE(end.handled());
2572 widget->Close();
2575 // A class used in WidgetTest.GestureEventLocationWhileBubbling to verify
2576 // that when a gesture event bubbles up a View hierarchy, the location
2577 // of a gesture event seen by each View is in the local coordinate space
2578 // of that View.
2579 class GestureLocationView : public EventCountView {
2580 public:
2581 GestureLocationView() {}
2582 ~GestureLocationView() override {}
2584 void set_expected_location(gfx::Point expected_location) {
2585 expected_location_ = expected_location;
2588 // EventCountView:
2589 void OnGestureEvent(ui::GestureEvent* event) override {
2590 EventCountView::OnGestureEvent(event);
2592 // Verify that the location of |event| is in the local coordinate
2593 // space of |this|.
2594 EXPECT_EQ(expected_location_, event->location());
2597 private:
2598 // The expected location of a gesture event dispatched to |this|.
2599 gfx::Point expected_location_;
2601 DISALLOW_COPY_AND_ASSIGN(GestureLocationView);
2604 // Verifies that the location of a gesture event is always in the local
2605 // coordinate space of the View receiving the event while bubbling.
2606 TEST_F(WidgetTest, GestureEventLocationWhileBubbling) {
2607 Widget* widget = CreateTopLevelNativeWidget();
2608 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2610 // Define a hierarchy of three views (coordinates shown below are in the
2611 // coordinate space of the root view, but the coordinates used for
2612 // SetBounds() are in their parent coordinate space).
2613 // v1 (50, 50, 150, 150)
2614 // v2 (100, 70, 50, 80)
2615 // v3 (120, 100, 10, 10)
2616 GestureLocationView* v1 = new GestureLocationView();
2617 v1->SetBounds(50, 50, 150, 150);
2618 GestureLocationView* v2 = new GestureLocationView();
2619 v2->SetBounds(50, 20, 50, 80);
2620 GestureLocationView* v3 = new GestureLocationView();
2621 v3->SetBounds(20, 30, 10, 10);
2622 internal::RootView* root_view =
2623 static_cast<internal::RootView*>(widget->GetRootView());
2624 root_view->AddChildView(v1);
2625 v1->AddChildView(v2);
2626 v2->AddChildView(v3);
2628 widget->Show();
2630 // Define a GESTURE_TAP event located at (125, 105) in root view coordinates.
2631 // This event is contained within all of |v1|, |v2|, and |v3|.
2632 gfx::Point location_in_root(125, 105);
2633 GestureEventForTest tap(
2634 ui::ET_GESTURE_TAP, location_in_root.x(), location_in_root.y());
2636 // Calculate the location of the event in the local coordinate spaces
2637 // of each of the views.
2638 gfx::Point location_in_v1(ConvertPointFromWidgetToView(v1, location_in_root));
2639 EXPECT_EQ(gfx::Point(75, 55), location_in_v1);
2640 gfx::Point location_in_v2(ConvertPointFromWidgetToView(v2, location_in_root));
2641 EXPECT_EQ(gfx::Point(25, 35), location_in_v2);
2642 gfx::Point location_in_v3(ConvertPointFromWidgetToView(v3, location_in_root));
2643 EXPECT_EQ(gfx::Point(5, 5), location_in_v3);
2645 // Dispatch the event. When each view receives the event, its location should
2646 // be in the local coordinate space of that view (see the check made by
2647 // GestureLocationView). After dispatch is complete the event's location
2648 // should be in the root coordinate space.
2649 v1->set_expected_location(location_in_v1);
2650 v2->set_expected_location(location_in_v2);
2651 v3->set_expected_location(location_in_v3);
2652 widget->OnGestureEvent(&tap);
2653 EXPECT_EQ(location_in_root, tap.location());
2655 // Verify that each view did in fact see the event.
2656 EventCountView* view1 = v1;
2657 EventCountView* view2 = v2;
2658 EventCountView* view3 = v3;
2659 EXPECT_EQ(1, view1->GetEventCount(ui::ET_GESTURE_TAP));
2660 EXPECT_EQ(1, view2->GetEventCount(ui::ET_GESTURE_TAP));
2661 EXPECT_EQ(1, view3->GetEventCount(ui::ET_GESTURE_TAP));
2663 widget->Close();
2666 // Verifies that disabled views are permitted to be set as the default gesture
2667 // handler in RootView. Also verifies that gesture events targeted to a disabled
2668 // view are not actually dispatched to the view, but are still marked as
2669 // handled.
2670 TEST_F(WidgetTest, DisabledGestureEventTarget) {
2671 Widget* widget = CreateTopLevelNativeWidget();
2672 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2674 // Define a hierarchy of four views (coordinates are in
2675 // their parent coordinate space).
2676 // v1 (0, 0, 300, 300)
2677 // v2 (0, 0, 100, 100)
2678 // v3 (0, 0, 50, 50)
2679 // v4(0, 0, 10, 10)
2680 EventCountView* v1 = new EventCountView();
2681 v1->SetBounds(0, 0, 300, 300);
2682 EventCountView* v2 = new EventCountView();
2683 v2->SetBounds(0, 0, 100, 100);
2684 EventCountView* v3 = new EventCountView();
2685 v3->SetBounds(0, 0, 50, 50);
2686 EventCountView* v4 = new EventCountView();
2687 v4->SetBounds(0, 0, 10, 10);
2688 internal::RootView* root_view =
2689 static_cast<internal::RootView*>(widget->GetRootView());
2690 root_view->AddChildView(v1);
2691 v1->AddChildView(v2);
2692 v2->AddChildView(v3);
2693 v3->AddChildView(v4);
2695 widget->Show();
2697 // |v1|, |v2|, and |v3| all handle gesture events but |v3| is marked as
2698 // disabled.
2699 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2700 v2->set_handle_mode(EventCountView::CONSUME_EVENTS);
2701 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2702 v3->SetEnabled(false);
2704 // No gesture handler is set in the root view. In this case the tap event
2705 // should be dispatched only to |v4|, the gesture handler should be set to
2706 // |v3|, and the event should be marked as handled.
2707 GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5);
2708 widget->OnGestureEvent(&tap);
2709 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2710 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2711 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2712 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2713 EXPECT_EQ(v3, GetGestureHandler(root_view));
2714 EXPECT_TRUE(tap.handled());
2715 v1->ResetCounts();
2716 v2->ResetCounts();
2717 v3->ResetCounts();
2718 v4->ResetCounts();
2720 // A subsequent gesture event should be marked as handled but not dispatched.
2721 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2722 widget->OnGestureEvent(&tap);
2723 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2724 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2725 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2726 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2727 EXPECT_EQ(v3, GetGestureHandler(root_view));
2728 EXPECT_TRUE(tap.handled());
2729 v1->ResetCounts();
2730 v2->ResetCounts();
2731 v3->ResetCounts();
2732 v4->ResetCounts();
2734 // A GESTURE_END should reset the default gesture handler to NULL. It should
2735 // also not be dispatched to |v3| but still marked as handled.
2736 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2737 widget->OnGestureEvent(&end);
2738 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2739 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2740 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2741 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2742 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2743 EXPECT_TRUE(end.handled());
2744 v1->ResetCounts();
2745 v2->ResetCounts();
2746 v3->ResetCounts();
2747 v4->ResetCounts();
2749 // Change the handle mode of |v3| to indicate that it would no longer like
2750 // to handle events which are dispatched to it.
2751 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2753 // No gesture handler is set in the root view. In this case the tap event
2754 // should be dispatched only to |v4| and the event should be marked as
2755 // handled. Furthermore, the gesture handler should be set to
2756 // |v3|; even though |v3| does not explicitly handle events, it is a
2757 // valid target for the tap event because it is disabled.
2758 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2759 widget->OnGestureEvent(&tap);
2760 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2761 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2762 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2763 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2764 EXPECT_EQ(v3, GetGestureHandler(root_view));
2765 EXPECT_TRUE(tap.handled());
2766 v1->ResetCounts();
2767 v2->ResetCounts();
2768 v3->ResetCounts();
2769 v4->ResetCounts();
2771 // A GESTURE_END should reset the default gesture handler to NULL. It should
2772 // also not be dispatched to |v3| but still marked as handled.
2773 end = GestureEventForTest(ui::ET_GESTURE_END, 5, 5);
2774 widget->OnGestureEvent(&end);
2775 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2776 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2777 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2778 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2779 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2780 EXPECT_TRUE(end.handled());
2782 widget->Close();
2785 // Test the result of Widget::GetAllChildWidgets().
2786 TEST_F(WidgetTest, GetAllChildWidgets) {
2787 // Create the following widget hierarchy:
2789 // toplevel
2790 // +-- w1
2791 // +-- w11
2792 // +-- w2
2793 // +-- w21
2794 // +-- w22
2795 Widget* toplevel = CreateTopLevelPlatformWidget();
2796 Widget* w1 = CreateChildPlatformWidget(toplevel->GetNativeView());
2797 Widget* w11 = CreateChildPlatformWidget(w1->GetNativeView());
2798 Widget* w2 = CreateChildPlatformWidget(toplevel->GetNativeView());
2799 Widget* w21 = CreateChildPlatformWidget(w2->GetNativeView());
2800 Widget* w22 = CreateChildPlatformWidget(w2->GetNativeView());
2802 std::set<Widget*> expected;
2803 expected.insert(toplevel);
2804 expected.insert(w1);
2805 expected.insert(w11);
2806 expected.insert(w2);
2807 expected.insert(w21);
2808 expected.insert(w22);
2810 std::set<Widget*> widgets;
2811 Widget::GetAllChildWidgets(toplevel->GetNativeView(), &widgets);
2813 EXPECT_EQ(expected.size(), widgets.size());
2814 EXPECT_TRUE(std::equal(expected.begin(), expected.end(), widgets.begin()));
2817 // Used by DestroyChildWidgetsInOrder. On destruction adds the supplied name to
2818 // a vector.
2819 class DestroyedTrackingView : public View {
2820 public:
2821 DestroyedTrackingView(const std::string& name,
2822 std::vector<std::string>* add_to)
2823 : name_(name),
2824 add_to_(add_to) {
2827 ~DestroyedTrackingView() override { add_to_->push_back(name_); }
2829 private:
2830 const std::string name_;
2831 std::vector<std::string>* add_to_;
2833 DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingView);
2836 class WidgetChildDestructionTest : public WidgetTest {
2837 public:
2838 WidgetChildDestructionTest() {}
2840 // Creates a top level and a child, destroys the child and verifies the views
2841 // of the child are destroyed before the views of the parent.
2842 void RunDestroyChildWidgetsTest(bool top_level_has_desktop_native_widget_aura,
2843 bool child_has_desktop_native_widget_aura) {
2844 // When a View is destroyed its name is added here.
2845 std::vector<std::string> destroyed;
2847 Widget* top_level = new Widget;
2848 Widget::InitParams params =
2849 CreateParams(views::Widget::InitParams::TYPE_WINDOW);
2850 #if !defined(OS_CHROMEOS)
2851 if (top_level_has_desktop_native_widget_aura)
2852 params.native_widget = new PlatformDesktopNativeWidget(top_level);
2853 #endif
2854 top_level->Init(params);
2855 top_level->GetRootView()->AddChildView(
2856 new DestroyedTrackingView("parent", &destroyed));
2857 top_level->Show();
2859 Widget* child = new Widget;
2860 Widget::InitParams child_params =
2861 CreateParams(views::Widget::InitParams::TYPE_POPUP);
2862 child_params.parent = top_level->GetNativeView();
2863 #if !defined(OS_CHROMEOS)
2864 if (child_has_desktop_native_widget_aura)
2865 child_params.native_widget = new PlatformDesktopNativeWidget(child);
2866 #endif
2867 child->Init(child_params);
2868 child->GetRootView()->AddChildView(
2869 new DestroyedTrackingView("child", &destroyed));
2870 child->Show();
2872 // Should trigger destruction of the child too.
2873 top_level->native_widget_private()->CloseNow();
2875 // Child should be destroyed first.
2876 ASSERT_EQ(2u, destroyed.size());
2877 EXPECT_EQ("child", destroyed[0]);
2878 EXPECT_EQ("parent", destroyed[1]);
2881 private:
2882 DISALLOW_COPY_AND_ASSIGN(WidgetChildDestructionTest);
2885 #if !defined(OS_CHROMEOS)
2886 // See description of RunDestroyChildWidgetsTest(). Parent uses
2887 // DesktopNativeWidgetAura.
2888 TEST_F(WidgetChildDestructionTest,
2889 DestroyChildWidgetsInOrderWithDesktopNativeWidget) {
2890 RunDestroyChildWidgetsTest(true, false);
2893 // See description of RunDestroyChildWidgetsTest(). Both parent and child use
2894 // DesktopNativeWidgetAura.
2895 TEST_F(WidgetChildDestructionTest,
2896 DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth) {
2897 RunDestroyChildWidgetsTest(true, true);
2899 #endif // !defined(OS_CHROMEOS)
2901 // See description of RunDestroyChildWidgetsTest().
2902 TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) {
2903 RunDestroyChildWidgetsTest(false, false);
2906 #if !defined(OS_CHROMEOS)
2907 // Provides functionality to create a window modal dialog.
2908 class ModalDialogDelegate : public DialogDelegateView {
2909 public:
2910 ModalDialogDelegate() {}
2911 ~ModalDialogDelegate() override {}
2913 // WidgetDelegate overrides.
2914 ui::ModalType GetModalType() const override { return ui::MODAL_TYPE_WINDOW; }
2916 private:
2917 DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate);
2920 // This test verifies that whether mouse events when a modal dialog is
2921 // displayed are eaten or recieved by the dialog.
2922 TEST_F(WidgetTest, WindowMouseModalityTest) {
2923 // Create a top level widget.
2924 Widget top_level_widget;
2925 Widget::InitParams init_params =
2926 CreateParams(Widget::InitParams::TYPE_WINDOW);
2927 init_params.show_state = ui::SHOW_STATE_NORMAL;
2928 gfx::Rect initial_bounds(0, 0, 500, 500);
2929 init_params.bounds = initial_bounds;
2930 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2931 init_params.native_widget =
2932 new PlatformDesktopNativeWidget(&top_level_widget);
2933 top_level_widget.Init(init_params);
2934 top_level_widget.Show();
2935 EXPECT_TRUE(top_level_widget.IsVisible());
2937 // Create a view and validate that a mouse moves makes it to the view.
2938 EventCountView* widget_view = new EventCountView();
2939 widget_view->SetBounds(0, 0, 10, 10);
2940 top_level_widget.GetRootView()->AddChildView(widget_view);
2942 gfx::Point cursor_location_main(5, 5);
2943 ui::MouseEvent move_main(ui::ET_MOUSE_MOVED, cursor_location_main,
2944 cursor_location_main, ui::EventTimeForNow(),
2945 ui::EF_NONE, ui::EF_NONE);
2946 ui::EventDispatchDetails details =
2947 GetEventProcessor(&top_level_widget)->OnEventFromSource(&move_main);
2948 ASSERT_FALSE(details.dispatcher_destroyed);
2950 EXPECT_EQ(1, widget_view->GetEventCount(ui::ET_MOUSE_ENTERED));
2951 widget_view->ResetCounts();
2953 // Create a modal dialog and validate that a mouse down message makes it to
2954 // the main view within the dialog.
2956 // This instance will be destroyed when the dialog is destroyed.
2957 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
2959 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
2960 dialog_delegate, NULL, top_level_widget.GetNativeView());
2961 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
2962 EventCountView* dialog_widget_view = new EventCountView();
2963 dialog_widget_view->SetBounds(0, 0, 50, 50);
2964 modal_dialog_widget->GetRootView()->AddChildView(dialog_widget_view);
2965 modal_dialog_widget->Show();
2966 EXPECT_TRUE(modal_dialog_widget->IsVisible());
2968 gfx::Point cursor_location_dialog(100, 100);
2969 ui::MouseEvent mouse_down_dialog(
2970 ui::ET_MOUSE_PRESSED, cursor_location_dialog, cursor_location_dialog,
2971 ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
2972 details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
2973 &mouse_down_dialog);
2974 ASSERT_FALSE(details.dispatcher_destroyed);
2975 EXPECT_EQ(1, dialog_widget_view->GetEventCount(ui::ET_MOUSE_PRESSED));
2977 // Send a mouse move message to the main window. It should not be received by
2978 // the main window as the modal dialog is still active.
2979 gfx::Point cursor_location_main2(6, 6);
2980 ui::MouseEvent mouse_down_main(ui::ET_MOUSE_MOVED, cursor_location_main2,
2981 cursor_location_main2, ui::EventTimeForNow(),
2982 ui::EF_NONE, ui::EF_NONE);
2983 details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
2984 &mouse_down_main);
2985 ASSERT_FALSE(details.dispatcher_destroyed);
2986 EXPECT_EQ(0, widget_view->GetEventCount(ui::ET_MOUSE_MOVED));
2988 modal_dialog_widget->CloseNow();
2989 top_level_widget.CloseNow();
2992 // Verifies nativeview visbility matches that of Widget visibility when
2993 // SetFullscreen is invoked.
2994 TEST_F(WidgetTest, FullscreenStatePropagated) {
2995 Widget::InitParams init_params =
2996 CreateParams(Widget::InitParams::TYPE_WINDOW);
2997 init_params.show_state = ui::SHOW_STATE_NORMAL;
2998 init_params.bounds = gfx::Rect(0, 0, 500, 500);
2999 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3002 Widget top_level_widget;
3003 top_level_widget.Init(init_params);
3004 top_level_widget.SetFullscreen(true);
3005 EXPECT_EQ(top_level_widget.IsVisible(),
3006 IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
3007 top_level_widget.CloseNow();
3009 #if !defined(OS_CHROMEOS)
3011 Widget top_level_widget;
3012 init_params.native_widget =
3013 new PlatformDesktopNativeWidget(&top_level_widget);
3014 top_level_widget.Init(init_params);
3015 top_level_widget.SetFullscreen(true);
3016 EXPECT_EQ(top_level_widget.IsVisible(),
3017 IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
3018 top_level_widget.CloseNow();
3020 #endif
3022 #if defined(OS_WIN)
3024 // Provides functionality to test widget activation via an activation flag
3025 // which can be set by an accessor.
3026 class ModalWindowTestWidgetDelegate : public WidgetDelegate {
3027 public:
3028 ModalWindowTestWidgetDelegate()
3029 : widget_(NULL),
3030 can_activate_(true) {}
3032 virtual ~ModalWindowTestWidgetDelegate() {}
3034 // Overridden from WidgetDelegate:
3035 virtual void DeleteDelegate() override {
3036 delete this;
3038 virtual Widget* GetWidget() override {
3039 return widget_;
3041 virtual const Widget* GetWidget() const override {
3042 return widget_;
3044 virtual bool CanActivate() const override {
3045 return can_activate_;
3047 virtual bool ShouldAdvanceFocusToTopLevelWidget() const override {
3048 return true;
3051 void set_can_activate(bool can_activate) {
3052 can_activate_ = can_activate;
3055 void set_widget(Widget* widget) {
3056 widget_ = widget;
3059 private:
3060 Widget* widget_;
3061 bool can_activate_;
3063 DISALLOW_COPY_AND_ASSIGN(ModalWindowTestWidgetDelegate);
3066 // Tests whether we can activate the top level widget when a modal dialog is
3067 // active.
3068 TEST_F(WidgetTest, WindowModalityActivationTest) {
3069 // Destroyed when the top level widget created below is destroyed.
3070 ModalWindowTestWidgetDelegate* widget_delegate =
3071 new ModalWindowTestWidgetDelegate;
3072 // Create a top level widget.
3073 Widget top_level_widget;
3074 Widget::InitParams init_params =
3075 CreateParams(Widget::InitParams::TYPE_WINDOW);
3076 init_params.show_state = ui::SHOW_STATE_NORMAL;
3077 gfx::Rect initial_bounds(0, 0, 500, 500);
3078 init_params.bounds = initial_bounds;
3079 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3080 init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget);
3081 init_params.delegate = widget_delegate;
3082 top_level_widget.Init(init_params);
3083 widget_delegate->set_widget(&top_level_widget);
3084 top_level_widget.Show();
3085 EXPECT_TRUE(top_level_widget.IsVisible());
3087 HWND win32_window = views::HWNDForWidget(&top_level_widget);
3088 EXPECT_TRUE(::IsWindow(win32_window));
3090 // This instance will be destroyed when the dialog is destroyed.
3091 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
3093 // We should be able to activate the window even if the WidgetDelegate
3094 // says no, when a modal dialog is active.
3095 widget_delegate->set_can_activate(false);
3097 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
3098 dialog_delegate, NULL, top_level_widget.GetNativeWindow());
3099 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
3100 modal_dialog_widget->Show();
3101 EXPECT_TRUE(modal_dialog_widget->IsVisible());
3103 LRESULT activate_result = ::SendMessage(
3104 win32_window,
3105 WM_MOUSEACTIVATE,
3106 reinterpret_cast<WPARAM>(win32_window),
3107 MAKELPARAM(WM_LBUTTONDOWN, HTCLIENT));
3108 EXPECT_EQ(activate_result, MA_ACTIVATE);
3110 modal_dialog_widget->CloseNow();
3111 top_level_widget.CloseNow();
3113 #endif // defined(OS_WIN)
3114 #endif // !defined(OS_CHROMEOS)
3116 namespace {
3118 class FullscreenAwareFrame : public views::NonClientFrameView {
3119 public:
3120 explicit FullscreenAwareFrame(views::Widget* widget)
3121 : widget_(widget), fullscreen_layout_called_(false) {}
3122 ~FullscreenAwareFrame() override {}
3124 // views::NonClientFrameView overrides:
3125 gfx::Rect GetBoundsForClientView() const override { return gfx::Rect(); }
3126 gfx::Rect GetWindowBoundsForClientBounds(
3127 const gfx::Rect& client_bounds) const override {
3128 return gfx::Rect();
3130 int NonClientHitTest(const gfx::Point& point) override { return HTNOWHERE; }
3131 void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override {}
3132 void ResetWindowControls() override {}
3133 void UpdateWindowIcon() override {}
3134 void UpdateWindowTitle() override {}
3135 void SizeConstraintsChanged() override {}
3137 // views::View overrides:
3138 void Layout() override {
3139 if (widget_->IsFullscreen())
3140 fullscreen_layout_called_ = true;
3143 bool fullscreen_layout_called() const { return fullscreen_layout_called_; }
3145 private:
3146 views::Widget* widget_;
3147 bool fullscreen_layout_called_;
3149 DISALLOW_COPY_AND_ASSIGN(FullscreenAwareFrame);
3152 } // namespace
3154 // Tests that frame Layout is called when a widget goes fullscreen without
3155 // changing its size or title.
3156 TEST_F(WidgetTest, FullscreenFrameLayout) {
3157 Widget* widget = CreateTopLevelPlatformWidget();
3158 FullscreenAwareFrame* frame = new FullscreenAwareFrame(widget);
3159 widget->non_client_view()->SetFrameView(frame); // Owns |frame|.
3161 widget->Maximize();
3162 RunPendingMessages();
3164 EXPECT_FALSE(frame->fullscreen_layout_called());
3165 widget->SetFullscreen(true);
3166 widget->Show();
3167 RunPendingMessages();
3169 if (IsTestingSnowLeopard()) {
3170 // Fullscreen is currently ignored on Snow Leopard.
3171 EXPECT_FALSE(frame->fullscreen_layout_called());
3172 } else {
3173 EXPECT_TRUE(frame->fullscreen_layout_called());
3176 widget->CloseNow();
3179 #if !defined(OS_CHROMEOS)
3180 namespace {
3182 // Trivial WidgetObserverTest that invokes Widget::IsActive() from
3183 // OnWindowDestroying.
3184 class IsActiveFromDestroyObserver : public WidgetObserver {
3185 public:
3186 IsActiveFromDestroyObserver() {}
3187 ~IsActiveFromDestroyObserver() override {}
3188 void OnWidgetDestroying(Widget* widget) override { widget->IsActive(); }
3190 private:
3191 DISALLOW_COPY_AND_ASSIGN(IsActiveFromDestroyObserver);
3194 } // namespace
3196 // Verifies Widget::IsActive() invoked from
3197 // WidgetObserver::OnWidgetDestroying() in a child widget doesn't crash.
3198 TEST_F(WidgetTest, IsActiveFromDestroy) {
3199 // Create two widgets, one a child of the other.
3200 IsActiveFromDestroyObserver observer;
3201 Widget parent_widget;
3202 Widget::InitParams parent_params =
3203 CreateParams(Widget::InitParams::TYPE_POPUP);
3204 parent_params.native_widget = new PlatformDesktopNativeWidget(&parent_widget);
3205 parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3206 parent_widget.Init(parent_params);
3207 parent_widget.Show();
3209 Widget child_widget;
3210 Widget::InitParams child_params =
3211 CreateParams(Widget::InitParams::TYPE_POPUP);
3212 child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3213 child_params.context = parent_widget.GetNativeWindow();
3214 child_widget.Init(child_params);
3215 child_widget.AddObserver(&observer);
3216 child_widget.Show();
3218 parent_widget.CloseNow();
3220 #endif // !defined(OS_CHROMEOS)
3222 // Tests that events propagate through from the dispatcher with the correct
3223 // event type, and that the different platforms behave the same.
3224 TEST_F(WidgetTest, MouseEventTypesViaGenerator) {
3225 EventCountView* view = new EventCountView;
3226 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
3227 view->SetBounds(10, 10, 50, 40);
3229 Widget* widget = CreateTopLevelFramelessPlatformWidget();
3230 widget->GetRootView()->AddChildView(view);
3232 widget->SetBounds(gfx::Rect(0, 0, 100, 80));
3233 widget->Show();
3235 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
3236 generator.set_current_location(gfx::Point(20, 20));
3238 generator.ClickLeftButton();
3239 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3240 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3241 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags());
3243 generator.PressRightButton();
3244 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3245 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3246 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags());
3248 generator.ReleaseRightButton();
3249 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3250 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3251 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags());
3253 // Test mouse move events.
3254 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_MOVED));
3255 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3257 // Move the mouse within the view (20, 20) -> (30, 30).
3258 generator.MoveMouseTo(gfx::Point(30, 30));
3259 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_MOVED));
3260 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3261 EXPECT_EQ(ui::EF_NONE, view->last_flags());
3263 // Move it again - entered count shouldn't change.
3264 generator.MoveMouseTo(gfx::Point(31, 31));
3265 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED));
3266 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3267 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_EXITED));
3269 // Move it off the view.
3270 generator.MoveMouseTo(gfx::Point(5, 5));
3271 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED));
3272 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3273 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED));
3275 // Move it back on.
3276 generator.MoveMouseTo(gfx::Point(20, 20));
3277 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_MOVED));
3278 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3279 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED));
3281 // Drargging. Cover HasCapture() and NativeWidgetPrivate::IsMouseButtonDown().
3282 generator.DragMouseTo(gfx::Point(40, 40));
3283 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3284 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3285 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_DRAGGED));
3286 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags());
3288 widget->CloseNow();
3291 // Tests that the root view is correctly set up for Widget types that do not
3292 // require a non-client view, before any other views are added to the widget.
3293 // That is, before Widget::ReorderNativeViews() is called which, if called with
3294 // a root view not set, could cause the root view to get resized to the widget.
3295 TEST_F(WidgetTest, NonClientWindowValidAfterInit) {
3296 Widget* widget = CreateTopLevelFramelessPlatformWidget();
3297 View* root_view = widget->GetRootView();
3299 // Size the root view to exceed the widget bounds.
3300 const gfx::Rect test_rect(0, 0, 500, 500);
3301 root_view->SetBoundsRect(test_rect);
3303 EXPECT_NE(test_rect.size(), widget->GetWindowBoundsInScreen().size());
3305 EXPECT_EQ(test_rect, root_view->bounds());
3306 widget->ReorderNativeViews();
3307 EXPECT_EQ(test_rect, root_view->bounds());
3309 widget->CloseNow();
3312 #if defined(OS_WIN)
3313 // This test validates that sending WM_CHAR/WM_SYSCHAR/WM_SYSDEADCHAR
3314 // messages via the WindowEventTarget interface implemented by the
3315 // HWNDMessageHandler class does not cause a crash due to an unprocessed
3316 // event
3317 TEST_F(WidgetTest, CharMessagesAsKeyboardMessagesDoesNotCrash) {
3318 Widget widget;
3319 Widget::InitParams params =
3320 CreateParams(Widget::InitParams::TYPE_WINDOW);
3321 params.native_widget = new PlatformDesktopNativeWidget(&widget);
3322 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3323 widget.Init(params);
3324 widget.Show();
3326 ui::WindowEventTarget* target =
3327 reinterpret_cast<ui::WindowEventTarget*>(ui::ViewProp::GetValue(
3328 widget.GetNativeWindow()->GetHost()->GetAcceleratedWidget(),
3329 ui::WindowEventTarget::kWin32InputEventTarget));
3330 EXPECT_NE(nullptr, target);
3331 bool handled = false;
3332 target->HandleKeyboardMessage(WM_CHAR, 0, 0, &handled);
3333 target->HandleKeyboardMessage(WM_SYSCHAR, 0, 0, &handled);
3334 target->HandleKeyboardMessage(WM_SYSDEADCHAR, 0, 0, &handled);
3335 widget.CloseNow();
3337 #endif
3339 } // namespace test
3340 } // namespace views