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.
8 #include "base/basictypes.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_widget_observer.h"
27 #include "ui/views/test/widget_test.h"
28 #include "ui/views/widget/native_widget_delegate.h"
29 #include "ui/views/widget/root_view.h"
30 #include "ui/views/widget/widget_deletion_observer.h"
31 #include "ui/views/window/dialog_delegate.h"
32 #include "ui/views/window/native_frame_view.h"
35 #include "ui/aura/window.h"
36 #include "ui/aura/window_tree_host.h"
37 #include "ui/base/view_prop.h"
38 #include "ui/base/win/window_event_target.h"
39 #include "ui/views/win/hwnd_util.h"
42 #if defined(OS_MACOSX)
43 #include "base/mac/mac_util.h"
51 // TODO(tdanderson): This utility function is used in different unittest
52 // files. Move to a common location to avoid
54 gfx::Point
ConvertPointFromWidgetToView(View
* view
, const gfx::Point
& p
) {
56 View::ConvertPointToTarget(view
->GetWidget()->GetRootView(), view
, &tmp
);
60 // Helper function for Snow Leopard special cases to avoid #ifdef litter.
61 bool IsTestingSnowLeopard() {
62 #if defined(OS_MACOSX)
63 return base::mac::IsOSSnowLeopard();
71 // A view that keeps track of the events it receives, optionally consuming them.
72 class EventCountView
: public View
{
74 // Whether to call SetHandled() on events as they are received. For some event
75 // types, this will allow EventCountView to receives future events in the
76 // event sequence, such as a drag.
84 handle_mode_(PROPAGATE_EVENTS
) {}
86 ~EventCountView() override
{}
88 int GetEventCount(ui::EventType type
) {
89 return event_count_
[type
];
96 int last_flags() const {
100 void set_handle_mode(HandleMode handle_mode
) {
101 handle_mode_
= handle_mode
;
105 // Overridden from View:
106 void OnMouseMoved(const ui::MouseEvent
& event
) override
{
107 // MouseMove events are not re-dispatched from the RootView.
108 ++event_count_
[ui::ET_MOUSE_MOVED
];
112 // Overridden from ui::EventHandler:
113 void OnKeyEvent(ui::KeyEvent
* event
) override
{ RecordEvent(event
); }
114 void OnMouseEvent(ui::MouseEvent
* event
) override
{ RecordEvent(event
); }
115 void OnScrollEvent(ui::ScrollEvent
* event
) override
{ RecordEvent(event
); }
116 void OnGestureEvent(ui::GestureEvent
* event
) override
{ RecordEvent(event
); }
119 void RecordEvent(ui::Event
* event
) {
120 ++event_count_
[event
->type()];
121 last_flags_
= event
->flags();
122 if (handle_mode_
== CONSUME_EVENTS
)
126 std::map
<ui::EventType
, int> event_count_
;
128 HandleMode handle_mode_
;
130 DISALLOW_COPY_AND_ASSIGN(EventCountView
);
133 // A view that keeps track of the events it receives, and consumes all scroll
134 // gesture events and ui::ET_SCROLL events.
135 class ScrollableEventCountView
: public EventCountView
{
137 ScrollableEventCountView() {}
138 ~ScrollableEventCountView() override
{}
141 // Overridden from ui::EventHandler:
142 void OnGestureEvent(ui::GestureEvent
* event
) override
{
143 EventCountView::OnGestureEvent(event
);
144 switch (event
->type()) {
145 case ui::ET_GESTURE_SCROLL_BEGIN
:
146 case ui::ET_GESTURE_SCROLL_UPDATE
:
147 case ui::ET_GESTURE_SCROLL_END
:
148 case ui::ET_SCROLL_FLING_START
:
156 void OnScrollEvent(ui::ScrollEvent
* event
) override
{
157 EventCountView::OnScrollEvent(event
);
158 if (event
->type() == ui::ET_SCROLL
)
162 DISALLOW_COPY_AND_ASSIGN(ScrollableEventCountView
);
165 // A view that implements GetMinimumSize.
166 class MinimumSizeFrameView
: public NativeFrameView
{
168 explicit MinimumSizeFrameView(Widget
* frame
): NativeFrameView(frame
) {}
169 ~MinimumSizeFrameView() override
{}
172 // Overridden from View:
173 gfx::Size
GetMinimumSize() const override
{ return gfx::Size(300, 400); }
175 DISALLOW_COPY_AND_ASSIGN(MinimumSizeFrameView
);
178 // An event handler that simply keeps a count of the different types of events
180 class EventCountHandler
: public ui::EventHandler
{
182 EventCountHandler() {}
183 ~EventCountHandler() override
{}
185 int GetEventCount(ui::EventType type
) {
186 return event_count_
[type
];
190 event_count_
.clear();
194 // Overridden from ui::EventHandler:
195 void OnEvent(ui::Event
* event
) override
{
197 ui::EventHandler::OnEvent(event
);
201 void RecordEvent(const ui::Event
& event
) {
202 ++event_count_
[event
.type()];
205 std::map
<ui::EventType
, int> event_count_
;
207 DISALLOW_COPY_AND_ASSIGN(EventCountHandler
);
210 // A helper WidgetDelegate for tests that require hooks into WidgetDelegate
211 // calls, and removes some of the boilerplate for initializing a Widget. Calls
212 // Widget::CloseNow() when destroyed if it hasn't already been done.
213 class TestDesktopWidgetDelegate
: public WidgetDelegate
{
215 TestDesktopWidgetDelegate() : widget_(new Widget
) {}
217 ~TestDesktopWidgetDelegate() override
{
220 EXPECT_FALSE(widget_
);
223 // Initialize the Widget, adding some meaningful default InitParams.
224 void InitWidget(Widget::InitParams init_params
) {
225 init_params
.delegate
= this;
226 #if !defined(OS_CHROMEOS)
227 init_params
.native_widget
= new PlatformDesktopNativeWidget(widget_
);
229 init_params
.bounds
= initial_bounds_
;
230 widget_
->Init(init_params
);
233 // Set the contents view to be used during Widget initialization. For Widgets
234 // that use non-client views, this will be the contents_view used to
235 // initialize the ClientView in WidgetDelegate::CreateClientView(). Otherwise,
236 // it is the ContentsView of the Widget's RootView. Ownership passes to the
237 // view hierarchy during InitWidget().
238 void set_contents_view(View
* contents_view
) {
239 contents_view_
= contents_view
;
242 int window_closing_count() const { return window_closing_count_
; }
243 const gfx::Rect
& initial_bounds() { return initial_bounds_
; }
245 // WidgetDelegate overrides:
246 void WindowClosing() override
{
247 window_closing_count_
++;
251 Widget
* GetWidget() override
{ return widget_
; }
252 const Widget
* GetWidget() const override
{ return widget_
; }
254 View
* GetContentsView() override
{
255 return contents_view_
? contents_view_
: WidgetDelegate::GetContentsView();
258 bool ShouldAdvanceFocusToTopLevelWidget() const override
{
259 return true; // Same default as DefaultWidgetDelegate in widget.cc.
264 View
* contents_view_
= nullptr;
265 int window_closing_count_
= 0;
266 gfx::Rect initial_bounds_
= gfx::Rect(100, 100, 200, 200);
268 DISALLOW_COPY_AND_ASSIGN(TestDesktopWidgetDelegate
);
271 TEST_F(WidgetTest
, WidgetInitParams
) {
272 // Widgets are not transparent by default.
273 Widget::InitParams init1
;
274 EXPECT_EQ(Widget::InitParams::INFER_OPACITY
, init1
.opacity
);
277 TEST_F(WidgetTest
, NativeWindowProperty
) {
278 const char* key
= "foo";
281 Widget
* widget
= CreateTopLevelPlatformWidget();
282 EXPECT_EQ(nullptr, widget
->GetNativeWindowProperty(key
));
284 widget
->SetNativeWindowProperty(key
, &value
);
285 EXPECT_EQ(&value
, widget
->GetNativeWindowProperty(key
));
287 widget
->SetNativeWindowProperty(key
, nullptr);
288 EXPECT_EQ(nullptr, widget
->GetNativeWindowProperty(key
));
293 ////////////////////////////////////////////////////////////////////////////////
294 // Widget::GetTopLevelWidget tests.
296 TEST_F(WidgetTest
, GetTopLevelWidget_Native
) {
297 // Create a hierarchy of native widgets.
298 Widget
* toplevel
= CreateTopLevelPlatformWidget();
299 gfx::NativeView parent
= toplevel
->GetNativeView();
300 Widget
* child
= CreateChildPlatformWidget(parent
);
302 EXPECT_EQ(toplevel
, toplevel
->GetTopLevelWidget());
303 EXPECT_EQ(toplevel
, child
->GetTopLevelWidget());
305 toplevel
->CloseNow();
306 // |child| should be automatically destroyed with |toplevel|.
309 // Test if a focus manager and an inputmethod work without CHECK failure
310 // when window activation changes.
311 TEST_F(WidgetTest
, ChangeActivation
) {
312 Widget
* top1
= CreateTopLevelPlatformWidget();
314 RunPendingMessages();
316 Widget
* top2
= CreateTopLevelPlatformWidget();
318 RunPendingMessages();
321 RunPendingMessages();
324 RunPendingMessages();
327 RunPendingMessages();
333 // Tests visibility of child widgets.
334 TEST_F(WidgetTest
, Visibility
) {
335 Widget
* toplevel
= CreateTopLevelPlatformWidget();
336 gfx::NativeView parent
= toplevel
->GetNativeView();
337 Widget
* child
= CreateChildPlatformWidget(parent
);
339 EXPECT_FALSE(toplevel
->IsVisible());
340 EXPECT_FALSE(child
->IsVisible());
342 // Showing a child with a hidden parent keeps the child hidden.
344 EXPECT_FALSE(toplevel
->IsVisible());
345 EXPECT_FALSE(child
->IsVisible());
347 // Showing a hidden parent with a visible child shows both.
349 EXPECT_TRUE(toplevel
->IsVisible());
350 EXPECT_TRUE(child
->IsVisible());
352 // Hiding a parent hides both parent and child.
354 EXPECT_FALSE(toplevel
->IsVisible());
355 EXPECT_FALSE(child
->IsVisible());
357 // Hiding a child while the parent is hidden keeps the child hidden when the
361 EXPECT_TRUE(toplevel
->IsVisible());
362 EXPECT_FALSE(child
->IsVisible());
364 toplevel
->CloseNow();
365 // |child| should be automatically destroyed with |toplevel|.
368 // Test that child widgets are positioned relative to their parent.
369 TEST_F(WidgetTest
, ChildBoundsRelativeToParent
) {
370 Widget
* toplevel
= CreateTopLevelPlatformWidget();
371 Widget
* child
= CreateChildPlatformWidget(toplevel
->GetNativeView());
373 toplevel
->SetBounds(gfx::Rect(160, 100, 320, 200));
374 child
->SetBounds(gfx::Rect(0, 0, 320, 200));
379 gfx::Rect toplevel_bounds
= toplevel
->GetWindowBoundsInScreen();
381 // Check the parent origin. If it was (0, 0) the test wouldn't be interesting.
382 EXPECT_NE(gfx::Vector2d(0, 0), toplevel_bounds
.OffsetFromOrigin());
384 // The child's origin is at (0, 0), but the same size, so bounds should match.
385 EXPECT_EQ(toplevel_bounds
, child
->GetWindowBoundsInScreen());
387 toplevel
->CloseNow();
390 // Test z-order of child widgets relative to their parent.
391 TEST_F(WidgetTest
, ChildStackedRelativeToParent
) {
392 Widget
* parent
= CreateTopLevelPlatformWidget();
393 Widget
* child
= CreateChildPlatformWidget(parent
->GetNativeView());
395 parent
->SetBounds(gfx::Rect(160, 100, 320, 200));
396 child
->SetBounds(gfx::Rect(50, 50, 30, 20));
398 // Child shown first. Initially not visible, but on top of parent when shown.
399 // Use ShowInactive whenever showing the child, otherwise the usual activation
400 // logic will just put it on top anyway. Here, we want to ensure it is on top
401 // of its parent regardless.
402 child
->ShowInactive();
403 EXPECT_FALSE(child
->IsVisible());
406 EXPECT_TRUE(child
->IsVisible());
407 EXPECT_TRUE(IsWindowStackedAbove(child
, parent
));
408 EXPECT_FALSE(IsWindowStackedAbove(parent
, child
)); // Sanity check.
410 Widget
* popover
= CreateTopLevelPlatformWidget();
411 popover
->SetBounds(gfx::Rect(150, 90, 340, 240));
414 EXPECT_TRUE(IsWindowStackedAbove(popover
, child
));
415 EXPECT_TRUE(IsWindowStackedAbove(child
, parent
));
417 // Showing the parent again should raise it and its child above the popover.
419 EXPECT_TRUE(IsWindowStackedAbove(child
, parent
));
420 EXPECT_TRUE(IsWindowStackedAbove(parent
, popover
));
422 // Test grandchildren.
423 Widget
* grandchild
= CreateChildPlatformWidget(child
->GetNativeView());
424 grandchild
->SetBounds(gfx::Rect(5, 5, 15, 10));
425 grandchild
->ShowInactive();
426 EXPECT_TRUE(IsWindowStackedAbove(grandchild
, child
));
427 EXPECT_TRUE(IsWindowStackedAbove(child
, parent
));
428 EXPECT_TRUE(IsWindowStackedAbove(parent
, popover
));
431 EXPECT_TRUE(IsWindowStackedAbove(popover
, grandchild
));
432 EXPECT_TRUE(IsWindowStackedAbove(grandchild
, child
));
435 EXPECT_TRUE(IsWindowStackedAbove(grandchild
, child
));
436 EXPECT_TRUE(IsWindowStackedAbove(child
, popover
));
438 // Test hiding and reshowing.
440 EXPECT_FALSE(grandchild
->IsVisible());
443 EXPECT_TRUE(IsWindowStackedAbove(grandchild
, child
));
444 EXPECT_TRUE(IsWindowStackedAbove(child
, parent
));
445 EXPECT_TRUE(IsWindowStackedAbove(parent
, popover
));
448 EXPECT_FALSE(grandchild
->IsVisible());
449 grandchild
->ShowInactive();
451 EXPECT_TRUE(IsWindowStackedAbove(grandchild
, child
));
452 EXPECT_TRUE(IsWindowStackedAbove(child
, parent
));
453 EXPECT_TRUE(IsWindowStackedAbove(parent
, popover
));
459 ////////////////////////////////////////////////////////////////////////////////
460 // Widget ownership tests.
462 // Tests various permutations of Widget ownership specified in the
463 // InitParams::Ownership param.
465 // A WidgetTest that supplies a toplevel widget for NativeWidget to parent to.
466 class WidgetOwnershipTest
: public WidgetTest
{
468 WidgetOwnershipTest() {}
469 ~WidgetOwnershipTest() override
{}
471 void SetUp() override
{
473 desktop_widget_
= CreateTopLevelPlatformWidget();
476 void TearDown() override
{
477 desktop_widget_
->CloseNow();
478 WidgetTest::TearDown();
482 Widget
* desktop_widget_
;
484 DISALLOW_COPY_AND_ASSIGN(WidgetOwnershipTest
);
487 // A bag of state to monitor destructions.
488 struct OwnershipTestState
{
489 OwnershipTestState() : widget_deleted(false), native_widget_deleted(false) {}
492 bool native_widget_deleted
;
495 // A platform NativeWidget subclass that updates a bag of state when it is
497 class OwnershipTestNativeWidget
: public PlatformNativeWidget
{
499 OwnershipTestNativeWidget(internal::NativeWidgetDelegate
* delegate
,
500 OwnershipTestState
* state
)
501 : PlatformNativeWidget(delegate
),
504 ~OwnershipTestNativeWidget() override
{
505 state_
->native_widget_deleted
= true;
509 OwnershipTestState
* state_
;
511 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidget
);
514 // A views NativeWidget subclass that updates a bag of state when it is
516 class OwnershipTestNativeWidgetAura
: public NativeWidgetCapture
{
518 OwnershipTestNativeWidgetAura(internal::NativeWidgetDelegate
* delegate
,
519 OwnershipTestState
* state
)
520 : NativeWidgetCapture(delegate
),
523 ~OwnershipTestNativeWidgetAura() override
{
524 state_
->native_widget_deleted
= true;
528 OwnershipTestState
* state_
;
530 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetAura
);
533 // A Widget subclass that updates a bag of state when it is destroyed.
534 class OwnershipTestWidget
: public Widget
{
536 explicit OwnershipTestWidget(OwnershipTestState
* state
) : state_(state
) {}
537 ~OwnershipTestWidget() override
{ state_
->widget_deleted
= true; }
540 OwnershipTestState
* state_
;
542 DISALLOW_COPY_AND_ASSIGN(OwnershipTestWidget
);
545 // Widget owns its NativeWidget, part 1: NativeWidget is a platform-native
547 TEST_F(WidgetOwnershipTest
, Ownership_WidgetOwnsPlatformNativeWidget
) {
548 OwnershipTestState state
;
550 scoped_ptr
<Widget
> widget(new OwnershipTestWidget(&state
));
551 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
552 params
.native_widget
=
553 new OwnershipTestNativeWidgetAura(widget
.get(), &state
);
554 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
555 widget
->Init(params
);
557 // Now delete the Widget, which should delete the NativeWidget.
560 EXPECT_TRUE(state
.widget_deleted
);
561 EXPECT_TRUE(state
.native_widget_deleted
);
563 // TODO(beng): write test for this ownership scenario and the NativeWidget
564 // being deleted out from under the Widget.
567 // Widget owns its NativeWidget, part 2: NativeWidget is a NativeWidget.
568 TEST_F(WidgetOwnershipTest
, Ownership_WidgetOwnsViewsNativeWidget
) {
569 OwnershipTestState state
;
571 scoped_ptr
<Widget
> widget(new OwnershipTestWidget(&state
));
572 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
573 params
.native_widget
=
574 new OwnershipTestNativeWidgetAura(widget
.get(), &state
);
575 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
576 widget
->Init(params
);
578 // Now delete the Widget, which should delete the NativeWidget.
581 EXPECT_TRUE(state
.widget_deleted
);
582 EXPECT_TRUE(state
.native_widget_deleted
);
584 // TODO(beng): write test for this ownership scenario and the NativeWidget
585 // being deleted out from under the Widget.
588 // Widget owns its NativeWidget, part 3: NativeWidget is a NativeWidget,
589 // destroy the parent view.
590 TEST_F(WidgetOwnershipTest
,
591 Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView
) {
592 OwnershipTestState state
;
594 Widget
* toplevel
= CreateTopLevelPlatformWidget();
596 scoped_ptr
<Widget
> widget(new OwnershipTestWidget(&state
));
597 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
598 params
.native_widget
=
599 new OwnershipTestNativeWidgetAura(widget
.get(), &state
);
600 params
.parent
= toplevel
->GetNativeView();
601 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
602 widget
->Init(params
);
604 // Now close the toplevel, which deletes the view hierarchy.
605 toplevel
->CloseNow();
607 RunPendingMessages();
609 // This shouldn't delete the widget because it shouldn't be deleted
610 // from the native side.
611 EXPECT_FALSE(state
.widget_deleted
);
612 EXPECT_FALSE(state
.native_widget_deleted
);
614 // Now delete it explicitly.
617 EXPECT_TRUE(state
.widget_deleted
);
618 EXPECT_TRUE(state
.native_widget_deleted
);
621 // NativeWidget owns its Widget, part 1: NativeWidget is a platform-native
623 TEST_F(WidgetOwnershipTest
, Ownership_PlatformNativeWidgetOwnsWidget
) {
624 OwnershipTestState state
;
626 Widget
* widget
= new OwnershipTestWidget(&state
);
627 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
628 params
.native_widget
=
629 new OwnershipTestNativeWidgetAura(widget
, &state
);
630 widget
->Init(params
);
632 // Now destroy the native widget.
635 EXPECT_TRUE(state
.widget_deleted
);
636 EXPECT_TRUE(state
.native_widget_deleted
);
639 // NativeWidget owns its Widget, part 2: NativeWidget is a NativeWidget.
640 TEST_F(WidgetOwnershipTest
, Ownership_ViewsNativeWidgetOwnsWidget
) {
641 OwnershipTestState state
;
643 Widget
* toplevel
= CreateTopLevelPlatformWidget();
645 Widget
* widget
= new OwnershipTestWidget(&state
);
646 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
647 params
.native_widget
=
648 new OwnershipTestNativeWidgetAura(widget
, &state
);
649 params
.parent
= toplevel
->GetNativeView();
650 widget
->Init(params
);
652 // Now destroy the native widget. This is achieved by closing the toplevel.
653 toplevel
->CloseNow();
655 // The NativeWidget won't be deleted until after a return to the message loop
656 // so we have to run pending messages before testing the destruction status.
657 RunPendingMessages();
659 EXPECT_TRUE(state
.widget_deleted
);
660 EXPECT_TRUE(state
.native_widget_deleted
);
663 // NativeWidget owns its Widget, part 3: NativeWidget is a platform-native
664 // widget, destroyed out from under it by the OS.
665 TEST_F(WidgetOwnershipTest
,
666 Ownership_PlatformNativeWidgetOwnsWidget_NativeDestroy
) {
667 OwnershipTestState state
;
669 Widget
* widget
= new OwnershipTestWidget(&state
);
670 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
671 params
.native_widget
=
672 new OwnershipTestNativeWidgetAura(widget
, &state
);
673 widget
->Init(params
);
675 // Now simulate a destroy of the platform native widget from the OS:
676 SimulateNativeDestroy(widget
);
678 EXPECT_TRUE(state
.widget_deleted
);
679 EXPECT_TRUE(state
.native_widget_deleted
);
682 // NativeWidget owns its Widget, part 4: NativeWidget is a NativeWidget,
683 // destroyed by the view hierarchy that contains it.
684 TEST_F(WidgetOwnershipTest
,
685 Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy
) {
686 OwnershipTestState state
;
688 Widget
* toplevel
= CreateTopLevelPlatformWidget();
690 Widget
* widget
= new OwnershipTestWidget(&state
);
691 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
692 params
.native_widget
=
693 new OwnershipTestNativeWidgetAura(widget
, &state
);
694 params
.parent
= toplevel
->GetNativeView();
695 widget
->Init(params
);
697 // Destroy the widget (achieved by closing the toplevel).
698 toplevel
->CloseNow();
700 // The NativeWidget won't be deleted until after a return to the message loop
701 // so we have to run pending messages before testing the destruction status.
702 RunPendingMessages();
704 EXPECT_TRUE(state
.widget_deleted
);
705 EXPECT_TRUE(state
.native_widget_deleted
);
708 // NativeWidget owns its Widget, part 5: NativeWidget is a NativeWidget,
709 // we close it directly.
710 TEST_F(WidgetOwnershipTest
,
711 Ownership_ViewsNativeWidgetOwnsWidget_Close
) {
712 OwnershipTestState state
;
714 Widget
* toplevel
= CreateTopLevelPlatformWidget();
716 Widget
* widget
= new OwnershipTestWidget(&state
);
717 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
718 params
.native_widget
=
719 new OwnershipTestNativeWidgetAura(widget
, &state
);
720 params
.parent
= toplevel
->GetNativeView();
721 widget
->Init(params
);
723 // Destroy the widget.
725 toplevel
->CloseNow();
727 // The NativeWidget won't be deleted until after a return to the message loop
728 // so we have to run pending messages before testing the destruction status.
729 RunPendingMessages();
731 EXPECT_TRUE(state
.widget_deleted
);
732 EXPECT_TRUE(state
.native_widget_deleted
);
735 // Widget owns its NativeWidget and has a WidgetDelegateView as its contents.
736 TEST_F(WidgetOwnershipTest
,
737 Ownership_WidgetOwnsNativeWidgetWithWithWidgetDelegateView
) {
738 OwnershipTestState state
;
740 WidgetDelegateView
* delegate_view
= new WidgetDelegateView
;
742 scoped_ptr
<Widget
> widget(new OwnershipTestWidget(&state
));
743 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
744 params
.native_widget
=
745 new OwnershipTestNativeWidgetAura(widget
.get(), &state
);
746 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
747 params
.delegate
= delegate_view
;
748 widget
->Init(params
);
749 widget
->SetContentsView(delegate_view
);
751 // Now delete the Widget. There should be no crash or use-after-free.
754 EXPECT_TRUE(state
.widget_deleted
);
755 EXPECT_TRUE(state
.native_widget_deleted
);
758 ////////////////////////////////////////////////////////////////////////////////
759 // Test to verify using various Widget methods doesn't crash when the underlying
760 // NativeView is destroyed.
762 class WidgetWithDestroyedNativeViewTest
: public ViewsTestBase
{
764 WidgetWithDestroyedNativeViewTest() {}
765 ~WidgetWithDestroyedNativeViewTest() override
{}
767 void InvokeWidgetMethods(Widget
* widget
) {
768 widget
->GetNativeView();
769 widget
->GetNativeWindow();
770 ui::Accelerator accelerator
;
771 widget
->GetAccelerator(0, &accelerator
);
772 widget
->GetTopLevelWidget();
773 widget
->GetWindowBoundsInScreen();
774 widget
->GetClientAreaBoundsInScreen();
775 widget
->SetBounds(gfx::Rect(0, 0, 100, 80));
776 widget
->SetSize(gfx::Size(10, 11));
777 widget
->SetBoundsConstrained(gfx::Rect(0, 0, 120, 140));
778 widget
->SetVisibilityChangedAnimationsEnabled(false);
779 widget
->StackAtTop();
784 widget
->Deactivate();
786 widget
->DisableInactiveRendering();
787 widget
->SetAlwaysOnTop(true);
788 widget
->IsAlwaysOnTop();
792 widget
->IsMaximized();
793 widget
->IsFullscreen();
794 widget
->SetOpacity(0);
795 widget
->SetUseDragFrame(true);
796 widget
->FlashFrame(true);
798 widget
->GetThemeProvider();
799 widget
->GetNativeTheme();
800 widget
->GetFocusManager();
801 widget
->SchedulePaintInRect(gfx::Rect(0, 0, 1, 2));
802 widget
->IsMouseEventsEnabled();
803 widget
->SetNativeWindowProperty("xx", widget
);
804 widget
->GetNativeWindowProperty("xx");
805 widget
->GetFocusTraversable();
807 widget
->ReorderNativeViews();
808 widget
->SetCapture(widget
->GetRootView());
809 widget
->ReleaseCapture();
810 widget
->HasCapture();
811 widget
->GetWorkAreaBoundsInScreen();
812 widget
->IsTranslucentWindowOpacitySupported();
816 DISALLOW_COPY_AND_ASSIGN(WidgetWithDestroyedNativeViewTest
);
819 TEST_F(WidgetWithDestroyedNativeViewTest
, Test
) {
822 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
823 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
827 widget
.native_widget_private()->CloseNow();
828 InvokeWidgetMethods(&widget
);
830 #if !defined(OS_CHROMEOS)
833 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
834 params
.native_widget
= new PlatformDesktopNativeWidget(&widget
);
835 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
839 widget
.native_widget_private()->CloseNow();
840 InvokeWidgetMethods(&widget
);
845 ////////////////////////////////////////////////////////////////////////////////
846 // Widget observer tests.
849 class WidgetObserverTest
: public WidgetTest
, public WidgetObserver
{
853 widget_closed_(nullptr),
854 widget_activated_(nullptr),
855 widget_shown_(nullptr),
856 widget_hidden_(nullptr),
857 widget_bounds_changed_(nullptr),
858 widget_to_close_on_hide_(nullptr) {
861 ~WidgetObserverTest() override
{}
863 // Set a widget to Close() the next time the Widget being observed is hidden.
864 void CloseOnNextHide(Widget
* widget
) {
865 widget_to_close_on_hide_
= widget
;
868 // Overridden from WidgetObserver:
869 void OnWidgetDestroying(Widget
* widget
) override
{
870 if (active_
== widget
)
872 widget_closed_
= widget
;
875 void OnWidgetActivationChanged(Widget
* widget
, bool active
) override
{
877 if (widget_activated_
)
878 widget_activated_
->Deactivate();
879 widget_activated_
= widget
;
882 if (widget_activated_
== widget
)
883 widget_activated_
= nullptr;
884 widget_deactivated_
= widget
;
888 void OnWidgetVisibilityChanged(Widget
* widget
, bool visible
) override
{
890 widget_shown_
= widget
;
893 widget_hidden_
= widget
;
894 if (widget_to_close_on_hide_
) {
895 widget_to_close_on_hide_
->Close();
896 widget_to_close_on_hide_
= nullptr;
900 void OnWidgetBoundsChanged(Widget
* widget
,
901 const gfx::Rect
& new_bounds
) override
{
902 widget_bounds_changed_
= widget
;
907 widget_closed_
= nullptr;
908 widget_activated_
= nullptr;
909 widget_deactivated_
= nullptr;
910 widget_shown_
= nullptr;
911 widget_hidden_
= nullptr;
912 widget_bounds_changed_
= nullptr;
915 Widget
* NewWidget() {
916 Widget
* widget
= CreateTopLevelNativeWidget();
917 widget
->AddObserver(this);
921 const Widget
* active() const { return active_
; }
922 const Widget
* widget_closed() const { return widget_closed_
; }
923 const Widget
* widget_activated() const { return widget_activated_
; }
924 const Widget
* widget_deactivated() const { return widget_deactivated_
; }
925 const Widget
* widget_shown() const { return widget_shown_
; }
926 const Widget
* widget_hidden() const { return widget_hidden_
; }
927 const Widget
* widget_bounds_changed() const { return widget_bounds_changed_
; }
932 Widget
* widget_closed_
;
933 Widget
* widget_activated_
;
934 Widget
* widget_deactivated_
;
935 Widget
* widget_shown_
;
936 Widget
* widget_hidden_
;
937 Widget
* widget_bounds_changed_
;
939 Widget
* widget_to_close_on_hide_
;
942 TEST_F(WidgetObserverTest
, DISABLED_ActivationChange
) {
943 Widget
* toplevel
= CreateTopLevelPlatformWidget();
945 Widget
* toplevel1
= NewWidget();
946 Widget
* toplevel2
= NewWidget();
953 toplevel1
->Activate();
955 RunPendingMessages();
956 EXPECT_EQ(toplevel1
, widget_activated());
958 toplevel2
->Activate();
959 RunPendingMessages();
960 EXPECT_EQ(toplevel1
, widget_deactivated());
961 EXPECT_EQ(toplevel2
, widget_activated());
962 EXPECT_EQ(toplevel2
, active());
964 toplevel
->CloseNow();
967 TEST_F(WidgetObserverTest
, DISABLED_VisibilityChange
) {
968 Widget
* toplevel
= CreateTopLevelPlatformWidget();
970 Widget
* child1
= NewWidget();
971 Widget
* child2
= NewWidget();
980 EXPECT_EQ(child1
, widget_hidden());
983 EXPECT_EQ(child2
, widget_hidden());
986 EXPECT_EQ(child1
, widget_shown());
989 EXPECT_EQ(child2
, widget_shown());
991 toplevel
->CloseNow();
994 TEST_F(WidgetObserverTest
, DestroyBubble
) {
995 Widget
* anchor
= CreateTopLevelPlatformWidget();
998 BubbleDelegateView
* bubble_delegate
=
999 new BubbleDelegateView(anchor
->client_view(), BubbleBorder::NONE
);
1000 Widget
* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate
));
1001 bubble_widget
->Show();
1002 bubble_widget
->CloseNow();
1008 TEST_F(WidgetObserverTest
, WidgetBoundsChanged
) {
1009 Widget
* child1
= NewWidget();
1010 Widget
* child2
= NewWidget();
1012 child1
->OnNativeWidgetMove();
1013 EXPECT_EQ(child1
, widget_bounds_changed());
1015 child2
->OnNativeWidgetMove();
1016 EXPECT_EQ(child2
, widget_bounds_changed());
1018 child1
->OnNativeWidgetSizeChanged(gfx::Size());
1019 EXPECT_EQ(child1
, widget_bounds_changed());
1021 child2
->OnNativeWidgetSizeChanged(gfx::Size());
1022 EXPECT_EQ(child2
, widget_bounds_changed());
1028 // An extension to WidgetBoundsChanged to ensure notifications are forwarded
1029 // by the NativeWidget implementation.
1030 TEST_F(WidgetObserverTest
, WidgetBoundsChangedNative
) {
1031 // Don't use NewWidget(), so that the Init() flow can be observed to ensure
1032 // consistency across platforms.
1033 Widget
* widget
= new Widget(); // Note: owned by NativeWidget.
1034 widget
->AddObserver(this);
1036 EXPECT_FALSE(widget_bounds_changed());
1038 // Init causes a bounds change, even while not showing. Note some platforms
1039 // cause a bounds change even when the bounds are empty. Mac does not.
1040 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_WINDOW
);
1041 params
.bounds
= gfx::Rect(0, 0, 100, 100);
1042 widget
->Init(params
);
1043 EXPECT_TRUE(widget_bounds_changed());
1046 // Resizing while hidden, triggers a change.
1047 widget
->SetSize(gfx::Size(160, 100));
1048 EXPECT_FALSE(widget
->IsVisible());
1049 EXPECT_TRUE(widget_bounds_changed());
1052 // Setting the same size does nothing.
1053 widget
->SetSize(gfx::Size(160, 100));
1054 EXPECT_FALSE(widget_bounds_changed());
1057 // Showing does nothing to the bounds.
1059 EXPECT_TRUE(widget
->IsVisible());
1060 EXPECT_FALSE(widget_bounds_changed());
1063 // Resizing while shown.
1064 widget
->SetSize(gfx::Size(170, 100));
1065 EXPECT_TRUE(widget_bounds_changed());
1068 // Resize to the same thing while shown does nothing.
1069 widget
->SetSize(gfx::Size(170, 100));
1070 EXPECT_FALSE(widget_bounds_changed());
1073 // No bounds change when closing.
1075 EXPECT_FALSE(widget_bounds_changed());
1078 // Test correct behavior when widgets close themselves in response to visibility
1080 TEST_F(WidgetObserverTest
, ClosingOnHiddenParent
) {
1081 Widget
* parent
= NewWidget();
1082 Widget
* child
= CreateChildPlatformWidget(parent
->GetNativeView());
1084 TestWidgetObserver
child_observer(child
);
1086 EXPECT_FALSE(parent
->IsVisible());
1087 EXPECT_FALSE(child
->IsVisible());
1089 // Note |child| is TYPE_CONTROL, which start shown. So no need to show the
1090 // child separately.
1092 EXPECT_TRUE(parent
->IsVisible());
1093 EXPECT_TRUE(child
->IsVisible());
1095 // Simulate a child widget that closes itself when the parent is hidden.
1096 CloseOnNextHide(child
);
1097 EXPECT_FALSE(child_observer
.widget_closed());
1099 RunPendingMessages();
1100 EXPECT_TRUE(child_observer
.widget_closed());
1105 // Test behavior of NativeWidget*::GetWindowPlacement on the native desktop.
1106 TEST_F(WidgetTest
, GetWindowPlacement
) {
1108 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
1109 // On desktop-Linux cheat and use non-desktop widgets. On X11, minimize is
1110 // asynchronous. Also (harder) showing a window doesn't activate it without
1111 // user interaction (or extra steps only done for interactive ui tests).
1112 // Without that, show_state remains in ui::SHOW_STATE_INACTIVE throughout.
1113 // TODO(tapted): Find a nice way to run this with desktop widgets on Linux.
1114 widget
= CreateTopLevelPlatformWidget();
1116 widget
= CreateNativeDesktopWidget();
1119 gfx::Rect
expected_bounds(100, 110, 200, 220);
1120 widget
->SetBounds(expected_bounds
);
1123 // Start with something invalid to ensure it changes.
1124 ui::WindowShowState show_state
= ui::SHOW_STATE_END
;
1125 gfx::Rect restored_bounds
;
1127 internal::NativeWidgetPrivate
* native_widget
=
1128 widget
->native_widget_private();
1130 native_widget
->GetWindowPlacement(&restored_bounds
, &show_state
);
1131 EXPECT_EQ(expected_bounds
, restored_bounds
);
1132 #if defined(OS_LINUX)
1133 // Non-desktop/Ash widgets start off in "default" until a Restore().
1134 EXPECT_EQ(ui::SHOW_STATE_DEFAULT
, show_state
);
1136 native_widget
->GetWindowPlacement(&restored_bounds
, &show_state
);
1138 EXPECT_EQ(ui::SHOW_STATE_NORMAL
, show_state
);
1141 native_widget
->GetWindowPlacement(&restored_bounds
, &show_state
);
1142 EXPECT_EQ(ui::SHOW_STATE_MINIMIZED
, show_state
);
1143 EXPECT_EQ(expected_bounds
, restored_bounds
);
1146 native_widget
->GetWindowPlacement(&restored_bounds
, &show_state
);
1147 EXPECT_EQ(ui::SHOW_STATE_NORMAL
, show_state
);
1148 EXPECT_EQ(expected_bounds
, restored_bounds
);
1150 expected_bounds
= gfx::Rect(130, 140, 230, 250);
1151 widget
->SetBounds(expected_bounds
);
1152 native_widget
->GetWindowPlacement(&restored_bounds
, &show_state
);
1153 EXPECT_EQ(ui::SHOW_STATE_NORMAL
, show_state
);
1154 EXPECT_EQ(expected_bounds
, restored_bounds
);
1156 widget
->SetFullscreen(true);
1157 native_widget
->GetWindowPlacement(&restored_bounds
, &show_state
);
1160 // Desktop Aura widgets on Windows currently don't update show_state when
1161 // going fullscreen, and report restored_bounds as the full screen size.
1162 // See http://crbug.com/475813.
1163 EXPECT_EQ(ui::SHOW_STATE_NORMAL
, show_state
);
1165 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN
, show_state
);
1166 EXPECT_EQ(expected_bounds
, restored_bounds
);
1169 widget
->SetFullscreen(false);
1170 native_widget
->GetWindowPlacement(&restored_bounds
, &show_state
);
1171 EXPECT_EQ(ui::SHOW_STATE_NORMAL
, show_state
);
1172 EXPECT_EQ(expected_bounds
, restored_bounds
);
1177 // Test that widget size constraints are properly applied immediately after
1178 // Init(), and that SetBounds() calls are appropriately clamped.
1179 TEST_F(WidgetTest
, MinimumSizeConstraints
) {
1180 TestDesktopWidgetDelegate delegate
;
1181 gfx::Size
minimum_size(100, 100);
1182 const gfx::Size
smaller_size(90, 90);
1184 delegate
.set_contents_view(new StaticSizedView(minimum_size
));
1185 delegate
.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW
));
1186 Widget
* widget
= delegate
.GetWidget();
1188 // On desktop Linux, the Widget must be shown to ensure the window is mapped.
1189 // On other platforms this line is optional.
1193 EXPECT_GT(delegate
.initial_bounds().width(), minimum_size
.width());
1194 EXPECT_GT(delegate
.initial_bounds().height(), minimum_size
.height());
1195 EXPECT_EQ(delegate
.initial_bounds().size(),
1196 widget
->GetWindowBoundsInScreen().size());
1197 // Note: StaticSizedView doesn't currently provide a maximum size.
1198 EXPECT_EQ(gfx::Size(), widget
->GetMaximumSize());
1200 if (!widget
->ShouldUseNativeFrame()) {
1201 // The test environment may have dwm disabled on Windows. In this case,
1202 // CustomFrameView is used instead of the NativeFrameView, which will
1203 // provide a minimum size that includes frame decorations.
1204 minimum_size
= widget
->non_client_view()->GetWindowBoundsForClientBounds(
1205 gfx::Rect(minimum_size
)).size();
1208 EXPECT_EQ(minimum_size
, widget
->GetMinimumSize());
1209 EXPECT_EQ(minimum_size
, GetNativeWidgetMinimumContentSize(widget
));
1211 // Trying to resize smaller than the minimum size should restrict the content
1212 // size to the minimum size.
1213 widget
->SetBounds(gfx::Rect(smaller_size
));
1214 EXPECT_EQ(minimum_size
, widget
->GetClientAreaBoundsInScreen().size());
1216 widget
->SetSize(smaller_size
);
1217 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
1218 // TODO(tapted): Desktop Linux ignores size constraints for SetSize. Fix it.
1219 EXPECT_EQ(smaller_size
, widget
->GetClientAreaBoundsInScreen().size());
1221 EXPECT_EQ(minimum_size
, widget
->GetClientAreaBoundsInScreen().size());
1225 // Tests that SetBounds() and GetWindowBoundsInScreen() is symmetric when the
1226 // widget is visible and not maximized or fullscreen.
1227 TEST_F(WidgetTest
, GetWindowBoundsInScreen
) {
1228 // Choose test coordinates away from edges and dimensions that are "small"
1229 // (but not too small) to ensure the OS doesn't try to adjust them.
1230 const gfx::Rect
kTestBounds(150, 150, 400, 300);
1231 const gfx::Size
kTestSize(200, 180);
1233 // First test a toplevel widget.
1234 Widget
* widget
= CreateTopLevelPlatformWidget();
1237 EXPECT_NE(kTestSize
.ToString(),
1238 widget
->GetWindowBoundsInScreen().size().ToString());
1239 widget
->SetSize(kTestSize
);
1240 EXPECT_EQ(kTestSize
.ToString(),
1241 widget
->GetWindowBoundsInScreen().size().ToString());
1243 EXPECT_NE(kTestBounds
.ToString(),
1244 widget
->GetWindowBoundsInScreen().ToString());
1245 widget
->SetBounds(kTestBounds
);
1246 EXPECT_EQ(kTestBounds
.ToString(),
1247 widget
->GetWindowBoundsInScreen().ToString());
1249 // Changing just the size should not change the origin.
1250 widget
->SetSize(kTestSize
);
1251 EXPECT_EQ(kTestBounds
.origin().ToString(),
1252 widget
->GetWindowBoundsInScreen().origin().ToString());
1256 // Same tests with a frameless window.
1257 widget
= CreateTopLevelFramelessPlatformWidget();
1260 EXPECT_NE(kTestSize
.ToString(),
1261 widget
->GetWindowBoundsInScreen().size().ToString());
1262 widget
->SetSize(kTestSize
);
1263 EXPECT_EQ(kTestSize
.ToString(),
1264 widget
->GetWindowBoundsInScreen().size().ToString());
1266 EXPECT_NE(kTestBounds
.ToString(),
1267 widget
->GetWindowBoundsInScreen().ToString());
1268 widget
->SetBounds(kTestBounds
);
1269 EXPECT_EQ(kTestBounds
.ToString(),
1270 widget
->GetWindowBoundsInScreen().ToString());
1272 // For a frameless widget, the client bounds should also match.
1273 EXPECT_EQ(kTestBounds
.ToString(),
1274 widget
->GetClientAreaBoundsInScreen().ToString());
1276 // Verify origin is stable for a frameless window as well.
1277 widget
->SetSize(kTestSize
);
1278 EXPECT_EQ(kTestBounds
.origin().ToString(),
1279 widget
->GetWindowBoundsInScreen().origin().ToString());
1284 // Before being enabled on Mac, this was #ifdef(false).
1285 // TODO(tapted): Fix this for DesktopNativeWidgets on other platforms.
1286 #if defined(OS_MACOSX)
1287 // Aura needs shell to maximize/fullscreen window.
1288 // NativeWidgetGtk doesn't implement GetRestoredBounds.
1289 TEST_F(WidgetTest
, GetRestoredBounds
) {
1290 Widget
* toplevel
= CreateTopLevelPlatformWidget();
1291 EXPECT_EQ(toplevel
->GetWindowBoundsInScreen().ToString(),
1292 toplevel
->GetRestoredBounds().ToString());
1294 toplevel
->Maximize();
1295 RunPendingMessages();
1296 #if defined(OS_MACOSX)
1297 // Current expectation on Mac is to do nothing on Maximize.
1298 EXPECT_EQ(toplevel
->GetWindowBoundsInScreen().ToString(),
1299 toplevel
->GetRestoredBounds().ToString());
1301 EXPECT_NE(toplevel
->GetWindowBoundsInScreen().ToString(),
1302 toplevel
->GetRestoredBounds().ToString());
1304 EXPECT_GT(toplevel
->GetRestoredBounds().width(), 0);
1305 EXPECT_GT(toplevel
->GetRestoredBounds().height(), 0);
1307 toplevel
->Restore();
1308 RunPendingMessages();
1309 EXPECT_EQ(toplevel
->GetWindowBoundsInScreen().ToString(),
1310 toplevel
->GetRestoredBounds().ToString());
1312 toplevel
->SetFullscreen(true);
1313 RunPendingMessages();
1315 if (IsTestingSnowLeopard()) {
1316 // Fullscreen not implemented for Snow Leopard.
1317 EXPECT_EQ(toplevel
->GetWindowBoundsInScreen().ToString(),
1318 toplevel
->GetRestoredBounds().ToString());
1320 EXPECT_NE(toplevel
->GetWindowBoundsInScreen().ToString(),
1321 toplevel
->GetRestoredBounds().ToString());
1323 EXPECT_GT(toplevel
->GetRestoredBounds().width(), 0);
1324 EXPECT_GT(toplevel
->GetRestoredBounds().height(), 0);
1328 // The key-event propagation from Widget happens differently on aura and
1329 // non-aura systems because of the difference in IME. So this test works only on
1331 TEST_F(WidgetTest
, KeyboardInputEvent
) {
1332 Widget
* toplevel
= CreateTopLevelPlatformWidget();
1333 View
* container
= toplevel
->client_view();
1335 Textfield
* textfield
= new Textfield();
1336 textfield
->SetText(base::ASCIIToUTF16("some text"));
1337 container
->AddChildView(textfield
);
1339 textfield
->RequestFocus();
1341 // The press gets handled. The release doesn't have an effect.
1342 ui::KeyEvent
backspace_p(ui::ET_KEY_PRESSED
, ui::VKEY_DELETE
, ui::EF_NONE
);
1343 toplevel
->OnKeyEvent(&backspace_p
);
1344 EXPECT_TRUE(backspace_p
.stopped_propagation());
1345 ui::KeyEvent
backspace_r(ui::ET_KEY_RELEASED
, ui::VKEY_DELETE
, ui::EF_NONE
);
1346 toplevel
->OnKeyEvent(&backspace_r
);
1347 EXPECT_FALSE(backspace_r
.handled());
1352 // Verifies bubbles result in a focus lost when shown.
1353 // TODO(msw): this tests relies on focus, it needs to be in
1354 // interactive_ui_tests.
1355 TEST_F(WidgetTest
, DISABLED_FocusChangesOnBubble
) {
1356 // Create a widget, show and activate it and focus the contents view.
1357 View
* contents_view
= new View
;
1358 contents_view
->SetFocusable(true);
1360 Widget::InitParams init_params
=
1361 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS
);
1362 init_params
.bounds
= gfx::Rect(0, 0, 200, 200);
1363 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1364 #if !defined(OS_CHROMEOS)
1365 init_params
.native_widget
= new PlatformDesktopNativeWidget(&widget
);
1367 widget
.Init(init_params
);
1368 widget
.SetContentsView(contents_view
);
1371 contents_view
->RequestFocus();
1372 EXPECT_TRUE(contents_view
->HasFocus());
1375 BubbleDelegateView
* bubble_delegate_view
=
1376 new BubbleDelegateView(contents_view
, BubbleBorder::TOP_LEFT
);
1377 bubble_delegate_view
->SetFocusable(true);
1378 BubbleDelegateView::CreateBubble(bubble_delegate_view
)->Show();
1379 bubble_delegate_view
->RequestFocus();
1381 // |contents_view_| should no longer have focus.
1382 EXPECT_FALSE(contents_view
->HasFocus());
1383 EXPECT_TRUE(bubble_delegate_view
->HasFocus());
1385 bubble_delegate_view
->GetWidget()->CloseNow();
1387 // Closing the bubble should result in focus going back to the contents view.
1388 EXPECT_TRUE(contents_view
->HasFocus());
1391 class TestBubbleDelegateView
: public BubbleDelegateView
{
1393 TestBubbleDelegateView(View
* anchor
)
1394 : BubbleDelegateView(anchor
, BubbleBorder::NONE
),
1395 reset_controls_called_(false) {}
1396 ~TestBubbleDelegateView() override
{}
1398 bool ShouldShowCloseButton() const override
{
1399 reset_controls_called_
= true;
1403 mutable bool reset_controls_called_
;
1406 TEST_F(WidgetTest
, BubbleControlsResetOnInit
) {
1407 Widget
* anchor
= CreateTopLevelPlatformWidget();
1410 TestBubbleDelegateView
* bubble_delegate
=
1411 new TestBubbleDelegateView(anchor
->client_view());
1412 Widget
* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate
));
1413 EXPECT_TRUE(bubble_delegate
->reset_controls_called_
);
1414 bubble_widget
->Show();
1415 bubble_widget
->CloseNow();
1422 // Test to ensure that after minimize, view width is set to zero. This is only
1423 // the case for desktop widgets on Windows. Other platforms retain the window
1424 // size while minimized.
1425 TEST_F(WidgetTest
, TestViewWidthAfterMinimizingWidget
) {
1428 Widget::InitParams init_params
=
1429 CreateParams(Widget::InitParams::TYPE_WINDOW
);
1430 init_params
.show_state
= ui::SHOW_STATE_NORMAL
;
1431 gfx::Rect
initial_bounds(0, 0, 300, 400);
1432 init_params
.bounds
= initial_bounds
;
1433 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1434 init_params
.native_widget
= new PlatformDesktopNativeWidget(&widget
);
1435 widget
.Init(init_params
);
1436 NonClientView
* non_client_view
= widget
.non_client_view();
1437 NonClientFrameView
* frame_view
= new MinimumSizeFrameView(&widget
);
1438 non_client_view
->SetFrameView(frame_view
);
1439 // Setting the frame view doesn't do a layout, so force one.
1440 non_client_view
->Layout();
1442 EXPECT_NE(0, frame_view
->width());
1444 EXPECT_EQ(0, frame_view
->width());
1448 // Desktop native widget Aura tests are for non Chrome OS platforms.
1449 #if !defined(OS_CHROMEOS)
1450 // This class validates whether paints are received for a visible Widget.
1451 // To achieve this it overrides the Show and Close methods on the Widget class
1452 // and sets state whether subsequent paints are expected.
1453 class DesktopAuraTestValidPaintWidget
: public views::Widget
{
1455 DesktopAuraTestValidPaintWidget()
1456 : received_paint_(false),
1457 expect_paint_(true),
1458 received_paint_while_hidden_(false) {}
1460 ~DesktopAuraTestValidPaintWidget() override
{}
1462 void InitForTest(Widget::InitParams create_params
);
1464 void Show() override
{
1465 expect_paint_
= true;
1466 views::Widget::Show();
1469 void Close() override
{
1470 expect_paint_
= false;
1471 views::Widget::Close();
1475 expect_paint_
= false;
1476 views::Widget::Hide();
1479 void OnNativeWidgetPaint(const ui::PaintContext
& context
) override
{
1480 received_paint_
= true;
1481 EXPECT_TRUE(expect_paint_
);
1483 received_paint_while_hidden_
= true;
1484 views::Widget::OnNativeWidgetPaint(context
);
1487 bool ReadReceivedPaintAndReset() {
1488 bool result
= received_paint_
;
1489 received_paint_
= false;
1493 bool received_paint_while_hidden() const {
1494 return received_paint_while_hidden_
;
1498 bool received_paint_
;
1500 bool received_paint_while_hidden_
;
1502 DISALLOW_COPY_AND_ASSIGN(DesktopAuraTestValidPaintWidget
);
1505 void DesktopAuraTestValidPaintWidget::InitForTest(InitParams init_params
) {
1506 init_params
.bounds
= gfx::Rect(0, 0, 200, 200);
1507 init_params
.ownership
= InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1508 init_params
.native_widget
= new PlatformDesktopNativeWidget(this);
1511 View
* contents_view
= new View
;
1512 contents_view
->SetFocusable(true);
1513 SetContentsView(contents_view
);
1519 TEST_F(WidgetTest
, DesktopNativeWidgetNoPaintAfterCloseTest
) {
1520 DesktopAuraTestValidPaintWidget widget
;
1521 widget
.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS
));
1522 RunPendingMessages();
1523 EXPECT_TRUE(widget
.ReadReceivedPaintAndReset());
1524 widget
.SchedulePaintInRect(widget
.GetRestoredBounds());
1526 RunPendingMessages();
1527 EXPECT_FALSE(widget
.ReadReceivedPaintAndReset());
1528 EXPECT_FALSE(widget
.received_paint_while_hidden());
1531 TEST_F(WidgetTest
, DesktopNativeWidgetNoPaintAfterHideTest
) {
1532 DesktopAuraTestValidPaintWidget widget
;
1533 widget
.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS
));
1534 RunPendingMessages();
1535 EXPECT_TRUE(widget
.ReadReceivedPaintAndReset());
1536 widget
.SchedulePaintInRect(widget
.GetRestoredBounds());
1538 RunPendingMessages();
1539 EXPECT_FALSE(widget
.ReadReceivedPaintAndReset());
1540 EXPECT_FALSE(widget
.received_paint_while_hidden());
1544 // Test to ensure that the aura Window's visiblity state is set to visible if
1545 // the underlying widget is hidden and then shown.
1546 TEST_F(WidgetTest
, TestWindowVisibilityAfterHide
) {
1549 Widget::InitParams init_params
=
1550 CreateParams(Widget::InitParams::TYPE_WINDOW
);
1551 init_params
.show_state
= ui::SHOW_STATE_NORMAL
;
1552 gfx::Rect
initial_bounds(0, 0, 300, 400);
1553 init_params
.bounds
= initial_bounds
;
1554 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1555 init_params
.native_widget
= new PlatformDesktopNativeWidget(&widget
);
1556 widget
.Init(init_params
);
1557 NonClientView
* non_client_view
= widget
.non_client_view();
1558 NonClientFrameView
* frame_view
= new MinimumSizeFrameView(&widget
);
1559 non_client_view
->SetFrameView(frame_view
);
1562 EXPECT_TRUE(IsNativeWindowVisible(widget
.GetNativeWindow()));
1564 EXPECT_FALSE(IsNativeWindowVisible(widget
.GetNativeWindow()));
1566 EXPECT_TRUE(IsNativeWindowVisible(widget
.GetNativeWindow()));
1569 #endif // !defined(OS_CHROMEOS)
1571 // Tests that wheel events generated from scroll events are targetted to the
1572 // views under the cursor when the focused view does not processed them.
1573 TEST_F(WidgetTest
, WheelEventsFromScrollEventTarget
) {
1574 EventCountView
* cursor_view
= new EventCountView
;
1575 cursor_view
->SetBounds(60, 0, 50, 40);
1577 Widget
* widget
= CreateTopLevelPlatformWidget();
1578 widget
->GetRootView()->AddChildView(cursor_view
);
1580 // Generate a scroll event on the cursor view.
1581 ui::ScrollEvent
scroll(ui::ET_SCROLL
,
1583 ui::EventTimeForNow(),
1588 widget
->OnScrollEvent(&scroll
);
1590 EXPECT_EQ(1, cursor_view
->GetEventCount(ui::ET_SCROLL
));
1591 EXPECT_EQ(1, cursor_view
->GetEventCount(ui::ET_MOUSEWHEEL
));
1593 cursor_view
->ResetCounts();
1595 ui::ScrollEvent
scroll2(ui::ET_SCROLL
,
1597 ui::EventTimeForNow(),
1602 widget
->OnScrollEvent(&scroll2
);
1604 EXPECT_EQ(0, cursor_view
->GetEventCount(ui::ET_SCROLL
));
1605 EXPECT_EQ(0, cursor_view
->GetEventCount(ui::ET_MOUSEWHEEL
));
1610 // Tests that if a scroll-begin gesture is not handled, then subsequent scroll
1611 // events are not dispatched to any view.
1612 TEST_F(WidgetTest
, GestureScrollEventDispatching
) {
1613 EventCountView
* noscroll_view
= new EventCountView
;
1614 EventCountView
* scroll_view
= new ScrollableEventCountView
;
1616 noscroll_view
->SetBounds(0, 0, 50, 40);
1617 scroll_view
->SetBounds(60, 0, 40, 40);
1619 Widget
* widget
= CreateTopLevelPlatformWidget();
1620 widget
->GetRootView()->AddChildView(noscroll_view
);
1621 widget
->GetRootView()->AddChildView(scroll_view
);
1624 ui::GestureEvent
begin(
1629 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN
));
1630 widget
->OnGestureEvent(&begin
);
1631 ui::GestureEvent
update(
1636 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE
, 20, 10));
1637 widget
->OnGestureEvent(&update
);
1638 ui::GestureEvent
end(25,
1642 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END
));
1643 widget
->OnGestureEvent(&end
);
1645 EXPECT_EQ(1, noscroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
1646 EXPECT_EQ(0, noscroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
1647 EXPECT_EQ(0, noscroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
1651 ui::GestureEvent
begin(
1656 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN
));
1657 widget
->OnGestureEvent(&begin
);
1658 ui::GestureEvent
update(
1663 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE
, 20, 10));
1664 widget
->OnGestureEvent(&update
);
1665 ui::GestureEvent
end(85,
1669 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END
));
1670 widget
->OnGestureEvent(&end
);
1672 EXPECT_EQ(1, scroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
1673 EXPECT_EQ(1, scroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
1674 EXPECT_EQ(1, scroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
1680 // Tests that event-handlers installed on the RootView get triggered correctly.
1681 // TODO(tdanderson): Clean up this test as part of crbug.com/355680.
1682 TEST_F(WidgetTest
, EventHandlersOnRootView
) {
1683 Widget
* widget
= CreateTopLevelNativeWidget();
1684 View
* root_view
= widget
->GetRootView();
1686 scoped_ptr
<EventCountView
> view(new EventCountView());
1687 view
->set_owned_by_client();
1688 view
->SetBounds(0, 0, 20, 20);
1689 root_view
->AddChildView(view
.get());
1691 EventCountHandler h1
;
1692 root_view
->AddPreTargetHandler(&h1
);
1694 EventCountHandler h2
;
1695 root_view
->AddPostTargetHandler(&h2
);
1697 widget
->SetBounds(gfx::Rect(0, 0, 100, 100));
1700 // Dispatch a ui::ET_SCROLL event. The event remains unhandled and should
1701 // bubble up the views hierarchy to be re-dispatched on the root view.
1702 ui::ScrollEvent
scroll(ui::ET_SCROLL
,
1704 ui::EventTimeForNow(),
1709 widget
->OnScrollEvent(&scroll
);
1710 EXPECT_EQ(2, h1
.GetEventCount(ui::ET_SCROLL
));
1711 EXPECT_EQ(1, view
->GetEventCount(ui::ET_SCROLL
));
1712 EXPECT_EQ(2, h2
.GetEventCount(ui::ET_SCROLL
));
1714 // Unhandled scroll events are turned into wheel events and re-dispatched.
1715 EXPECT_EQ(1, h1
.GetEventCount(ui::ET_MOUSEWHEEL
));
1716 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSEWHEEL
));
1717 EXPECT_EQ(1, h2
.GetEventCount(ui::ET_MOUSEWHEEL
));
1720 view
->ResetCounts();
1723 // Dispatch a ui::ET_SCROLL_FLING_START event. The event remains unhandled and
1724 // should bubble up the views hierarchy to be re-dispatched on the root view.
1725 ui::ScrollEvent
fling(ui::ET_SCROLL_FLING_START
,
1727 ui::EventTimeForNow(),
1732 widget
->OnScrollEvent(&fling
);
1733 EXPECT_EQ(2, h1
.GetEventCount(ui::ET_SCROLL_FLING_START
));
1734 EXPECT_EQ(1, view
->GetEventCount(ui::ET_SCROLL_FLING_START
));
1735 EXPECT_EQ(2, h2
.GetEventCount(ui::ET_SCROLL_FLING_START
));
1737 // Unhandled scroll events which are not of type ui::ET_SCROLL should not
1738 // be turned into wheel events and re-dispatched.
1739 EXPECT_EQ(0, h1
.GetEventCount(ui::ET_MOUSEWHEEL
));
1740 EXPECT_EQ(0, view
->GetEventCount(ui::ET_MOUSEWHEEL
));
1741 EXPECT_EQ(0, h2
.GetEventCount(ui::ET_MOUSEWHEEL
));
1744 view
->ResetCounts();
1747 // Change the handle mode of |view| so that events are marked as handled at
1748 // the target phase.
1749 view
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
1751 // Dispatch a ui::ET_GESTURE_TAP_DOWN and a ui::ET_GESTURE_TAP_CANCEL event.
1752 // The events are handled at the target phase and should not reach the
1753 // post-target handler.
1754 ui::GestureEvent
tap_down(5,
1757 ui::EventTimeForNow(),
1758 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN
));
1759 widget
->OnGestureEvent(&tap_down
);
1760 EXPECT_EQ(1, h1
.GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
1761 EXPECT_EQ(1, view
->GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
1762 EXPECT_EQ(0, h2
.GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
1764 ui::GestureEvent
tap_cancel(
1768 ui::EventTimeForNow(),
1769 ui::GestureEventDetails(ui::ET_GESTURE_TAP_CANCEL
));
1770 widget
->OnGestureEvent(&tap_cancel
);
1771 EXPECT_EQ(1, h1
.GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
1772 EXPECT_EQ(1, view
->GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
1773 EXPECT_EQ(0, h2
.GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
1776 view
->ResetCounts();
1779 // Dispatch a ui::ET_SCROLL event. The event is handled at the target phase
1780 // and should not reach the post-target handler.
1781 ui::ScrollEvent
consumed_scroll(ui::ET_SCROLL
,
1783 ui::EventTimeForNow(),
1788 widget
->OnScrollEvent(&consumed_scroll
);
1789 EXPECT_EQ(1, h1
.GetEventCount(ui::ET_SCROLL
));
1790 EXPECT_EQ(1, view
->GetEventCount(ui::ET_SCROLL
));
1791 EXPECT_EQ(0, h2
.GetEventCount(ui::ET_SCROLL
));
1793 // Handled scroll events are not turned into wheel events and re-dispatched.
1794 EXPECT_EQ(0, h1
.GetEventCount(ui::ET_MOUSEWHEEL
));
1795 EXPECT_EQ(0, view
->GetEventCount(ui::ET_MOUSEWHEEL
));
1796 EXPECT_EQ(0, h2
.GetEventCount(ui::ET_MOUSEWHEEL
));
1801 TEST_F(WidgetTest
, SynthesizeMouseMoveEvent
) {
1802 Widget
* widget
= CreateTopLevelNativeWidget();
1803 View
* root_view
= widget
->GetRootView();
1805 EventCountView
* v1
= new EventCountView();
1806 v1
->SetBounds(0, 0, 10, 10);
1807 root_view
->AddChildView(v1
);
1808 EventCountView
* v2
= new EventCountView();
1809 v2
->SetBounds(0, 10, 10, 10);
1810 root_view
->AddChildView(v2
);
1812 gfx::Point
cursor_location(5, 5);
1813 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
, cursor_location
, cursor_location
,
1814 ui::EventTimeForNow(), ui::EF_NONE
, ui::EF_NONE
);
1815 widget
->OnMouseEvent(&move
);
1817 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_MOUSE_ENTERED
));
1818 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_MOUSE_ENTERED
));
1821 v2
->SetBounds(0, 0, 10, 10);
1822 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_MOUSE_ENTERED
));
1824 widget
->SynthesizeMouseMoveEvent();
1825 EXPECT_EQ(1, v2
->GetEventCount(ui::ET_MOUSE_ENTERED
));
1830 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
1831 #if !defined(OS_MACOSX) || defined(USE_AURA)
1835 // ui::EventHandler which handles all mouse press events.
1836 class MousePressEventConsumer
: public ui::EventHandler
{
1838 MousePressEventConsumer() {}
1841 // ui::EventHandler:
1842 void OnMouseEvent(ui::MouseEvent
* event
) override
{
1843 if (event
->type() == ui::ET_MOUSE_PRESSED
)
1844 event
->SetHandled();
1847 DISALLOW_COPY_AND_ASSIGN(MousePressEventConsumer
);
1852 // Test that mouse presses and mouse releases are dispatched normally when a
1854 TEST_F(WidgetTest
, MouseEventDispatchWhileTouchIsDown
) {
1855 Widget
* widget
= CreateTopLevelNativeWidget();
1857 widget
->SetSize(gfx::Size(300, 300));
1859 EventCountView
* event_count_view
= new EventCountView();
1860 event_count_view
->SetBounds(0, 0, 300, 300);
1861 widget
->GetRootView()->AddChildView(event_count_view
);
1863 MousePressEventConsumer consumer
;
1864 event_count_view
->AddPostTargetHandler(&consumer
);
1866 ui::test::EventGenerator
generator(GetContext(), widget
->GetNativeWindow());
1867 generator
.PressTouch();
1868 generator
.ClickLeftButton();
1870 EXPECT_EQ(1, event_count_view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
1871 EXPECT_EQ(1, event_count_view
->GetEventCount(ui::ET_MOUSE_RELEASED
));
1876 #endif // !defined(OS_MACOSX) || defined(USE_AURA)
1878 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget
1880 TEST_F(WidgetTest
, SingleWindowClosing
) {
1881 TestDesktopWidgetDelegate delegate
;
1882 delegate
.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW
));
1883 EXPECT_EQ(0, delegate
.window_closing_count());
1884 delegate
.GetWidget()->CloseNow();
1885 EXPECT_EQ(1, delegate
.window_closing_count());
1888 class WidgetWindowTitleTest
: public WidgetTest
{
1890 void RunTest(bool desktop_native_widget
) {
1891 Widget
* widget
= new Widget(); // Destroyed by CloseNow() below.
1892 Widget::InitParams init_params
=
1893 CreateParams(Widget::InitParams::TYPE_WINDOW
);
1894 widget
->Init(init_params
);
1896 #if !defined(OS_CHROMEOS)
1897 if (desktop_native_widget
)
1898 init_params
.native_widget
= new PlatformDesktopNativeWidget(widget
);
1900 DCHECK(!desktop_native_widget
)
1901 << "DesktopNativeWidget does not exist on non-Aura or on ChromeOS.";
1904 internal::NativeWidgetPrivate
* native_widget
=
1905 widget
->native_widget_private();
1907 base::string16 empty
;
1908 base::string16
s1(base::UTF8ToUTF16("Title1"));
1909 base::string16
s2(base::UTF8ToUTF16("Title2"));
1910 base::string16
s3(base::UTF8ToUTF16("TitleLong"));
1912 // The widget starts with no title, setting empty should not change
1914 EXPECT_FALSE(native_widget
->SetWindowTitle(empty
));
1915 // Setting the title to something non-empty should cause a change.
1916 EXPECT_TRUE(native_widget
->SetWindowTitle(s1
));
1917 // Setting the title to something else with the same length should cause a
1919 EXPECT_TRUE(native_widget
->SetWindowTitle(s2
));
1920 // Setting the title to something else with a different length should cause
1922 EXPECT_TRUE(native_widget
->SetWindowTitle(s3
));
1923 // Setting the title to the same thing twice should not cause a change.
1924 EXPECT_FALSE(native_widget
->SetWindowTitle(s3
));
1930 TEST_F(WidgetWindowTitleTest
, SetWindowTitleChanged_NativeWidget
) {
1931 // Use the default NativeWidget.
1932 bool desktop_native_widget
= false;
1933 RunTest(desktop_native_widget
);
1936 // DesktopNativeWidget does not exist on non-Aura or on ChromeOS.
1937 #if !defined(OS_CHROMEOS)
1938 TEST_F(WidgetWindowTitleTest
, SetWindowTitleChanged_DesktopNativeWidget
) {
1939 // Override to use a DesktopNativeWidget.
1940 bool desktop_native_widget
= true;
1941 RunTest(desktop_native_widget
);
1943 #endif // !OS_CHROMEOS
1945 TEST_F(WidgetTest
, WidgetDeleted_InOnMousePressed
) {
1946 Widget
* widget
= new Widget
;
1947 Widget::InitParams params
=
1948 CreateParams(views::Widget::InitParams::TYPE_POPUP
);
1949 widget
->Init(params
);
1951 widget
->SetContentsView(new CloseWidgetView(ui::ET_MOUSE_PRESSED
));
1953 widget
->SetSize(gfx::Size(100, 100));
1956 ui::test::EventGenerator
generator(GetContext(), widget
->GetNativeWindow());
1958 WidgetDeletionObserver
deletion_observer(widget
);
1959 generator
.ClickLeftButton();
1960 EXPECT_FALSE(deletion_observer
.IsWidgetAlive());
1962 // Yay we did not crash!
1965 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
1966 #if !defined(OS_MACOSX) || defined(USE_AURA)
1968 TEST_F(WidgetTest
, WidgetDeleted_InDispatchGestureEvent
) {
1969 Widget
* widget
= new Widget
;
1970 Widget::InitParams params
=
1971 CreateParams(views::Widget::InitParams::TYPE_POPUP
);
1972 widget
->Init(params
);
1974 widget
->SetContentsView(new CloseWidgetView(ui::ET_GESTURE_TAP_DOWN
));
1976 widget
->SetSize(gfx::Size(100, 100));
1979 ui::test::EventGenerator
generator(GetContext(), widget
->GetNativeWindow());
1981 WidgetDeletionObserver
deletion_observer(widget
);
1982 generator
.GestureTapAt(widget
->GetWindowBoundsInScreen().CenterPoint());
1983 EXPECT_FALSE(deletion_observer
.IsWidgetAlive());
1985 // Yay we did not crash!
1988 #endif // !defined(OS_MACOSX) || defined(USE_AURA)
1990 // See description of RunGetNativeThemeFromDestructor() for details.
1991 class GetNativeThemeFromDestructorView
: public WidgetDelegateView
{
1993 GetNativeThemeFromDestructorView() {}
1994 ~GetNativeThemeFromDestructorView() override
{ VerifyNativeTheme(); }
1996 View
* GetContentsView() override
{ return this; }
1999 void VerifyNativeTheme() {
2000 ASSERT_TRUE(GetNativeTheme() != NULL
);
2003 DISALLOW_COPY_AND_ASSIGN(GetNativeThemeFromDestructorView
);
2006 // Verifies GetNativeTheme() from the destructor of a WidgetDelegateView doesn't
2007 // crash. |is_first_run| is true if this is the first call. A return value of
2008 // true indicates this should be run again with a value of false.
2009 // First run uses DesktopNativeWidgetAura (if possible). Second run doesn't.
2010 bool RunGetNativeThemeFromDestructor(const Widget::InitParams
& in_params
,
2011 bool is_first_run
) {
2012 bool needs_second_run
= false;
2013 // Destroyed by CloseNow() below.
2014 Widget
* widget
= new Widget
;
2015 Widget::InitParams
params(in_params
);
2016 // Deletes itself when the Widget is destroyed.
2017 params
.delegate
= new GetNativeThemeFromDestructorView
;
2018 #if !defined(OS_CHROMEOS)
2020 params
.native_widget
= new PlatformDesktopNativeWidget(widget
);
2021 needs_second_run
= true;
2024 widget
->Init(params
);
2026 return needs_second_run
;
2029 // See description of RunGetNativeThemeFromDestructor() for details.
2030 TEST_F(WidgetTest
, GetNativeThemeFromDestructor
) {
2031 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
2032 if (RunGetNativeThemeFromDestructor(params
, true))
2033 RunGetNativeThemeFromDestructor(params
, false);
2036 // Used by HideCloseDestroy. Allows setting a boolean when the widget is
2038 class CloseDestroysWidget
: public Widget
{
2040 explicit CloseDestroysWidget(bool* destroyed
)
2041 : destroyed_(destroyed
) {
2044 ~CloseDestroysWidget() override
{
2047 base::MessageLoop::current()->QuitNow();
2051 void Detach() { destroyed_
= NULL
; }
2054 // If non-null set to true from destructor.
2057 DISALLOW_COPY_AND_ASSIGN(CloseDestroysWidget
);
2060 // An observer that registers that an animation has ended.
2061 class AnimationEndObserver
: public ui::ImplicitAnimationObserver
{
2063 AnimationEndObserver() : animation_completed_(false) {}
2064 ~AnimationEndObserver() override
{}
2066 bool animation_completed() const { return animation_completed_
; }
2068 // ui::ImplicitAnimationObserver:
2069 void OnImplicitAnimationsCompleted() override
{ animation_completed_
= true; }
2072 bool animation_completed_
;
2074 DISALLOW_COPY_AND_ASSIGN(AnimationEndObserver
);
2077 // An observer that registers the bounds of a widget on destruction.
2078 class WidgetBoundsObserver
: public WidgetObserver
{
2080 WidgetBoundsObserver() {}
2081 ~WidgetBoundsObserver() override
{}
2083 gfx::Rect
bounds() { return bounds_
; }
2086 void OnWidgetDestroying(Widget
* widget
) override
{
2087 bounds_
= widget
->GetWindowBoundsInScreen();
2093 DISALLOW_COPY_AND_ASSIGN(WidgetBoundsObserver
);
2096 // Verifies Close() results in destroying.
2097 TEST_F(WidgetTest
, CloseDestroys
) {
2098 bool destroyed
= false;
2099 CloseDestroysWidget
* widget
= new CloseDestroysWidget(&destroyed
);
2100 Widget::InitParams params
=
2101 CreateParams(views::Widget::InitParams::TYPE_MENU
);
2102 params
.opacity
= Widget::InitParams::OPAQUE_WINDOW
;
2103 #if !defined(OS_CHROMEOS)
2104 params
.native_widget
= new PlatformDesktopNativeWidget(widget
);
2106 widget
->Init(params
);
2110 EXPECT_FALSE(destroyed
);
2111 // Run the message loop as Close() asynchronously deletes.
2112 base::RunLoop().Run();
2113 EXPECT_TRUE(destroyed
);
2114 // Close() should destroy the widget. If not we'll cleanup to avoid leaks.
2121 // Tests that killing a widget while animating it does not crash.
2122 TEST_F(WidgetTest
, CloseWidgetWhileAnimating
) {
2123 scoped_ptr
<Widget
> widget(new Widget
);
2124 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
2125 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
2126 params
.bounds
= gfx::Rect(50, 50, 250, 250);
2127 widget
->Init(params
);
2128 AnimationEndObserver animation_observer
;
2129 WidgetBoundsObserver widget_observer
;
2130 gfx::Rect
bounds(0, 0, 50, 50);
2132 // Normal animations for tests have ZERO_DURATION, make sure we are actually
2133 // animating the movement.
2134 ui::ScopedAnimationDurationScaleMode
animation_scale_mode(
2135 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION
);
2136 ui::ScopedLayerAnimationSettings
animation_settings(
2137 widget
->GetLayer()->GetAnimator());
2138 animation_settings
.AddObserver(&animation_observer
);
2139 widget
->AddObserver(&widget_observer
);
2142 // Animate the bounds change.
2143 widget
->SetBounds(bounds
);
2145 EXPECT_FALSE(animation_observer
.animation_completed());
2147 EXPECT_TRUE(animation_observer
.animation_completed());
2148 EXPECT_EQ(widget_observer
.bounds(), bounds
);
2151 // Tests that we do not crash when a Widget is destroyed by going out of
2152 // scope (as opposed to being explicitly deleted by its NativeWidget).
2153 TEST_F(WidgetTest
, NoCrashOnWidgetDelete
) {
2154 scoped_ptr
<Widget
> widget(new Widget
);
2155 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
2156 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
2157 widget
->Init(params
);
2160 // Tests that we do not crash when a Widget is destroyed before it finishes
2161 // processing of pending input events in the message loop.
2162 TEST_F(WidgetTest
, NoCrashOnWidgetDeleteWithPendingEvents
) {
2163 scoped_ptr
<Widget
> widget(new Widget
);
2164 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_WINDOW
);
2165 params
.bounds
= gfx::Rect(0, 0, 200, 200);
2166 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
2167 widget
->Init(params
);
2170 ui::test::EventGenerator
generator(GetContext(), widget
->GetNativeWindow());
2171 generator
.MoveMouseTo(10, 10);
2173 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
2174 #if defined(OS_MACOSX) && !defined(USE_AURA)
2175 generator
.ClickLeftButton();
2177 generator
.PressTouch();
2182 // A view that consumes mouse-pressed event and gesture-tap-down events.
2183 class RootViewTestView
: public View
{
2185 RootViewTestView(): View() {}
2188 bool OnMousePressed(const ui::MouseEvent
& event
) override
{ return true; }
2190 void OnGestureEvent(ui::GestureEvent
* event
) override
{
2191 if (event
->type() == ui::ET_GESTURE_TAP_DOWN
)
2192 event
->SetHandled();
2196 // Checks if RootView::*_handler_ fields are unset when widget is hidden.
2197 // Fails on chromium.webkit Windows bot, see crbug.com/264872.
2199 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
2200 DISABLED_TestRootViewHandlersWhenHidden
2202 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
2203 TestRootViewHandlersWhenHidden
2205 TEST_F(WidgetTest
, MAYBE_DisableTestRootViewHandlersWhenHidden
) {
2206 Widget
* widget
= CreateTopLevelNativeWidget();
2207 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
2208 View
* view
= new RootViewTestView();
2209 view
->SetBounds(0, 0, 300, 300);
2210 internal::RootView
* root_view
=
2211 static_cast<internal::RootView
*>(widget
->GetRootView());
2212 root_view
->AddChildView(view
);
2214 // Check RootView::mouse_pressed_handler_.
2216 EXPECT_EQ(NULL
, GetMousePressedHandler(root_view
));
2217 gfx::Point
click_location(45, 15);
2218 ui::MouseEvent
press(ui::ET_MOUSE_PRESSED
, click_location
, click_location
,
2219 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON
,
2220 ui::EF_LEFT_MOUSE_BUTTON
);
2221 widget
->OnMouseEvent(&press
);
2222 EXPECT_EQ(view
, GetMousePressedHandler(root_view
));
2224 EXPECT_EQ(NULL
, GetMousePressedHandler(root_view
));
2226 // Check RootView::mouse_move_handler_.
2228 EXPECT_EQ(NULL
, GetMouseMoveHandler(root_view
));
2229 gfx::Point
move_location(45, 15);
2230 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
, move_location
, move_location
,
2231 ui::EventTimeForNow(), 0, 0);
2232 widget
->OnMouseEvent(&move
);
2233 EXPECT_EQ(view
, GetMouseMoveHandler(root_view
));
2235 EXPECT_EQ(NULL
, GetMouseMoveHandler(root_view
));
2237 // Check RootView::gesture_handler_.
2239 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2240 ui::GestureEvent
tap_down(15,
2244 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN
));
2245 widget
->OnGestureEvent(&tap_down
);
2246 EXPECT_EQ(view
, GetGestureHandler(root_view
));
2248 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2253 // Convenience to make constructing a GestureEvent simpler.
2254 class GestureEventForTest
: public ui::GestureEvent
{
2256 GestureEventForTest(ui::EventType type
, int x
, int y
)
2261 ui::GestureEventDetails(type
)) {}
2263 GestureEventForTest(ui::GestureEventDetails details
, int x
, int y
)
2264 : GestureEvent(x
, y
, 0, base::TimeDelta(), details
) {}
2267 // Tests that the |gesture_handler_| member in RootView is always NULL
2268 // after the dispatch of a ui::ET_GESTURE_END event corresponding to
2269 // the release of the final touch point on the screen, but that
2270 // ui::ET_GESTURE_END events corresponding to the removal of any other touch
2271 // point do not modify |gesture_handler_|.
2272 TEST_F(WidgetTest
, GestureEndEvents
) {
2273 Widget
* widget
= CreateTopLevelNativeWidget();
2274 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
2275 EventCountView
* view
= new EventCountView();
2276 view
->SetBounds(0, 0, 300, 300);
2277 internal::RootView
* root_view
=
2278 static_cast<internal::RootView
*>(widget
->GetRootView());
2279 root_view
->AddChildView(view
);
2282 // If no gesture handler is set, a ui::ET_GESTURE_END event should not set
2283 // the gesture handler.
2284 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2285 GestureEventForTest
end(ui::ET_GESTURE_END
, 15, 15);
2286 widget
->OnGestureEvent(&end
);
2287 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2289 // Change the handle mode of |view| to indicate that it would like
2290 // to handle all events, then send a GESTURE_TAP to set the gesture handler.
2291 view
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2292 GestureEventForTest
tap(ui::ET_GESTURE_TAP
, 15, 15);
2293 widget
->OnGestureEvent(&tap
);
2294 EXPECT_TRUE(tap
.handled());
2295 EXPECT_EQ(view
, GetGestureHandler(root_view
));
2297 // The gesture handler should remain unchanged on a ui::ET_GESTURE_END
2298 // corresponding to a second touch point, but should be reset to NULL by a
2299 // ui::ET_GESTURE_END corresponding to the final touch point.
2300 ui::GestureEventDetails
details(ui::ET_GESTURE_END
);
2301 details
.set_touch_points(2);
2302 GestureEventForTest
end_second_touch_point(details
, 15, 15);
2303 widget
->OnGestureEvent(&end_second_touch_point
);
2304 EXPECT_EQ(view
, GetGestureHandler(root_view
));
2306 end
= GestureEventForTest(ui::ET_GESTURE_END
, 15, 15);
2307 widget
->OnGestureEvent(&end
);
2308 EXPECT_TRUE(end
.handled());
2309 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2311 // Send a GESTURE_TAP to set the gesture handler, then change the handle
2312 // mode of |view| to indicate that it does not want to handle any
2314 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 15, 15);
2315 widget
->OnGestureEvent(&tap
);
2316 EXPECT_TRUE(tap
.handled());
2317 EXPECT_EQ(view
, GetGestureHandler(root_view
));
2318 view
->set_handle_mode(EventCountView::PROPAGATE_EVENTS
);
2320 // The gesture handler should remain unchanged on a ui::ET_GESTURE_END
2321 // corresponding to a second touch point, but should be reset to NULL by a
2322 // ui::ET_GESTURE_END corresponding to the final touch point.
2323 end_second_touch_point
= GestureEventForTest(details
, 15, 15);
2324 widget
->OnGestureEvent(&end_second_touch_point
);
2325 EXPECT_EQ(view
, GetGestureHandler(root_view
));
2327 end
= GestureEventForTest(ui::ET_GESTURE_END
, 15, 15);
2328 widget
->OnGestureEvent(&end
);
2329 EXPECT_FALSE(end
.handled());
2330 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2335 // Tests that gesture events which should not be processed (because
2336 // RootView::OnEventProcessingStarted() has marked them as handled) are not
2337 // dispatched to any views.
2338 TEST_F(WidgetTest
, GestureEventsNotProcessed
) {
2339 Widget
* widget
= CreateTopLevelNativeWidget();
2340 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
2342 // Define a hierarchy of four views (coordinates are in
2343 // their parent coordinate space).
2344 // v1 (0, 0, 300, 300)
2345 // v2 (0, 0, 100, 100)
2346 // v3 (0, 0, 50, 50)
2348 EventCountView
* v1
= new EventCountView();
2349 v1
->SetBounds(0, 0, 300, 300);
2350 EventCountView
* v2
= new EventCountView();
2351 v2
->SetBounds(0, 0, 100, 100);
2352 EventCountView
* v3
= new EventCountView();
2353 v3
->SetBounds(0, 0, 50, 50);
2354 EventCountView
* v4
= new EventCountView();
2355 v4
->SetBounds(0, 0, 10, 10);
2356 internal::RootView
* root_view
=
2357 static_cast<internal::RootView
*>(widget
->GetRootView());
2358 root_view
->AddChildView(v1
);
2359 v1
->AddChildView(v2
);
2360 v2
->AddChildView(v3
);
2361 v3
->AddChildView(v4
);
2365 // ui::ET_GESTURE_BEGIN events should never be seen by any view, but
2366 // they should be marked as handled by OnEventProcessingStarted().
2367 GestureEventForTest
begin(ui::ET_GESTURE_BEGIN
, 5, 5);
2368 widget
->OnGestureEvent(&begin
);
2369 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_BEGIN
));
2370 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_BEGIN
));
2371 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_BEGIN
));
2372 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_BEGIN
));
2373 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2374 EXPECT_TRUE(begin
.handled());
2380 // ui::ET_GESTURE_END events should not be seen by any view when there is
2381 // no default gesture handler set, but they should be marked as handled by
2382 // OnEventProcessingStarted().
2383 GestureEventForTest
end(ui::ET_GESTURE_END
, 5, 5);
2384 widget
->OnGestureEvent(&end
);
2385 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_END
));
2386 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_END
));
2387 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_END
));
2388 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_END
));
2389 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2390 EXPECT_TRUE(end
.handled());
2396 // ui::ET_GESTURE_END events not corresponding to the release of the
2397 // final touch point should never be seen by any view, but they should
2398 // be marked as handled by OnEventProcessingStarted().
2399 ui::GestureEventDetails
details(ui::ET_GESTURE_END
);
2400 details
.set_touch_points(2);
2401 GestureEventForTest
end_second_touch_point(details
, 5, 5);
2402 widget
->OnGestureEvent(&end_second_touch_point
);
2403 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_END
));
2404 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_END
));
2405 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_END
));
2406 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_END
));
2407 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2408 EXPECT_TRUE(end_second_touch_point
.handled());
2414 // ui::ET_GESTURE_SCROLL_UPDATE events should never be seen by any view when
2415 // there is no default gesture handler set, but they should be marked as
2416 // handled by OnEventProcessingStarted().
2417 GestureEventForTest
scroll_update(ui::ET_GESTURE_SCROLL_UPDATE
, 5, 5);
2418 widget
->OnGestureEvent(&scroll_update
);
2419 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2420 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2421 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2422 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2423 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2424 EXPECT_TRUE(scroll_update
.handled());
2430 // ui::ET_GESTURE_SCROLL_END events should never be seen by any view when
2431 // there is no default gesture handler set, but they should be marked as
2432 // handled by OnEventProcessingStarted().
2433 GestureEventForTest
scroll_end(ui::ET_GESTURE_SCROLL_END
, 5, 5);
2434 widget
->OnGestureEvent(&scroll_end
);
2435 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2436 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2437 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2438 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2439 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2440 EXPECT_TRUE(scroll_end
.handled());
2446 // ui::ET_SCROLL_FLING_START events should never be seen by any view when
2447 // there is no default gesture handler set, but they should be marked as
2448 // handled by OnEventProcessingStarted().
2449 GestureEventForTest
scroll_fling_start(ui::ET_SCROLL_FLING_START
, 5, 5);
2450 widget
->OnGestureEvent(&scroll_fling_start
);
2451 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_SCROLL_FLING_START
));
2452 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_SCROLL_FLING_START
));
2453 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_SCROLL_FLING_START
));
2454 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_SCROLL_FLING_START
));
2455 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2456 EXPECT_TRUE(scroll_fling_start
.handled());
2465 // Tests that a (non-scroll) gesture event is dispatched to the correct views
2466 // in a view hierarchy and that the default gesture handler in RootView is set
2468 TEST_F(WidgetTest
, GestureEventDispatch
) {
2469 Widget
* widget
= CreateTopLevelNativeWidget();
2470 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
2472 // Define a hierarchy of four views (coordinates are in
2473 // their parent coordinate space).
2474 // v1 (0, 0, 300, 300)
2475 // v2 (0, 0, 100, 100)
2476 // v3 (0, 0, 50, 50)
2478 EventCountView
* v1
= new EventCountView();
2479 v1
->SetBounds(0, 0, 300, 300);
2480 EventCountView
* v2
= new EventCountView();
2481 v2
->SetBounds(0, 0, 100, 100);
2482 EventCountView
* v3
= new EventCountView();
2483 v3
->SetBounds(0, 0, 50, 50);
2484 EventCountView
* v4
= new EventCountView();
2485 v4
->SetBounds(0, 0, 10, 10);
2486 internal::RootView
* root_view
=
2487 static_cast<internal::RootView
*>(widget
->GetRootView());
2488 root_view
->AddChildView(v1
);
2489 v1
->AddChildView(v2
);
2490 v2
->AddChildView(v3
);
2491 v3
->AddChildView(v4
);
2495 // No gesture handler is set in the root view and none of the views in the
2496 // view hierarchy handle a ui::ET_GESTURE_TAP event. In this case the tap
2497 // event should be dispatched to all views in the hierarchy, the gesture
2498 // handler should remain unset, and the event should remain unhandled.
2499 GestureEventForTest
tap(ui::ET_GESTURE_TAP
, 5, 5);
2500 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2501 widget
->OnGestureEvent(&tap
);
2502 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2503 EXPECT_EQ(1, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2504 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2505 EXPECT_EQ(1, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2506 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2507 EXPECT_FALSE(tap
.handled());
2509 // No gesture handler is set in the root view and |v1|, |v2|, and |v3| all
2510 // handle a ui::ET_GESTURE_TAP event. In this case the tap event should be
2511 // dispatched to |v4| and |v3|, the gesture handler should be set to |v3|,
2512 // and the event should be marked as handled.
2517 v1
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2518 v2
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2519 v3
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2520 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2521 widget
->OnGestureEvent(&tap
);
2522 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2523 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2524 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2525 EXPECT_EQ(1, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2526 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2527 EXPECT_TRUE(tap
.handled());
2529 // The gesture handler is set to |v3| and all views handle all gesture event
2530 // types. In this case subsequent gesture events should only be dispatched to
2531 // |v3| and marked as handled. The gesture handler should remain as |v3|.
2536 v4
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2537 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2538 widget
->OnGestureEvent(&tap
);
2539 EXPECT_TRUE(tap
.handled());
2540 GestureEventForTest
show_press(ui::ET_GESTURE_SHOW_PRESS
, 5, 5);
2541 widget
->OnGestureEvent(&show_press
);
2542 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2543 widget
->OnGestureEvent(&tap
);
2544 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2545 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2546 EXPECT_EQ(2, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2547 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2548 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_SHOW_PRESS
));
2549 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_SHOW_PRESS
));
2550 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_SHOW_PRESS
));
2551 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_SHOW_PRESS
));
2552 EXPECT_TRUE(tap
.handled());
2553 EXPECT_TRUE(show_press
.handled());
2554 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2556 // The gesture handler is set to |v3|, but |v3| does not handle
2557 // ui::ET_GESTURE_TAP events. In this case a tap gesture should be dispatched
2558 // only to |v3|, but the event should remain unhandled. The gesture handler
2559 // should remain as |v3|.
2564 v3
->set_handle_mode(EventCountView::PROPAGATE_EVENTS
);
2565 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2566 widget
->OnGestureEvent(&tap
);
2567 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2568 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2569 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2570 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2571 EXPECT_FALSE(tap
.handled());
2572 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2577 // Tests that gesture scroll events will change the default gesture handler in
2578 // RootView if the current handler to which they are dispatched does not handle
2579 // gesture scroll events.
2580 TEST_F(WidgetTest
, ScrollGestureEventDispatch
) {
2581 Widget
* widget
= CreateTopLevelNativeWidget();
2582 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
2584 // Define a hierarchy of four views (coordinates are in
2585 // their parent coordinate space).
2586 // v1 (0, 0, 300, 300)
2587 // v2 (0, 0, 100, 100)
2588 // v3 (0, 0, 50, 50)
2590 EventCountView
* v1
= new EventCountView();
2591 v1
->SetBounds(0, 0, 300, 300);
2592 EventCountView
* v2
= new EventCountView();
2593 v2
->SetBounds(0, 0, 100, 100);
2594 EventCountView
* v3
= new EventCountView();
2595 v3
->SetBounds(0, 0, 50, 50);
2596 EventCountView
* v4
= new EventCountView();
2597 v4
->SetBounds(0, 0, 10, 10);
2598 internal::RootView
* root_view
=
2599 static_cast<internal::RootView
*>(widget
->GetRootView());
2600 root_view
->AddChildView(v1
);
2601 v1
->AddChildView(v2
);
2602 v2
->AddChildView(v3
);
2603 v3
->AddChildView(v4
);
2607 // Change the handle mode of |v3| to indicate that it would like to handle
2609 v3
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2611 // When no gesture handler is set, dispatching a ui::ET_GESTURE_TAP_DOWN
2612 // should bubble up the views hierarchy until it reaches the first view
2613 // that will handle it (|v3|) and then sets the handler to |v3|.
2614 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2615 GestureEventForTest
tap_down(ui::ET_GESTURE_TAP_DOWN
, 5, 5);
2616 widget
->OnGestureEvent(&tap_down
);
2617 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
2618 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
2619 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
2620 EXPECT_EQ(1, v4
->GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
2621 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2622 EXPECT_TRUE(tap_down
.handled());
2628 // A ui::ET_GESTURE_TAP_CANCEL event should be dispatched to |v3| directly.
2629 GestureEventForTest
tap_cancel(ui::ET_GESTURE_TAP_CANCEL
, 5, 5);
2630 widget
->OnGestureEvent(&tap_cancel
);
2631 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
2632 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
2633 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
2634 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
2635 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2636 EXPECT_TRUE(tap_cancel
.handled());
2642 // Change the handle mode of |v3| to indicate that it would no longer like
2643 // to handle events, and change the mode of |v1| to indicate that it would
2644 // like to handle events.
2645 v3
->set_handle_mode(EventCountView::PROPAGATE_EVENTS
);
2646 v1
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2648 // Dispatch a ui::ET_GESTURE_SCROLL_BEGIN event. Because the current gesture
2649 // handler (|v3|) does not handle scroll events, the event should bubble up
2650 // the views hierarchy until it reaches the first view that will handle
2651 // it (|v1|) and then sets the handler to |v1|.
2652 GestureEventForTest
scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN
, 5, 5);
2653 widget
->OnGestureEvent(&scroll_begin
);
2654 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
2655 EXPECT_EQ(1, v2
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
2656 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
2657 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
2658 EXPECT_EQ(v1
, GetGestureHandler(root_view
));
2659 EXPECT_TRUE(scroll_begin
.handled());
2665 // A ui::ET_GESTURE_SCROLL_UPDATE event should be dispatched to |v1|
2667 GestureEventForTest
scroll_update(ui::ET_GESTURE_SCROLL_UPDATE
, 5, 5);
2668 widget
->OnGestureEvent(&scroll_update
);
2669 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2670 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2671 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2672 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2673 EXPECT_EQ(v1
, GetGestureHandler(root_view
));
2674 EXPECT_TRUE(scroll_update
.handled());
2680 // A ui::ET_GESTURE_SCROLL_END event should be dispatched to |v1|
2681 // directly and should not reset the gesture handler.
2682 GestureEventForTest
scroll_end(ui::ET_GESTURE_SCROLL_END
, 5, 5);
2683 widget
->OnGestureEvent(&scroll_end
);
2684 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2685 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2686 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2687 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2688 EXPECT_EQ(v1
, GetGestureHandler(root_view
));
2689 EXPECT_TRUE(scroll_end
.handled());
2695 // A ui::ET_GESTURE_PINCH_BEGIN event (which is a non-scroll event) should
2696 // still be dispatched to |v1| directly.
2697 GestureEventForTest
pinch_begin(ui::ET_GESTURE_PINCH_BEGIN
, 5, 5);
2698 widget
->OnGestureEvent(&pinch_begin
);
2699 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN
));
2700 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN
));
2701 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN
));
2702 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN
));
2703 EXPECT_EQ(v1
, GetGestureHandler(root_view
));
2704 EXPECT_TRUE(pinch_begin
.handled());
2710 // A ui::ET_GESTURE_END event should be dispatched to |v1| and should
2711 // set the gesture handler to NULL.
2712 GestureEventForTest
end(ui::ET_GESTURE_END
, 5, 5);
2713 widget
->OnGestureEvent(&end
);
2714 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_END
));
2715 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_END
));
2716 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_END
));
2717 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_END
));
2718 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2719 EXPECT_TRUE(end
.handled());
2724 // A class used in WidgetTest.GestureEventLocationWhileBubbling to verify
2725 // that when a gesture event bubbles up a View hierarchy, the location
2726 // of a gesture event seen by each View is in the local coordinate space
2728 class GestureLocationView
: public EventCountView
{
2730 GestureLocationView() {}
2731 ~GestureLocationView() override
{}
2733 void set_expected_location(gfx::Point expected_location
) {
2734 expected_location_
= expected_location
;
2738 void OnGestureEvent(ui::GestureEvent
* event
) override
{
2739 EventCountView::OnGestureEvent(event
);
2741 // Verify that the location of |event| is in the local coordinate
2743 EXPECT_EQ(expected_location_
, event
->location());
2747 // The expected location of a gesture event dispatched to |this|.
2748 gfx::Point expected_location_
;
2750 DISALLOW_COPY_AND_ASSIGN(GestureLocationView
);
2753 // Verifies that the location of a gesture event is always in the local
2754 // coordinate space of the View receiving the event while bubbling.
2755 TEST_F(WidgetTest
, GestureEventLocationWhileBubbling
) {
2756 Widget
* widget
= CreateTopLevelNativeWidget();
2757 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
2759 // Define a hierarchy of three views (coordinates shown below are in the
2760 // coordinate space of the root view, but the coordinates used for
2761 // SetBounds() are in their parent coordinate space).
2762 // v1 (50, 50, 150, 150)
2763 // v2 (100, 70, 50, 80)
2764 // v3 (120, 100, 10, 10)
2765 GestureLocationView
* v1
= new GestureLocationView();
2766 v1
->SetBounds(50, 50, 150, 150);
2767 GestureLocationView
* v2
= new GestureLocationView();
2768 v2
->SetBounds(50, 20, 50, 80);
2769 GestureLocationView
* v3
= new GestureLocationView();
2770 v3
->SetBounds(20, 30, 10, 10);
2771 internal::RootView
* root_view
=
2772 static_cast<internal::RootView
*>(widget
->GetRootView());
2773 root_view
->AddChildView(v1
);
2774 v1
->AddChildView(v2
);
2775 v2
->AddChildView(v3
);
2779 // Define a GESTURE_TAP event located at (125, 105) in root view coordinates.
2780 // This event is contained within all of |v1|, |v2|, and |v3|.
2781 gfx::Point
location_in_root(125, 105);
2782 GestureEventForTest
tap(
2783 ui::ET_GESTURE_TAP
, location_in_root
.x(), location_in_root
.y());
2785 // Calculate the location of the event in the local coordinate spaces
2786 // of each of the views.
2787 gfx::Point
location_in_v1(ConvertPointFromWidgetToView(v1
, location_in_root
));
2788 EXPECT_EQ(gfx::Point(75, 55), location_in_v1
);
2789 gfx::Point
location_in_v2(ConvertPointFromWidgetToView(v2
, location_in_root
));
2790 EXPECT_EQ(gfx::Point(25, 35), location_in_v2
);
2791 gfx::Point
location_in_v3(ConvertPointFromWidgetToView(v3
, location_in_root
));
2792 EXPECT_EQ(gfx::Point(5, 5), location_in_v3
);
2794 // Dispatch the event. When each view receives the event, its location should
2795 // be in the local coordinate space of that view (see the check made by
2796 // GestureLocationView). After dispatch is complete the event's location
2797 // should be in the root coordinate space.
2798 v1
->set_expected_location(location_in_v1
);
2799 v2
->set_expected_location(location_in_v2
);
2800 v3
->set_expected_location(location_in_v3
);
2801 widget
->OnGestureEvent(&tap
);
2802 EXPECT_EQ(location_in_root
, tap
.location());
2804 // Verify that each view did in fact see the event.
2805 EventCountView
* view1
= v1
;
2806 EventCountView
* view2
= v2
;
2807 EventCountView
* view3
= v3
;
2808 EXPECT_EQ(1, view1
->GetEventCount(ui::ET_GESTURE_TAP
));
2809 EXPECT_EQ(1, view2
->GetEventCount(ui::ET_GESTURE_TAP
));
2810 EXPECT_EQ(1, view3
->GetEventCount(ui::ET_GESTURE_TAP
));
2815 // Verifies that disabled views are permitted to be set as the default gesture
2816 // handler in RootView. Also verifies that gesture events targeted to a disabled
2817 // view are not actually dispatched to the view, but are still marked as
2819 TEST_F(WidgetTest
, DisabledGestureEventTarget
) {
2820 Widget
* widget
= CreateTopLevelNativeWidget();
2821 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
2823 // Define a hierarchy of four views (coordinates are in
2824 // their parent coordinate space).
2825 // v1 (0, 0, 300, 300)
2826 // v2 (0, 0, 100, 100)
2827 // v3 (0, 0, 50, 50)
2829 EventCountView
* v1
= new EventCountView();
2830 v1
->SetBounds(0, 0, 300, 300);
2831 EventCountView
* v2
= new EventCountView();
2832 v2
->SetBounds(0, 0, 100, 100);
2833 EventCountView
* v3
= new EventCountView();
2834 v3
->SetBounds(0, 0, 50, 50);
2835 EventCountView
* v4
= new EventCountView();
2836 v4
->SetBounds(0, 0, 10, 10);
2837 internal::RootView
* root_view
=
2838 static_cast<internal::RootView
*>(widget
->GetRootView());
2839 root_view
->AddChildView(v1
);
2840 v1
->AddChildView(v2
);
2841 v2
->AddChildView(v3
);
2842 v3
->AddChildView(v4
);
2846 // |v1|, |v2|, and |v3| all handle gesture events but |v3| is marked as
2848 v1
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2849 v2
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2850 v3
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2851 v3
->SetEnabled(false);
2853 // No gesture handler is set in the root view. In this case the tap event
2854 // should be dispatched only to |v4|, the gesture handler should be set to
2855 // |v3|, and the event should be marked as handled.
2856 GestureEventForTest
tap(ui::ET_GESTURE_TAP
, 5, 5);
2857 widget
->OnGestureEvent(&tap
);
2858 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2859 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2860 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2861 EXPECT_EQ(1, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2862 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2863 EXPECT_TRUE(tap
.handled());
2869 // A subsequent gesture event should be marked as handled but not dispatched.
2870 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2871 widget
->OnGestureEvent(&tap
);
2872 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2873 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2874 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2875 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2876 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2877 EXPECT_TRUE(tap
.handled());
2883 // A GESTURE_END should reset the default gesture handler to NULL. It should
2884 // also not be dispatched to |v3| but still marked as handled.
2885 GestureEventForTest
end(ui::ET_GESTURE_END
, 5, 5);
2886 widget
->OnGestureEvent(&end
);
2887 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_END
));
2888 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_END
));
2889 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_END
));
2890 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_END
));
2891 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2892 EXPECT_TRUE(end
.handled());
2898 // Change the handle mode of |v3| to indicate that it would no longer like
2899 // to handle events which are dispatched to it.
2900 v3
->set_handle_mode(EventCountView::PROPAGATE_EVENTS
);
2902 // No gesture handler is set in the root view. In this case the tap event
2903 // should be dispatched only to |v4| and the event should be marked as
2904 // handled. Furthermore, the gesture handler should be set to
2905 // |v3|; even though |v3| does not explicitly handle events, it is a
2906 // valid target for the tap event because it is disabled.
2907 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2908 widget
->OnGestureEvent(&tap
);
2909 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2910 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2911 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2912 EXPECT_EQ(1, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2913 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2914 EXPECT_TRUE(tap
.handled());
2920 // A GESTURE_END should reset the default gesture handler to NULL. It should
2921 // also not be dispatched to |v3| but still marked as handled.
2922 end
= GestureEventForTest(ui::ET_GESTURE_END
, 5, 5);
2923 widget
->OnGestureEvent(&end
);
2924 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_END
));
2925 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_END
));
2926 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_END
));
2927 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_END
));
2928 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2929 EXPECT_TRUE(end
.handled());
2934 // Test the result of Widget::GetAllChildWidgets().
2935 TEST_F(WidgetTest
, GetAllChildWidgets
) {
2936 // Create the following widget hierarchy:
2944 Widget
* toplevel
= CreateTopLevelPlatformWidget();
2945 Widget
* w1
= CreateChildPlatformWidget(toplevel
->GetNativeView());
2946 Widget
* w11
= CreateChildPlatformWidget(w1
->GetNativeView());
2947 Widget
* w2
= CreateChildPlatformWidget(toplevel
->GetNativeView());
2948 Widget
* w21
= CreateChildPlatformWidget(w2
->GetNativeView());
2949 Widget
* w22
= CreateChildPlatformWidget(w2
->GetNativeView());
2951 std::set
<Widget
*> expected
;
2952 expected
.insert(toplevel
);
2953 expected
.insert(w1
);
2954 expected
.insert(w11
);
2955 expected
.insert(w2
);
2956 expected
.insert(w21
);
2957 expected
.insert(w22
);
2959 std::set
<Widget
*> widgets
;
2960 Widget::GetAllChildWidgets(toplevel
->GetNativeView(), &widgets
);
2962 EXPECT_EQ(expected
.size(), widgets
.size());
2963 EXPECT_TRUE(std::equal(expected
.begin(), expected
.end(), widgets
.begin()));
2964 toplevel
->CloseNow();
2967 // Used by DestroyChildWidgetsInOrder. On destruction adds the supplied name to
2969 class DestroyedTrackingView
: public View
{
2971 DestroyedTrackingView(const std::string
& name
,
2972 std::vector
<std::string
>* add_to
)
2977 ~DestroyedTrackingView() override
{ add_to_
->push_back(name_
); }
2980 const std::string name_
;
2981 std::vector
<std::string
>* add_to_
;
2983 DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingView
);
2986 class WidgetChildDestructionTest
: public WidgetTest
{
2988 WidgetChildDestructionTest() {}
2990 // Creates a top level and a child, destroys the child and verifies the views
2991 // of the child are destroyed before the views of the parent.
2992 void RunDestroyChildWidgetsTest(bool top_level_has_desktop_native_widget_aura
,
2993 bool child_has_desktop_native_widget_aura
) {
2994 // When a View is destroyed its name is added here.
2995 std::vector
<std::string
> destroyed
;
2997 Widget
* top_level
= new Widget
;
2998 Widget::InitParams params
=
2999 CreateParams(views::Widget::InitParams::TYPE_WINDOW
);
3000 #if !defined(OS_CHROMEOS)
3001 if (top_level_has_desktop_native_widget_aura
)
3002 params
.native_widget
= new PlatformDesktopNativeWidget(top_level
);
3004 top_level
->Init(params
);
3005 top_level
->GetRootView()->AddChildView(
3006 new DestroyedTrackingView("parent", &destroyed
));
3009 Widget
* child
= new Widget
;
3010 Widget::InitParams child_params
=
3011 CreateParams(views::Widget::InitParams::TYPE_POPUP
);
3012 child_params
.parent
= top_level
->GetNativeView();
3013 #if !defined(OS_CHROMEOS)
3014 if (child_has_desktop_native_widget_aura
)
3015 child_params
.native_widget
= new PlatformDesktopNativeWidget(child
);
3017 child
->Init(child_params
);
3018 child
->GetRootView()->AddChildView(
3019 new DestroyedTrackingView("child", &destroyed
));
3022 // Should trigger destruction of the child too.
3023 top_level
->native_widget_private()->CloseNow();
3025 // Child should be destroyed first.
3026 ASSERT_EQ(2u, destroyed
.size());
3027 EXPECT_EQ("child", destroyed
[0]);
3028 EXPECT_EQ("parent", destroyed
[1]);
3032 DISALLOW_COPY_AND_ASSIGN(WidgetChildDestructionTest
);
3035 #if !defined(OS_CHROMEOS)
3036 // See description of RunDestroyChildWidgetsTest(). Parent uses
3037 // DesktopNativeWidgetAura.
3038 TEST_F(WidgetChildDestructionTest
,
3039 DestroyChildWidgetsInOrderWithDesktopNativeWidget
) {
3040 RunDestroyChildWidgetsTest(true, false);
3043 // See description of RunDestroyChildWidgetsTest(). Both parent and child use
3044 // DesktopNativeWidgetAura.
3045 TEST_F(WidgetChildDestructionTest
,
3046 DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth
) {
3047 RunDestroyChildWidgetsTest(true, true);
3049 #endif // !defined(OS_CHROMEOS)
3051 // See description of RunDestroyChildWidgetsTest().
3052 TEST_F(WidgetChildDestructionTest
, DestroyChildWidgetsInOrder
) {
3053 RunDestroyChildWidgetsTest(false, false);
3056 #if !defined(OS_CHROMEOS)
3057 // Provides functionality to create a window modal dialog.
3058 class ModalDialogDelegate
: public DialogDelegateView
{
3060 ModalDialogDelegate() {}
3061 ~ModalDialogDelegate() override
{}
3063 // WidgetDelegate overrides.
3064 ui::ModalType
GetModalType() const override
{ return ui::MODAL_TYPE_WINDOW
; }
3067 DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate
);
3070 // This test verifies that whether mouse events when a modal dialog is
3071 // displayed are eaten or recieved by the dialog.
3072 TEST_F(WidgetTest
, WindowMouseModalityTest
) {
3073 // Create a top level widget.
3074 Widget top_level_widget
;
3075 Widget::InitParams init_params
=
3076 CreateParams(Widget::InitParams::TYPE_WINDOW
);
3077 init_params
.show_state
= ui::SHOW_STATE_NORMAL
;
3078 gfx::Rect
initial_bounds(0, 0, 500, 500);
3079 init_params
.bounds
= initial_bounds
;
3080 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
3081 init_params
.native_widget
=
3082 new PlatformDesktopNativeWidget(&top_level_widget
);
3083 top_level_widget
.Init(init_params
);
3084 top_level_widget
.Show();
3085 EXPECT_TRUE(top_level_widget
.IsVisible());
3087 // Create a view and validate that a mouse moves makes it to the view.
3088 EventCountView
* widget_view
= new EventCountView();
3089 widget_view
->SetBounds(0, 0, 10, 10);
3090 top_level_widget
.GetRootView()->AddChildView(widget_view
);
3092 gfx::Point
cursor_location_main(5, 5);
3093 ui::MouseEvent
move_main(ui::ET_MOUSE_MOVED
, cursor_location_main
,
3094 cursor_location_main
, ui::EventTimeForNow(),
3095 ui::EF_NONE
, ui::EF_NONE
);
3096 ui::EventDispatchDetails details
=
3097 GetEventProcessor(&top_level_widget
)->OnEventFromSource(&move_main
);
3098 ASSERT_FALSE(details
.dispatcher_destroyed
);
3100 EXPECT_EQ(1, widget_view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
3101 widget_view
->ResetCounts();
3103 // Create a modal dialog and validate that a mouse down message makes it to
3104 // the main view within the dialog.
3106 // This instance will be destroyed when the dialog is destroyed.
3107 ModalDialogDelegate
* dialog_delegate
= new ModalDialogDelegate
;
3109 Widget
* modal_dialog_widget
= views::DialogDelegate::CreateDialogWidget(
3110 dialog_delegate
, NULL
, top_level_widget
.GetNativeView());
3111 modal_dialog_widget
->SetBounds(gfx::Rect(100, 100, 200, 200));
3112 EventCountView
* dialog_widget_view
= new EventCountView();
3113 dialog_widget_view
->SetBounds(0, 0, 50, 50);
3114 modal_dialog_widget
->GetRootView()->AddChildView(dialog_widget_view
);
3115 modal_dialog_widget
->Show();
3116 EXPECT_TRUE(modal_dialog_widget
->IsVisible());
3118 gfx::Point
cursor_location_dialog(100, 100);
3119 ui::MouseEvent
mouse_down_dialog(
3120 ui::ET_MOUSE_PRESSED
, cursor_location_dialog
, cursor_location_dialog
,
3121 ui::EventTimeForNow(), ui::EF_NONE
, ui::EF_NONE
);
3122 details
= GetEventProcessor(&top_level_widget
)->OnEventFromSource(
3123 &mouse_down_dialog
);
3124 ASSERT_FALSE(details
.dispatcher_destroyed
);
3125 EXPECT_EQ(1, dialog_widget_view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
3127 // Send a mouse move message to the main window. It should not be received by
3128 // the main window as the modal dialog is still active.
3129 gfx::Point
cursor_location_main2(6, 6);
3130 ui::MouseEvent
mouse_down_main(ui::ET_MOUSE_MOVED
, cursor_location_main2
,
3131 cursor_location_main2
, ui::EventTimeForNow(),
3132 ui::EF_NONE
, ui::EF_NONE
);
3133 details
= GetEventProcessor(&top_level_widget
)->OnEventFromSource(
3135 ASSERT_FALSE(details
.dispatcher_destroyed
);
3136 EXPECT_EQ(0, widget_view
->GetEventCount(ui::ET_MOUSE_MOVED
));
3138 modal_dialog_widget
->CloseNow();
3139 top_level_widget
.CloseNow();
3142 // Verifies nativeview visbility matches that of Widget visibility when
3143 // SetFullscreen is invoked.
3144 TEST_F(WidgetTest
, FullscreenStatePropagated
) {
3145 Widget::InitParams init_params
=
3146 CreateParams(Widget::InitParams::TYPE_WINDOW
);
3147 init_params
.show_state
= ui::SHOW_STATE_NORMAL
;
3148 init_params
.bounds
= gfx::Rect(0, 0, 500, 500);
3149 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
3152 Widget top_level_widget
;
3153 top_level_widget
.Init(init_params
);
3154 top_level_widget
.SetFullscreen(true);
3155 EXPECT_EQ(top_level_widget
.IsVisible(),
3156 IsNativeWindowVisible(top_level_widget
.GetNativeWindow()));
3157 top_level_widget
.CloseNow();
3159 #if !defined(OS_CHROMEOS)
3161 Widget top_level_widget
;
3162 init_params
.native_widget
=
3163 new PlatformDesktopNativeWidget(&top_level_widget
);
3164 top_level_widget
.Init(init_params
);
3165 top_level_widget
.SetFullscreen(true);
3166 EXPECT_EQ(top_level_widget
.IsVisible(),
3167 IsNativeWindowVisible(top_level_widget
.GetNativeWindow()));
3168 top_level_widget
.CloseNow();
3174 // Tests whether we can activate the top level widget when a modal dialog is
3176 TEST_F(WidgetTest
, WindowModalityActivationTest
) {
3177 TestDesktopWidgetDelegate widget_delegate
;
3178 widget_delegate
.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW
));
3180 Widget
* top_level_widget
= widget_delegate
.GetWidget();
3181 top_level_widget
->Show();
3182 EXPECT_TRUE(top_level_widget
->IsVisible());
3184 HWND win32_window
= views::HWNDForWidget(top_level_widget
);
3185 EXPECT_TRUE(::IsWindow(win32_window
));
3187 // This instance will be destroyed when the dialog is destroyed.
3188 ModalDialogDelegate
* dialog_delegate
= new ModalDialogDelegate
;
3190 // We should be able to activate the window even if the WidgetDelegate
3191 // says no, when a modal dialog is active.
3192 widget_delegate
.set_can_activate(false);
3194 Widget
* modal_dialog_widget
= views::DialogDelegate::CreateDialogWidget(
3195 dialog_delegate
, NULL
, top_level_widget
->GetNativeView());
3196 modal_dialog_widget
->SetBounds(gfx::Rect(100, 100, 200, 200));
3197 modal_dialog_widget
->Show();
3198 EXPECT_TRUE(modal_dialog_widget
->IsVisible());
3200 LRESULT activate_result
= ::SendMessage(
3203 reinterpret_cast<WPARAM
>(win32_window
),
3204 MAKELPARAM(WM_LBUTTONDOWN
, HTCLIENT
));
3205 EXPECT_EQ(activate_result
, MA_ACTIVATE
);
3207 modal_dialog_widget
->CloseNow();
3209 #endif // defined(OS_WIN)
3210 #endif // !defined(OS_CHROMEOS)
3214 class FullscreenAwareFrame
: public views::NonClientFrameView
{
3216 explicit FullscreenAwareFrame(views::Widget
* widget
)
3217 : widget_(widget
), fullscreen_layout_called_(false) {}
3218 ~FullscreenAwareFrame() override
{}
3220 // views::NonClientFrameView overrides:
3221 gfx::Rect
GetBoundsForClientView() const override
{ return gfx::Rect(); }
3222 gfx::Rect
GetWindowBoundsForClientBounds(
3223 const gfx::Rect
& client_bounds
) const override
{
3226 int NonClientHitTest(const gfx::Point
& point
) override
{ return HTNOWHERE
; }
3227 void GetWindowMask(const gfx::Size
& size
, gfx::Path
* window_mask
) override
{}
3228 void ResetWindowControls() override
{}
3229 void UpdateWindowIcon() override
{}
3230 void UpdateWindowTitle() override
{}
3231 void SizeConstraintsChanged() override
{}
3233 // views::View overrides:
3234 void Layout() override
{
3235 if (widget_
->IsFullscreen())
3236 fullscreen_layout_called_
= true;
3239 bool fullscreen_layout_called() const { return fullscreen_layout_called_
; }
3242 views::Widget
* widget_
;
3243 bool fullscreen_layout_called_
;
3245 DISALLOW_COPY_AND_ASSIGN(FullscreenAwareFrame
);
3250 // Tests that frame Layout is called when a widget goes fullscreen without
3251 // changing its size or title.
3252 TEST_F(WidgetTest
, FullscreenFrameLayout
) {
3253 Widget
* widget
= CreateTopLevelPlatformWidget();
3254 FullscreenAwareFrame
* frame
= new FullscreenAwareFrame(widget
);
3255 widget
->non_client_view()->SetFrameView(frame
); // Owns |frame|.
3258 RunPendingMessages();
3260 EXPECT_FALSE(frame
->fullscreen_layout_called());
3261 widget
->SetFullscreen(true);
3263 RunPendingMessages();
3265 if (IsTestingSnowLeopard()) {
3266 // Fullscreen is currently ignored on Snow Leopard.
3267 EXPECT_FALSE(frame
->fullscreen_layout_called());
3269 EXPECT_TRUE(frame
->fullscreen_layout_called());
3275 #if !defined(OS_CHROMEOS)
3278 // Trivial WidgetObserverTest that invokes Widget::IsActive() from
3279 // OnWindowDestroying.
3280 class IsActiveFromDestroyObserver
: public WidgetObserver
{
3282 IsActiveFromDestroyObserver() {}
3283 ~IsActiveFromDestroyObserver() override
{}
3284 void OnWidgetDestroying(Widget
* widget
) override
{ widget
->IsActive(); }
3287 DISALLOW_COPY_AND_ASSIGN(IsActiveFromDestroyObserver
);
3292 // Verifies Widget::IsActive() invoked from
3293 // WidgetObserver::OnWidgetDestroying() in a child widget doesn't crash.
3294 TEST_F(WidgetTest
, IsActiveFromDestroy
) {
3295 // Create two widgets, one a child of the other.
3296 IsActiveFromDestroyObserver observer
;
3297 Widget parent_widget
;
3298 Widget::InitParams parent_params
=
3299 CreateParams(Widget::InitParams::TYPE_POPUP
);
3300 parent_params
.native_widget
= new PlatformDesktopNativeWidget(&parent_widget
);
3301 parent_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
3302 parent_widget
.Init(parent_params
);
3303 parent_widget
.Show();
3305 Widget child_widget
;
3306 Widget::InitParams child_params
=
3307 CreateParams(Widget::InitParams::TYPE_POPUP
);
3308 child_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
3309 child_params
.context
= parent_widget
.GetNativeWindow();
3310 child_widget
.Init(child_params
);
3311 child_widget
.AddObserver(&observer
);
3312 child_widget
.Show();
3314 parent_widget
.CloseNow();
3316 #endif // !defined(OS_CHROMEOS)
3318 // Tests that events propagate through from the dispatcher with the correct
3319 // event type, and that the different platforms behave the same.
3320 TEST_F(WidgetTest
, MouseEventTypesViaGenerator
) {
3321 EventCountView
* view
= new EventCountView
;
3322 view
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
3323 view
->SetBounds(10, 10, 50, 40);
3325 Widget
* widget
= CreateTopLevelFramelessPlatformWidget();
3326 widget
->GetRootView()->AddChildView(view
);
3328 widget
->SetBounds(gfx::Rect(0, 0, 100, 80));
3331 ui::test::EventGenerator
generator(GetContext(), widget
->GetNativeWindow());
3332 generator
.set_current_location(gfx::Point(20, 20));
3334 generator
.ClickLeftButton();
3335 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
3336 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_RELEASED
));
3337 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON
, view
->last_flags());
3339 generator
.PressRightButton();
3340 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
3341 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_RELEASED
));
3342 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON
, view
->last_flags());
3344 generator
.ReleaseRightButton();
3345 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
3346 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_RELEASED
));
3347 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON
, view
->last_flags());
3349 // Test mouse move events.
3350 EXPECT_EQ(0, view
->GetEventCount(ui::ET_MOUSE_MOVED
));
3351 EXPECT_EQ(0, view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
3353 // Move the mouse within the view (20, 20) -> (30, 30).
3354 generator
.MoveMouseTo(gfx::Point(30, 30));
3355 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_MOVED
));
3356 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
3357 EXPECT_EQ(ui::EF_NONE
, view
->last_flags());
3359 // Move it again - entered count shouldn't change.
3360 generator
.MoveMouseTo(gfx::Point(31, 31));
3361 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_MOVED
));
3362 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
3363 EXPECT_EQ(0, view
->GetEventCount(ui::ET_MOUSE_EXITED
));
3365 // Move it off the view.
3366 generator
.MoveMouseTo(gfx::Point(5, 5));
3367 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_MOVED
));
3368 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
3369 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_EXITED
));
3372 generator
.MoveMouseTo(gfx::Point(20, 20));
3373 EXPECT_EQ(3, view
->GetEventCount(ui::ET_MOUSE_MOVED
));
3374 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
3375 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_EXITED
));
3377 // Drargging. Cover HasCapture() and NativeWidgetPrivate::IsMouseButtonDown().
3378 generator
.DragMouseTo(gfx::Point(40, 40));
3379 EXPECT_EQ(3, view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
3380 EXPECT_EQ(3, view
->GetEventCount(ui::ET_MOUSE_RELEASED
));
3381 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_DRAGGED
));
3382 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON
, view
->last_flags());
3387 // Tests that the root view is correctly set up for Widget types that do not
3388 // require a non-client view, before any other views are added to the widget.
3389 // That is, before Widget::ReorderNativeViews() is called which, if called with
3390 // a root view not set, could cause the root view to get resized to the widget.
3391 TEST_F(WidgetTest
, NonClientWindowValidAfterInit
) {
3392 Widget
* widget
= CreateTopLevelFramelessPlatformWidget();
3393 View
* root_view
= widget
->GetRootView();
3395 // Size the root view to exceed the widget bounds.
3396 const gfx::Rect
test_rect(0, 0, 500, 500);
3397 root_view
->SetBoundsRect(test_rect
);
3399 EXPECT_NE(test_rect
.size(), widget
->GetWindowBoundsInScreen().size());
3401 EXPECT_EQ(test_rect
, root_view
->bounds());
3402 widget
->ReorderNativeViews();
3403 EXPECT_EQ(test_rect
, root_view
->bounds());
3409 // This test validates that sending WM_CHAR/WM_SYSCHAR/WM_SYSDEADCHAR
3410 // messages via the WindowEventTarget interface implemented by the
3411 // HWNDMessageHandler class does not cause a crash due to an unprocessed
3413 TEST_F(WidgetTest
, CharMessagesAsKeyboardMessagesDoesNotCrash
) {
3415 Widget::InitParams params
=
3416 CreateParams(Widget::InitParams::TYPE_WINDOW
);
3417 params
.native_widget
= new PlatformDesktopNativeWidget(&widget
);
3418 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
3419 widget
.Init(params
);
3422 ui::WindowEventTarget
* target
=
3423 reinterpret_cast<ui::WindowEventTarget
*>(ui::ViewProp::GetValue(
3424 widget
.GetNativeWindow()->GetHost()->GetAcceleratedWidget(),
3425 ui::WindowEventTarget::kWin32InputEventTarget
));
3426 EXPECT_NE(nullptr, target
);
3427 bool handled
= false;
3428 target
->HandleKeyboardMessage(WM_CHAR
, 0, 0, &handled
);
3429 target
->HandleKeyboardMessage(WM_SYSCHAR
, 0, 0, &handled
);
3430 target
->HandleKeyboardMessage(WM_SYSDEADCHAR
, 0, 0, &handled
);
3435 // Test that SetAlwaysOnTop and IsAlwaysOnTop are consistent.
3436 TEST_F(WidgetTest
, AlwaysOnTop
) {
3437 Widget
* widget
= CreateTopLevelNativeWidget();
3438 EXPECT_FALSE(widget
->IsAlwaysOnTop());
3439 widget
->SetAlwaysOnTop(true);
3440 EXPECT_TRUE(widget
->IsAlwaysOnTop());
3441 widget
->SetAlwaysOnTop(false);
3442 EXPECT_FALSE(widget
->IsAlwaysOnTop());
3447 } // namespace views