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_views_delegate.h"
27 #include "ui/views/test/test_widget_observer.h"
28 #include "ui/views/test/widget_test.h"
29 #include "ui/views/views_delegate.h"
30 #include "ui/views/widget/native_widget_delegate.h"
31 #include "ui/views/widget/root_view.h"
32 #include "ui/views/widget/widget_deletion_observer.h"
33 #include "ui/views/window/dialog_delegate.h"
34 #include "ui/views/window/native_frame_view.h"
37 #include "ui/aura/window.h"
38 #include "ui/aura/window_tree_host.h"
39 #include "ui/base/view_prop.h"
40 #include "ui/base/win/window_event_target.h"
41 #include "ui/views/win/hwnd_util.h"
44 #if defined(OS_MACOSX)
45 #include "base/mac/mac_util.h"
53 // TODO(tdanderson): This utility function is used in different unittest
54 // files. Move to a common location to avoid
56 gfx::Point
ConvertPointFromWidgetToView(View
* view
, const gfx::Point
& p
) {
58 View::ConvertPointToTarget(view
->GetWidget()->GetRootView(), view
, &tmp
);
62 // Helper function for Snow Leopard special cases to avoid #ifdef litter.
63 bool IsTestingSnowLeopard() {
64 #if defined(OS_MACOSX)
65 return base::mac::IsOSSnowLeopard();
73 // A view that keeps track of the events it receives, optionally consuming them.
74 class EventCountView
: public View
{
76 // Whether to call SetHandled() on events as they are received. For some event
77 // types, this will allow EventCountView to receives future events in the
78 // event sequence, such as a drag.
86 handle_mode_(PROPAGATE_EVENTS
) {}
88 ~EventCountView() override
{}
90 int GetEventCount(ui::EventType type
) {
91 return event_count_
[type
];
98 int last_flags() const {
102 void set_handle_mode(HandleMode handle_mode
) {
103 handle_mode_
= handle_mode
;
107 // Overridden from View:
108 void OnMouseMoved(const ui::MouseEvent
& event
) override
{
109 // MouseMove events are not re-dispatched from the RootView.
110 ++event_count_
[ui::ET_MOUSE_MOVED
];
114 // Overridden from ui::EventHandler:
115 void OnKeyEvent(ui::KeyEvent
* event
) override
{ RecordEvent(event
); }
116 void OnMouseEvent(ui::MouseEvent
* event
) override
{ RecordEvent(event
); }
117 void OnScrollEvent(ui::ScrollEvent
* event
) override
{ RecordEvent(event
); }
118 void OnGestureEvent(ui::GestureEvent
* event
) override
{ RecordEvent(event
); }
121 void RecordEvent(ui::Event
* event
) {
122 ++event_count_
[event
->type()];
123 last_flags_
= event
->flags();
124 if (handle_mode_
== CONSUME_EVENTS
)
128 std::map
<ui::EventType
, int> event_count_
;
130 HandleMode handle_mode_
;
132 DISALLOW_COPY_AND_ASSIGN(EventCountView
);
135 // A view that keeps track of the events it receives, and consumes all scroll
136 // gesture events and ui::ET_SCROLL events.
137 class ScrollableEventCountView
: public EventCountView
{
139 ScrollableEventCountView() {}
140 ~ScrollableEventCountView() override
{}
143 // Overridden from ui::EventHandler:
144 void OnGestureEvent(ui::GestureEvent
* event
) override
{
145 EventCountView::OnGestureEvent(event
);
146 switch (event
->type()) {
147 case ui::ET_GESTURE_SCROLL_BEGIN
:
148 case ui::ET_GESTURE_SCROLL_UPDATE
:
149 case ui::ET_GESTURE_SCROLL_END
:
150 case ui::ET_SCROLL_FLING_START
:
158 void OnScrollEvent(ui::ScrollEvent
* event
) override
{
159 EventCountView::OnScrollEvent(event
);
160 if (event
->type() == ui::ET_SCROLL
)
164 DISALLOW_COPY_AND_ASSIGN(ScrollableEventCountView
);
167 // A view that implements GetMinimumSize.
168 class MinimumSizeFrameView
: public NativeFrameView
{
170 explicit MinimumSizeFrameView(Widget
* frame
): NativeFrameView(frame
) {}
171 ~MinimumSizeFrameView() override
{}
174 // Overridden from View:
175 gfx::Size
GetMinimumSize() const override
{ return gfx::Size(300, 400); }
177 DISALLOW_COPY_AND_ASSIGN(MinimumSizeFrameView
);
180 // An event handler that simply keeps a count of the different types of events
182 class EventCountHandler
: public ui::EventHandler
{
184 EventCountHandler() {}
185 ~EventCountHandler() override
{}
187 int GetEventCount(ui::EventType type
) {
188 return event_count_
[type
];
192 event_count_
.clear();
196 // Overridden from ui::EventHandler:
197 void OnEvent(ui::Event
* event
) override
{
199 ui::EventHandler::OnEvent(event
);
203 void RecordEvent(const ui::Event
& event
) {
204 ++event_count_
[event
.type()];
207 std::map
<ui::EventType
, int> event_count_
;
209 DISALLOW_COPY_AND_ASSIGN(EventCountHandler
);
212 // A helper WidgetDelegate for tests that require hooks into WidgetDelegate
213 // calls, and removes some of the boilerplate for initializing a Widget. Calls
214 // Widget::CloseNow() when destroyed if it hasn't already been done.
215 class TestDesktopWidgetDelegate
: public WidgetDelegate
{
217 TestDesktopWidgetDelegate() : widget_(new Widget
) {}
219 ~TestDesktopWidgetDelegate() override
{
222 EXPECT_FALSE(widget_
);
225 // Initialize the Widget, adding some meaningful default InitParams.
226 void InitWidget(Widget::InitParams init_params
) {
227 init_params
.delegate
= this;
228 #if !defined(OS_CHROMEOS)
229 init_params
.native_widget
= new PlatformDesktopNativeWidget(widget_
);
231 init_params
.bounds
= initial_bounds_
;
232 widget_
->Init(init_params
);
235 // Set the contents view to be used during Widget initialization. For Widgets
236 // that use non-client views, this will be the contents_view used to
237 // initialize the ClientView in WidgetDelegate::CreateClientView(). Otherwise,
238 // it is the ContentsView of the Widget's RootView. Ownership passes to the
239 // view hierarchy during InitWidget().
240 void set_contents_view(View
* contents_view
) {
241 contents_view_
= contents_view
;
244 int window_closing_count() const { return window_closing_count_
; }
245 const gfx::Rect
& initial_bounds() { return initial_bounds_
; }
247 // WidgetDelegate overrides:
248 void WindowClosing() override
{
249 window_closing_count_
++;
253 Widget
* GetWidget() override
{ return widget_
; }
254 const Widget
* GetWidget() const override
{ return widget_
; }
256 View
* GetContentsView() override
{
257 return contents_view_
? contents_view_
: WidgetDelegate::GetContentsView();
260 bool ShouldAdvanceFocusToTopLevelWidget() const override
{
261 return true; // Same default as DefaultWidgetDelegate in widget.cc.
266 View
* contents_view_
= nullptr;
267 int window_closing_count_
= 0;
268 gfx::Rect initial_bounds_
= gfx::Rect(100, 100, 200, 200);
270 DISALLOW_COPY_AND_ASSIGN(TestDesktopWidgetDelegate
);
273 TEST_F(WidgetTest
, WidgetInitParams
) {
274 // Widgets are not transparent by default.
275 Widget::InitParams init1
;
276 EXPECT_EQ(Widget::InitParams::INFER_OPACITY
, init1
.opacity
);
279 TEST_F(WidgetTest
, NativeWindowProperty
) {
280 const char* key
= "foo";
283 Widget
* widget
= CreateTopLevelPlatformWidget();
284 EXPECT_EQ(nullptr, widget
->GetNativeWindowProperty(key
));
286 widget
->SetNativeWindowProperty(key
, &value
);
287 EXPECT_EQ(&value
, widget
->GetNativeWindowProperty(key
));
289 widget
->SetNativeWindowProperty(key
, nullptr);
290 EXPECT_EQ(nullptr, widget
->GetNativeWindowProperty(key
));
295 ////////////////////////////////////////////////////////////////////////////////
296 // Widget::GetTopLevelWidget tests.
298 TEST_F(WidgetTest
, GetTopLevelWidget_Native
) {
299 // Create a hierarchy of native widgets.
300 Widget
* toplevel
= CreateTopLevelPlatformWidget();
301 gfx::NativeView parent
= toplevel
->GetNativeView();
302 Widget
* child
= CreateChildPlatformWidget(parent
);
304 EXPECT_EQ(toplevel
, toplevel
->GetTopLevelWidget());
305 EXPECT_EQ(toplevel
, child
->GetTopLevelWidget());
307 toplevel
->CloseNow();
308 // |child| should be automatically destroyed with |toplevel|.
311 // Test if a focus manager and an inputmethod work without CHECK failure
312 // when window activation changes.
313 TEST_F(WidgetTest
, ChangeActivation
) {
314 Widget
* top1
= CreateTopLevelPlatformWidget();
315 // CreateInputMethod before activated
316 top1
->GetInputMethod();
318 RunPendingMessages();
320 Widget
* top2
= CreateTopLevelPlatformWidget();
322 RunPendingMessages();
325 RunPendingMessages();
327 // Create InputMethod after deactivated.
328 top2
->GetInputMethod();
330 RunPendingMessages();
333 RunPendingMessages();
339 // Tests visibility of child widgets.
340 TEST_F(WidgetTest
, Visibility
) {
341 Widget
* toplevel
= CreateTopLevelPlatformWidget();
342 gfx::NativeView parent
= toplevel
->GetNativeView();
343 Widget
* child
= CreateChildPlatformWidget(parent
);
345 EXPECT_FALSE(toplevel
->IsVisible());
346 EXPECT_FALSE(child
->IsVisible());
348 // Showing a child with a hidden parent keeps the child hidden.
350 EXPECT_FALSE(toplevel
->IsVisible());
351 EXPECT_FALSE(child
->IsVisible());
353 // Showing a hidden parent with a visible child shows both.
355 EXPECT_TRUE(toplevel
->IsVisible());
356 EXPECT_TRUE(child
->IsVisible());
358 // Hiding a parent hides both parent and child.
360 EXPECT_FALSE(toplevel
->IsVisible());
361 EXPECT_FALSE(child
->IsVisible());
363 // Hiding a child while the parent is hidden keeps the child hidden when the
367 EXPECT_TRUE(toplevel
->IsVisible());
368 EXPECT_FALSE(child
->IsVisible());
370 toplevel
->CloseNow();
371 // |child| should be automatically destroyed with |toplevel|.
374 // Test that child widgets are positioned relative to their parent.
375 TEST_F(WidgetTest
, ChildBoundsRelativeToParent
) {
376 Widget
* toplevel
= CreateTopLevelPlatformWidget();
377 Widget
* child
= CreateChildPlatformWidget(toplevel
->GetNativeView());
379 toplevel
->SetBounds(gfx::Rect(160, 100, 320, 200));
380 child
->SetBounds(gfx::Rect(0, 0, 320, 200));
385 gfx::Rect toplevel_bounds
= toplevel
->GetWindowBoundsInScreen();
387 // Check the parent origin. If it was (0, 0) the test wouldn't be interesting.
388 EXPECT_NE(gfx::Vector2d(0, 0), toplevel_bounds
.OffsetFromOrigin());
390 // The child's origin is at (0, 0), but the same size, so bounds should match.
391 EXPECT_EQ(toplevel_bounds
, child
->GetWindowBoundsInScreen());
393 toplevel
->CloseNow();
396 // Test z-order of child widgets relative to their parent.
397 TEST_F(WidgetTest
, ChildStackedRelativeToParent
) {
398 Widget
* parent
= CreateTopLevelPlatformWidget();
399 Widget
* child
= CreateChildPlatformWidget(parent
->GetNativeView());
401 parent
->SetBounds(gfx::Rect(160, 100, 320, 200));
402 child
->SetBounds(gfx::Rect(50, 50, 30, 20));
404 // Child shown first. Initially not visible, but on top of parent when shown.
405 // Use ShowInactive whenever showing the child, otherwise the usual activation
406 // logic will just put it on top anyway. Here, we want to ensure it is on top
407 // of its parent regardless.
408 child
->ShowInactive();
409 EXPECT_FALSE(child
->IsVisible());
412 EXPECT_TRUE(child
->IsVisible());
413 EXPECT_TRUE(IsWindowStackedAbove(child
, parent
));
414 EXPECT_FALSE(IsWindowStackedAbove(parent
, child
)); // Sanity check.
416 Widget
* popover
= CreateTopLevelPlatformWidget();
417 popover
->SetBounds(gfx::Rect(150, 90, 340, 240));
420 EXPECT_TRUE(IsWindowStackedAbove(popover
, child
));
421 EXPECT_TRUE(IsWindowStackedAbove(child
, parent
));
423 // Showing the parent again should raise it and its child above the popover.
425 EXPECT_TRUE(IsWindowStackedAbove(child
, parent
));
426 EXPECT_TRUE(IsWindowStackedAbove(parent
, popover
));
428 // Test grandchildren.
429 Widget
* grandchild
= CreateChildPlatformWidget(child
->GetNativeView());
430 grandchild
->SetBounds(gfx::Rect(5, 5, 15, 10));
431 grandchild
->ShowInactive();
432 EXPECT_TRUE(IsWindowStackedAbove(grandchild
, child
));
433 EXPECT_TRUE(IsWindowStackedAbove(child
, parent
));
434 EXPECT_TRUE(IsWindowStackedAbove(parent
, popover
));
437 EXPECT_TRUE(IsWindowStackedAbove(popover
, grandchild
));
438 EXPECT_TRUE(IsWindowStackedAbove(grandchild
, child
));
441 EXPECT_TRUE(IsWindowStackedAbove(grandchild
, child
));
442 EXPECT_TRUE(IsWindowStackedAbove(child
, popover
));
444 // Test hiding and reshowing.
446 EXPECT_FALSE(grandchild
->IsVisible());
449 EXPECT_TRUE(IsWindowStackedAbove(grandchild
, child
));
450 EXPECT_TRUE(IsWindowStackedAbove(child
, parent
));
451 EXPECT_TRUE(IsWindowStackedAbove(parent
, popover
));
454 EXPECT_FALSE(grandchild
->IsVisible());
455 grandchild
->ShowInactive();
457 EXPECT_TRUE(IsWindowStackedAbove(grandchild
, child
));
458 EXPECT_TRUE(IsWindowStackedAbove(child
, parent
));
459 EXPECT_TRUE(IsWindowStackedAbove(parent
, popover
));
465 ////////////////////////////////////////////////////////////////////////////////
466 // Widget ownership tests.
468 // Tests various permutations of Widget ownership specified in the
469 // InitParams::Ownership param.
471 // A WidgetTest that supplies a toplevel widget for NativeWidget to parent to.
472 class WidgetOwnershipTest
: public WidgetTest
{
474 WidgetOwnershipTest() {}
475 ~WidgetOwnershipTest() override
{}
477 void SetUp() override
{
479 desktop_widget_
= CreateTopLevelPlatformWidget();
482 void TearDown() override
{
483 desktop_widget_
->CloseNow();
484 WidgetTest::TearDown();
488 Widget
* desktop_widget_
;
490 DISALLOW_COPY_AND_ASSIGN(WidgetOwnershipTest
);
493 // A bag of state to monitor destructions.
494 struct OwnershipTestState
{
495 OwnershipTestState() : widget_deleted(false), native_widget_deleted(false) {}
498 bool native_widget_deleted
;
501 // A platform NativeWidget subclass that updates a bag of state when it is
503 class OwnershipTestNativeWidget
: public PlatformNativeWidget
{
505 OwnershipTestNativeWidget(internal::NativeWidgetDelegate
* delegate
,
506 OwnershipTestState
* state
)
507 : PlatformNativeWidget(delegate
),
510 ~OwnershipTestNativeWidget() override
{
511 state_
->native_widget_deleted
= true;
515 OwnershipTestState
* state_
;
517 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidget
);
520 // A views NativeWidget subclass that updates a bag of state when it is
522 class OwnershipTestNativeWidgetAura
: public NativeWidgetCapture
{
524 OwnershipTestNativeWidgetAura(internal::NativeWidgetDelegate
* delegate
,
525 OwnershipTestState
* state
)
526 : NativeWidgetCapture(delegate
),
529 ~OwnershipTestNativeWidgetAura() override
{
530 state_
->native_widget_deleted
= true;
534 OwnershipTestState
* state_
;
536 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetAura
);
539 // A Widget subclass that updates a bag of state when it is destroyed.
540 class OwnershipTestWidget
: public Widget
{
542 explicit OwnershipTestWidget(OwnershipTestState
* state
) : state_(state
) {}
543 ~OwnershipTestWidget() override
{ state_
->widget_deleted
= true; }
546 OwnershipTestState
* state_
;
548 DISALLOW_COPY_AND_ASSIGN(OwnershipTestWidget
);
551 // Widget owns its NativeWidget, part 1: NativeWidget is a platform-native
553 TEST_F(WidgetOwnershipTest
, Ownership_WidgetOwnsPlatformNativeWidget
) {
554 OwnershipTestState state
;
556 scoped_ptr
<Widget
> widget(new OwnershipTestWidget(&state
));
557 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
558 params
.native_widget
=
559 new OwnershipTestNativeWidgetAura(widget
.get(), &state
);
560 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
561 widget
->Init(params
);
563 // Now delete the Widget, which should delete the NativeWidget.
566 EXPECT_TRUE(state
.widget_deleted
);
567 EXPECT_TRUE(state
.native_widget_deleted
);
569 // TODO(beng): write test for this ownership scenario and the NativeWidget
570 // being deleted out from under the Widget.
573 // Widget owns its NativeWidget, part 2: NativeWidget is a NativeWidget.
574 TEST_F(WidgetOwnershipTest
, Ownership_WidgetOwnsViewsNativeWidget
) {
575 OwnershipTestState state
;
577 scoped_ptr
<Widget
> widget(new OwnershipTestWidget(&state
));
578 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
579 params
.native_widget
=
580 new OwnershipTestNativeWidgetAura(widget
.get(), &state
);
581 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
582 widget
->Init(params
);
584 // Now delete the Widget, which should delete the NativeWidget.
587 EXPECT_TRUE(state
.widget_deleted
);
588 EXPECT_TRUE(state
.native_widget_deleted
);
590 // TODO(beng): write test for this ownership scenario and the NativeWidget
591 // being deleted out from under the Widget.
594 // Widget owns its NativeWidget, part 3: NativeWidget is a NativeWidget,
595 // destroy the parent view.
596 TEST_F(WidgetOwnershipTest
,
597 Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView
) {
598 OwnershipTestState state
;
600 Widget
* toplevel
= CreateTopLevelPlatformWidget();
602 scoped_ptr
<Widget
> widget(new OwnershipTestWidget(&state
));
603 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
604 params
.native_widget
=
605 new OwnershipTestNativeWidgetAura(widget
.get(), &state
);
606 params
.parent
= toplevel
->GetNativeView();
607 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
608 widget
->Init(params
);
610 // Now close the toplevel, which deletes the view hierarchy.
611 toplevel
->CloseNow();
613 RunPendingMessages();
615 // This shouldn't delete the widget because it shouldn't be deleted
616 // from the native side.
617 EXPECT_FALSE(state
.widget_deleted
);
618 EXPECT_FALSE(state
.native_widget_deleted
);
620 // Now delete it explicitly.
623 EXPECT_TRUE(state
.widget_deleted
);
624 EXPECT_TRUE(state
.native_widget_deleted
);
627 // NativeWidget owns its Widget, part 1: NativeWidget is a platform-native
629 TEST_F(WidgetOwnershipTest
, Ownership_PlatformNativeWidgetOwnsWidget
) {
630 OwnershipTestState state
;
632 Widget
* widget
= new OwnershipTestWidget(&state
);
633 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
634 params
.native_widget
=
635 new OwnershipTestNativeWidgetAura(widget
, &state
);
636 widget
->Init(params
);
638 // Now destroy the native widget.
641 EXPECT_TRUE(state
.widget_deleted
);
642 EXPECT_TRUE(state
.native_widget_deleted
);
645 // NativeWidget owns its Widget, part 2: NativeWidget is a NativeWidget.
646 TEST_F(WidgetOwnershipTest
, Ownership_ViewsNativeWidgetOwnsWidget
) {
647 OwnershipTestState state
;
649 Widget
* toplevel
= CreateTopLevelPlatformWidget();
651 Widget
* widget
= new OwnershipTestWidget(&state
);
652 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
653 params
.native_widget
=
654 new OwnershipTestNativeWidgetAura(widget
, &state
);
655 params
.parent
= toplevel
->GetNativeView();
656 widget
->Init(params
);
658 // Now destroy the native widget. This is achieved by closing the toplevel.
659 toplevel
->CloseNow();
661 // The NativeWidget won't be deleted until after a return to the message loop
662 // so we have to run pending messages before testing the destruction status.
663 RunPendingMessages();
665 EXPECT_TRUE(state
.widget_deleted
);
666 EXPECT_TRUE(state
.native_widget_deleted
);
669 // NativeWidget owns its Widget, part 3: NativeWidget is a platform-native
670 // widget, destroyed out from under it by the OS.
671 TEST_F(WidgetOwnershipTest
,
672 Ownership_PlatformNativeWidgetOwnsWidget_NativeDestroy
) {
673 OwnershipTestState state
;
675 Widget
* widget
= new OwnershipTestWidget(&state
);
676 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
677 params
.native_widget
=
678 new OwnershipTestNativeWidgetAura(widget
, &state
);
679 widget
->Init(params
);
681 // Now simulate a destroy of the platform native widget from the OS:
682 SimulateNativeDestroy(widget
);
684 EXPECT_TRUE(state
.widget_deleted
);
685 EXPECT_TRUE(state
.native_widget_deleted
);
688 // NativeWidget owns its Widget, part 4: NativeWidget is a NativeWidget,
689 // destroyed by the view hierarchy that contains it.
690 TEST_F(WidgetOwnershipTest
,
691 Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy
) {
692 OwnershipTestState state
;
694 Widget
* toplevel
= CreateTopLevelPlatformWidget();
696 Widget
* widget
= new OwnershipTestWidget(&state
);
697 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
698 params
.native_widget
=
699 new OwnershipTestNativeWidgetAura(widget
, &state
);
700 params
.parent
= toplevel
->GetNativeView();
701 widget
->Init(params
);
703 // Destroy the widget (achieved by closing the toplevel).
704 toplevel
->CloseNow();
706 // The NativeWidget won't be deleted until after a return to the message loop
707 // so we have to run pending messages before testing the destruction status.
708 RunPendingMessages();
710 EXPECT_TRUE(state
.widget_deleted
);
711 EXPECT_TRUE(state
.native_widget_deleted
);
714 // NativeWidget owns its Widget, part 5: NativeWidget is a NativeWidget,
715 // we close it directly.
716 TEST_F(WidgetOwnershipTest
,
717 Ownership_ViewsNativeWidgetOwnsWidget_Close
) {
718 OwnershipTestState state
;
720 Widget
* toplevel
= CreateTopLevelPlatformWidget();
722 Widget
* widget
= new OwnershipTestWidget(&state
);
723 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
724 params
.native_widget
=
725 new OwnershipTestNativeWidgetAura(widget
, &state
);
726 params
.parent
= toplevel
->GetNativeView();
727 widget
->Init(params
);
729 // Destroy the widget.
731 toplevel
->CloseNow();
733 // The NativeWidget won't be deleted until after a return to the message loop
734 // so we have to run pending messages before testing the destruction status.
735 RunPendingMessages();
737 EXPECT_TRUE(state
.widget_deleted
);
738 EXPECT_TRUE(state
.native_widget_deleted
);
741 // Widget owns its NativeWidget and has a WidgetDelegateView as its contents.
742 TEST_F(WidgetOwnershipTest
,
743 Ownership_WidgetOwnsNativeWidgetWithWithWidgetDelegateView
) {
744 OwnershipTestState state
;
746 WidgetDelegateView
* delegate_view
= new WidgetDelegateView
;
748 scoped_ptr
<Widget
> widget(new OwnershipTestWidget(&state
));
749 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
750 params
.native_widget
=
751 new OwnershipTestNativeWidgetAura(widget
.get(), &state
);
752 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
753 params
.delegate
= delegate_view
;
754 widget
->Init(params
);
755 widget
->SetContentsView(delegate_view
);
757 // Now delete the Widget. There should be no crash or use-after-free.
760 EXPECT_TRUE(state
.widget_deleted
);
761 EXPECT_TRUE(state
.native_widget_deleted
);
764 ////////////////////////////////////////////////////////////////////////////////
765 // Test to verify using various Widget methods doesn't crash when the underlying
766 // NativeView is destroyed.
768 class WidgetWithDestroyedNativeViewTest
: public ViewsTestBase
{
770 WidgetWithDestroyedNativeViewTest() {}
771 ~WidgetWithDestroyedNativeViewTest() override
{}
773 void InvokeWidgetMethods(Widget
* widget
) {
774 widget
->GetNativeView();
775 widget
->GetNativeWindow();
776 ui::Accelerator accelerator
;
777 widget
->GetAccelerator(0, &accelerator
);
778 widget
->GetTopLevelWidget();
779 widget
->GetWindowBoundsInScreen();
780 widget
->GetClientAreaBoundsInScreen();
781 widget
->SetBounds(gfx::Rect(0, 0, 100, 80));
782 widget
->SetSize(gfx::Size(10, 11));
783 widget
->SetBoundsConstrained(gfx::Rect(0, 0, 120, 140));
784 widget
->SetVisibilityChangedAnimationsEnabled(false);
785 widget
->StackAtTop();
790 widget
->Deactivate();
792 widget
->DisableInactiveRendering();
793 widget
->SetAlwaysOnTop(true);
794 widget
->IsAlwaysOnTop();
798 widget
->IsMaximized();
799 widget
->IsFullscreen();
800 widget
->SetOpacity(0);
801 widget
->SetUseDragFrame(true);
802 widget
->FlashFrame(true);
804 widget
->GetThemeProvider();
805 widget
->GetNativeTheme();
806 widget
->GetFocusManager();
807 widget
->GetInputMethod();
808 widget
->SchedulePaintInRect(gfx::Rect(0, 0, 1, 2));
809 widget
->IsMouseEventsEnabled();
810 widget
->SetNativeWindowProperty("xx", widget
);
811 widget
->GetNativeWindowProperty("xx");
812 widget
->GetFocusTraversable();
814 widget
->ReorderNativeViews();
815 widget
->SetCapture(widget
->GetRootView());
816 widget
->ReleaseCapture();
817 widget
->HasCapture();
818 widget
->GetWorkAreaBoundsInScreen();
819 widget
->IsTranslucentWindowOpacitySupported();
823 DISALLOW_COPY_AND_ASSIGN(WidgetWithDestroyedNativeViewTest
);
826 TEST_F(WidgetWithDestroyedNativeViewTest
, Test
) {
829 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
830 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
834 widget
.native_widget_private()->CloseNow();
835 InvokeWidgetMethods(&widget
);
837 #if !defined(OS_CHROMEOS)
840 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
841 params
.native_widget
= new PlatformDesktopNativeWidget(&widget
);
842 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
846 widget
.native_widget_private()->CloseNow();
847 InvokeWidgetMethods(&widget
);
852 ////////////////////////////////////////////////////////////////////////////////
853 // Widget observer tests.
856 class WidgetObserverTest
: public WidgetTest
, public WidgetObserver
{
860 widget_closed_(nullptr),
861 widget_activated_(nullptr),
862 widget_shown_(nullptr),
863 widget_hidden_(nullptr),
864 widget_bounds_changed_(nullptr),
865 widget_to_close_on_hide_(nullptr) {
868 ~WidgetObserverTest() override
{}
870 // Set a widget to Close() the next time the Widget being observed is hidden.
871 void CloseOnNextHide(Widget
* widget
) {
872 widget_to_close_on_hide_
= widget
;
875 // Overridden from WidgetObserver:
876 void OnWidgetDestroying(Widget
* widget
) override
{
877 if (active_
== widget
)
879 widget_closed_
= widget
;
882 void OnWidgetActivationChanged(Widget
* widget
, bool active
) override
{
884 if (widget_activated_
)
885 widget_activated_
->Deactivate();
886 widget_activated_
= widget
;
889 if (widget_activated_
== widget
)
890 widget_activated_
= nullptr;
891 widget_deactivated_
= widget
;
895 void OnWidgetVisibilityChanged(Widget
* widget
, bool visible
) override
{
897 widget_shown_
= widget
;
900 widget_hidden_
= widget
;
901 if (widget_to_close_on_hide_
) {
902 widget_to_close_on_hide_
->Close();
903 widget_to_close_on_hide_
= nullptr;
907 void OnWidgetBoundsChanged(Widget
* widget
,
908 const gfx::Rect
& new_bounds
) override
{
909 widget_bounds_changed_
= widget
;
914 widget_closed_
= nullptr;
915 widget_activated_
= nullptr;
916 widget_deactivated_
= nullptr;
917 widget_shown_
= nullptr;
918 widget_hidden_
= nullptr;
919 widget_bounds_changed_
= nullptr;
922 Widget
* NewWidget() {
923 Widget
* widget
= CreateTopLevelNativeWidget();
924 widget
->AddObserver(this);
928 const Widget
* active() const { return active_
; }
929 const Widget
* widget_closed() const { return widget_closed_
; }
930 const Widget
* widget_activated() const { return widget_activated_
; }
931 const Widget
* widget_deactivated() const { return widget_deactivated_
; }
932 const Widget
* widget_shown() const { return widget_shown_
; }
933 const Widget
* widget_hidden() const { return widget_hidden_
; }
934 const Widget
* widget_bounds_changed() const { return widget_bounds_changed_
; }
939 Widget
* widget_closed_
;
940 Widget
* widget_activated_
;
941 Widget
* widget_deactivated_
;
942 Widget
* widget_shown_
;
943 Widget
* widget_hidden_
;
944 Widget
* widget_bounds_changed_
;
946 Widget
* widget_to_close_on_hide_
;
949 TEST_F(WidgetObserverTest
, DISABLED_ActivationChange
) {
950 Widget
* toplevel
= CreateTopLevelPlatformWidget();
952 Widget
* toplevel1
= NewWidget();
953 Widget
* toplevel2
= NewWidget();
960 toplevel1
->Activate();
962 RunPendingMessages();
963 EXPECT_EQ(toplevel1
, widget_activated());
965 toplevel2
->Activate();
966 RunPendingMessages();
967 EXPECT_EQ(toplevel1
, widget_deactivated());
968 EXPECT_EQ(toplevel2
, widget_activated());
969 EXPECT_EQ(toplevel2
, active());
971 toplevel
->CloseNow();
974 TEST_F(WidgetObserverTest
, DISABLED_VisibilityChange
) {
975 Widget
* toplevel
= CreateTopLevelPlatformWidget();
977 Widget
* child1
= NewWidget();
978 Widget
* child2
= NewWidget();
987 EXPECT_EQ(child1
, widget_hidden());
990 EXPECT_EQ(child2
, widget_hidden());
993 EXPECT_EQ(child1
, widget_shown());
996 EXPECT_EQ(child2
, widget_shown());
998 toplevel
->CloseNow();
1001 TEST_F(WidgetObserverTest
, DestroyBubble
) {
1002 Widget
* anchor
= CreateTopLevelPlatformWidget();
1005 BubbleDelegateView
* bubble_delegate
=
1006 new BubbleDelegateView(anchor
->client_view(), BubbleBorder::NONE
);
1007 Widget
* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate
));
1008 bubble_widget
->Show();
1009 bubble_widget
->CloseNow();
1015 TEST_F(WidgetObserverTest
, WidgetBoundsChanged
) {
1016 Widget
* child1
= NewWidget();
1017 Widget
* child2
= NewWidget();
1019 child1
->OnNativeWidgetMove();
1020 EXPECT_EQ(child1
, widget_bounds_changed());
1022 child2
->OnNativeWidgetMove();
1023 EXPECT_EQ(child2
, widget_bounds_changed());
1025 child1
->OnNativeWidgetSizeChanged(gfx::Size());
1026 EXPECT_EQ(child1
, widget_bounds_changed());
1028 child2
->OnNativeWidgetSizeChanged(gfx::Size());
1029 EXPECT_EQ(child2
, widget_bounds_changed());
1032 // An extension to WidgetBoundsChanged to ensure notifications are forwarded
1033 // by the NativeWidget implementation.
1034 TEST_F(WidgetObserverTest
, WidgetBoundsChangedNative
) {
1035 // Don't use NewWidget(), so that the Init() flow can be observed to ensure
1036 // consistency across platforms.
1037 Widget
* widget
= new Widget(); // Note: owned by NativeWidget.
1038 widget
->AddObserver(this);
1040 EXPECT_FALSE(widget_bounds_changed());
1042 // Init causes a bounds change, even while not showing. Note some platforms
1043 // cause a bounds change even when the bounds are empty. Mac does not.
1044 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_WINDOW
);
1045 params
.bounds
= gfx::Rect(0, 0, 100, 100);
1046 widget
->Init(params
);
1047 EXPECT_TRUE(widget_bounds_changed());
1050 // Resizing while hidden, triggers a change.
1051 widget
->SetSize(gfx::Size(160, 100));
1052 EXPECT_FALSE(widget
->IsVisible());
1053 EXPECT_TRUE(widget_bounds_changed());
1056 // Setting the same size does nothing.
1057 widget
->SetSize(gfx::Size(160, 100));
1058 EXPECT_FALSE(widget_bounds_changed());
1061 // Showing does nothing to the bounds.
1063 EXPECT_TRUE(widget
->IsVisible());
1064 EXPECT_FALSE(widget_bounds_changed());
1067 // Resizing while shown.
1068 widget
->SetSize(gfx::Size(170, 100));
1069 EXPECT_TRUE(widget_bounds_changed());
1072 // Resize to the same thing while shown does nothing.
1073 widget
->SetSize(gfx::Size(170, 100));
1074 EXPECT_FALSE(widget_bounds_changed());
1077 // No bounds change when closing.
1079 EXPECT_FALSE(widget_bounds_changed());
1082 // Test correct behavior when widgets close themselves in response to visibility
1084 TEST_F(WidgetObserverTest
, ClosingOnHiddenParent
) {
1085 Widget
* parent
= NewWidget();
1086 Widget
* child
= CreateChildPlatformWidget(parent
->GetNativeView());
1088 TestWidgetObserver
child_observer(child
);
1090 EXPECT_FALSE(parent
->IsVisible());
1091 EXPECT_FALSE(child
->IsVisible());
1093 // Note |child| is TYPE_CONTROL, which start shown. So no need to show the
1094 // child separately.
1096 EXPECT_TRUE(parent
->IsVisible());
1097 EXPECT_TRUE(child
->IsVisible());
1099 // Simulate a child widget that closes itself when the parent is hidden.
1100 CloseOnNextHide(child
);
1101 EXPECT_FALSE(child_observer
.widget_closed());
1103 RunPendingMessages();
1104 EXPECT_TRUE(child_observer
.widget_closed());
1109 // Test behavior of NativeWidget*::GetWindowPlacement on the native desktop.
1110 TEST_F(WidgetTest
, GetWindowPlacement
) {
1112 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
1113 // On desktop-Linux cheat and use non-desktop widgets. On X11, minimize is
1114 // asynchronous. Also (harder) showing a window doesn't activate it without
1115 // user interaction (or extra steps only done for interactive ui tests).
1116 // Without that, show_state remains in ui::SHOW_STATE_INACTIVE throughout.
1117 // TODO(tapted): Find a nice way to run this with desktop widgets on Linux.
1118 widget
= CreateTopLevelPlatformWidget();
1120 widget
= CreateNativeDesktopWidget();
1123 gfx::Rect
expected_bounds(100, 110, 200, 220);
1124 widget
->SetBounds(expected_bounds
);
1127 // Start with something invalid to ensure it changes.
1128 ui::WindowShowState show_state
= ui::SHOW_STATE_END
;
1129 gfx::Rect restored_bounds
;
1131 internal::NativeWidgetPrivate
* native_widget
=
1132 widget
->native_widget_private();
1134 native_widget
->GetWindowPlacement(&restored_bounds
, &show_state
);
1135 EXPECT_EQ(expected_bounds
, restored_bounds
);
1136 #if defined(OS_LINUX)
1137 // Non-desktop/Ash widgets start off in "default" until a Restore().
1138 EXPECT_EQ(ui::SHOW_STATE_DEFAULT
, show_state
);
1140 native_widget
->GetWindowPlacement(&restored_bounds
, &show_state
);
1142 EXPECT_EQ(ui::SHOW_STATE_NORMAL
, show_state
);
1145 native_widget
->GetWindowPlacement(&restored_bounds
, &show_state
);
1146 EXPECT_EQ(ui::SHOW_STATE_MINIMIZED
, show_state
);
1147 EXPECT_EQ(expected_bounds
, restored_bounds
);
1150 native_widget
->GetWindowPlacement(&restored_bounds
, &show_state
);
1151 EXPECT_EQ(ui::SHOW_STATE_NORMAL
, show_state
);
1152 EXPECT_EQ(expected_bounds
, restored_bounds
);
1154 expected_bounds
= gfx::Rect(130, 140, 230, 250);
1155 widget
->SetBounds(expected_bounds
);
1156 native_widget
->GetWindowPlacement(&restored_bounds
, &show_state
);
1157 EXPECT_EQ(ui::SHOW_STATE_NORMAL
, show_state
);
1158 EXPECT_EQ(expected_bounds
, restored_bounds
);
1160 widget
->SetFullscreen(true);
1161 native_widget
->GetWindowPlacement(&restored_bounds
, &show_state
);
1164 // Desktop Aura widgets on Windows currently don't update show_state when
1165 // going fullscreen, and report restored_bounds as the full screen size.
1166 // See http://crbug.com/475813.
1167 EXPECT_EQ(ui::SHOW_STATE_NORMAL
, show_state
);
1169 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN
, show_state
);
1170 EXPECT_EQ(expected_bounds
, restored_bounds
);
1173 widget
->SetFullscreen(false);
1174 native_widget
->GetWindowPlacement(&restored_bounds
, &show_state
);
1175 EXPECT_EQ(ui::SHOW_STATE_NORMAL
, show_state
);
1176 EXPECT_EQ(expected_bounds
, restored_bounds
);
1181 // Test that widget size constraints are properly applied immediately after
1182 // Init(), and that SetBounds() calls are appropriately clamped.
1183 TEST_F(WidgetTest
, MinimumSizeConstraints
) {
1184 TestDesktopWidgetDelegate delegate
;
1185 gfx::Size
minimum_size(100, 100);
1186 const gfx::Size
smaller_size(90, 90);
1188 delegate
.set_contents_view(new StaticSizedView(minimum_size
));
1189 delegate
.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW
));
1190 Widget
* widget
= delegate
.GetWidget();
1192 // On desktop Linux, the Widget must be shown to ensure the window is mapped.
1193 // On other platforms this line is optional.
1197 EXPECT_GT(delegate
.initial_bounds().width(), minimum_size
.width());
1198 EXPECT_GT(delegate
.initial_bounds().height(), minimum_size
.height());
1199 EXPECT_EQ(delegate
.initial_bounds().size(),
1200 widget
->GetWindowBoundsInScreen().size());
1201 // Note: StaticSizedView doesn't currently provide a maximum size.
1202 EXPECT_EQ(gfx::Size(), widget
->GetMaximumSize());
1204 if (!widget
->ShouldUseNativeFrame()) {
1205 // The test environment may have dwm disabled on Windows. In this case,
1206 // CustomFrameView is used instead of the NativeFrameView, which will
1207 // provide a minimum size that includes frame decorations.
1208 minimum_size
= widget
->non_client_view()->GetWindowBoundsForClientBounds(
1209 gfx::Rect(minimum_size
)).size();
1212 EXPECT_EQ(minimum_size
, widget
->GetMinimumSize());
1213 EXPECT_EQ(minimum_size
, GetNativeWidgetMinimumContentSize(widget
));
1215 // Trying to resize smaller than the minimum size should restrict the content
1216 // size to the minimum size.
1217 widget
->SetBounds(gfx::Rect(smaller_size
));
1218 EXPECT_EQ(minimum_size
, widget
->GetClientAreaBoundsInScreen().size());
1220 widget
->SetSize(smaller_size
);
1221 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
1222 // TODO(tapted): Desktop Linux ignores size constraints for SetSize. Fix it.
1223 EXPECT_EQ(smaller_size
, widget
->GetClientAreaBoundsInScreen().size());
1225 EXPECT_EQ(minimum_size
, widget
->GetClientAreaBoundsInScreen().size());
1229 // Tests that SetBounds() and GetWindowBoundsInScreen() is symmetric when the
1230 // widget is visible and not maximized or fullscreen.
1231 TEST_F(WidgetTest
, GetWindowBoundsInScreen
) {
1232 // Choose test coordinates away from edges and dimensions that are "small"
1233 // (but not too small) to ensure the OS doesn't try to adjust them.
1234 const gfx::Rect
kTestBounds(150, 150, 400, 300);
1235 const gfx::Size
kTestSize(200, 180);
1237 // First test a toplevel widget.
1238 Widget
* widget
= CreateTopLevelPlatformWidget();
1241 EXPECT_NE(kTestSize
.ToString(),
1242 widget
->GetWindowBoundsInScreen().size().ToString());
1243 widget
->SetSize(kTestSize
);
1244 EXPECT_EQ(kTestSize
.ToString(),
1245 widget
->GetWindowBoundsInScreen().size().ToString());
1247 EXPECT_NE(kTestBounds
.ToString(),
1248 widget
->GetWindowBoundsInScreen().ToString());
1249 widget
->SetBounds(kTestBounds
);
1250 EXPECT_EQ(kTestBounds
.ToString(),
1251 widget
->GetWindowBoundsInScreen().ToString());
1253 // Changing just the size should not change the origin.
1254 widget
->SetSize(kTestSize
);
1255 EXPECT_EQ(kTestBounds
.origin().ToString(),
1256 widget
->GetWindowBoundsInScreen().origin().ToString());
1260 // Same tests with a frameless window.
1261 widget
= CreateTopLevelFramelessPlatformWidget();
1264 EXPECT_NE(kTestSize
.ToString(),
1265 widget
->GetWindowBoundsInScreen().size().ToString());
1266 widget
->SetSize(kTestSize
);
1267 EXPECT_EQ(kTestSize
.ToString(),
1268 widget
->GetWindowBoundsInScreen().size().ToString());
1270 EXPECT_NE(kTestBounds
.ToString(),
1271 widget
->GetWindowBoundsInScreen().ToString());
1272 widget
->SetBounds(kTestBounds
);
1273 EXPECT_EQ(kTestBounds
.ToString(),
1274 widget
->GetWindowBoundsInScreen().ToString());
1276 // For a frameless widget, the client bounds should also match.
1277 EXPECT_EQ(kTestBounds
.ToString(),
1278 widget
->GetClientAreaBoundsInScreen().ToString());
1280 // Verify origin is stable for a frameless window as well.
1281 widget
->SetSize(kTestSize
);
1282 EXPECT_EQ(kTestBounds
.origin().ToString(),
1283 widget
->GetWindowBoundsInScreen().origin().ToString());
1288 // Before being enabled on Mac, this was #ifdef(false).
1289 // TODO(tapted): Fix this for DesktopNativeWidgets on other platforms.
1290 #if defined(OS_MACOSX)
1291 // Aura needs shell to maximize/fullscreen window.
1292 // NativeWidgetGtk doesn't implement GetRestoredBounds.
1293 TEST_F(WidgetTest
, GetRestoredBounds
) {
1294 Widget
* toplevel
= CreateTopLevelPlatformWidget();
1295 EXPECT_EQ(toplevel
->GetWindowBoundsInScreen().ToString(),
1296 toplevel
->GetRestoredBounds().ToString());
1298 toplevel
->Maximize();
1299 RunPendingMessages();
1300 #if defined(OS_MACOSX)
1301 // Current expectation on Mac is to do nothing on Maximize.
1302 EXPECT_EQ(toplevel
->GetWindowBoundsInScreen().ToString(),
1303 toplevel
->GetRestoredBounds().ToString());
1305 EXPECT_NE(toplevel
->GetWindowBoundsInScreen().ToString(),
1306 toplevel
->GetRestoredBounds().ToString());
1308 EXPECT_GT(toplevel
->GetRestoredBounds().width(), 0);
1309 EXPECT_GT(toplevel
->GetRestoredBounds().height(), 0);
1311 toplevel
->Restore();
1312 RunPendingMessages();
1313 EXPECT_EQ(toplevel
->GetWindowBoundsInScreen().ToString(),
1314 toplevel
->GetRestoredBounds().ToString());
1316 toplevel
->SetFullscreen(true);
1317 RunPendingMessages();
1319 if (IsTestingSnowLeopard()) {
1320 // Fullscreen not implemented for Snow Leopard.
1321 EXPECT_EQ(toplevel
->GetWindowBoundsInScreen().ToString(),
1322 toplevel
->GetRestoredBounds().ToString());
1324 EXPECT_NE(toplevel
->GetWindowBoundsInScreen().ToString(),
1325 toplevel
->GetRestoredBounds().ToString());
1327 EXPECT_GT(toplevel
->GetRestoredBounds().width(), 0);
1328 EXPECT_GT(toplevel
->GetRestoredBounds().height(), 0);
1332 // The key-event propagation from Widget happens differently on aura and
1333 // non-aura systems because of the difference in IME. So this test works only on
1335 TEST_F(WidgetTest
, KeyboardInputEvent
) {
1336 Widget
* toplevel
= CreateTopLevelPlatformWidget();
1337 View
* container
= toplevel
->client_view();
1339 Textfield
* textfield
= new Textfield();
1340 textfield
->SetText(base::ASCIIToUTF16("some text"));
1341 container
->AddChildView(textfield
);
1343 textfield
->RequestFocus();
1345 // The press gets handled. The release doesn't have an effect.
1346 ui::KeyEvent
backspace_p(ui::ET_KEY_PRESSED
, ui::VKEY_DELETE
, ui::EF_NONE
);
1347 toplevel
->OnKeyEvent(&backspace_p
);
1348 EXPECT_TRUE(backspace_p
.stopped_propagation());
1349 ui::KeyEvent
backspace_r(ui::ET_KEY_RELEASED
, ui::VKEY_DELETE
, ui::EF_NONE
);
1350 toplevel
->OnKeyEvent(&backspace_r
);
1351 EXPECT_FALSE(backspace_r
.handled());
1356 // Verifies bubbles result in a focus lost when shown.
1357 // TODO(msw): this tests relies on focus, it needs to be in
1358 // interactive_ui_tests.
1359 TEST_F(WidgetTest
, DISABLED_FocusChangesOnBubble
) {
1360 // Create a widget, show and activate it and focus the contents view.
1361 View
* contents_view
= new View
;
1362 contents_view
->SetFocusable(true);
1364 Widget::InitParams init_params
=
1365 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS
);
1366 init_params
.bounds
= gfx::Rect(0, 0, 200, 200);
1367 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1368 #if !defined(OS_CHROMEOS)
1369 init_params
.native_widget
= new PlatformDesktopNativeWidget(&widget
);
1371 widget
.Init(init_params
);
1372 widget
.SetContentsView(contents_view
);
1375 contents_view
->RequestFocus();
1376 EXPECT_TRUE(contents_view
->HasFocus());
1379 BubbleDelegateView
* bubble_delegate_view
=
1380 new BubbleDelegateView(contents_view
, BubbleBorder::TOP_LEFT
);
1381 bubble_delegate_view
->SetFocusable(true);
1382 BubbleDelegateView::CreateBubble(bubble_delegate_view
)->Show();
1383 bubble_delegate_view
->RequestFocus();
1385 // |contents_view_| should no longer have focus.
1386 EXPECT_FALSE(contents_view
->HasFocus());
1387 EXPECT_TRUE(bubble_delegate_view
->HasFocus());
1389 bubble_delegate_view
->GetWidget()->CloseNow();
1391 // Closing the bubble should result in focus going back to the contents view.
1392 EXPECT_TRUE(contents_view
->HasFocus());
1395 class TestBubbleDelegateView
: public BubbleDelegateView
{
1397 TestBubbleDelegateView(View
* anchor
)
1398 : BubbleDelegateView(anchor
, BubbleBorder::NONE
),
1399 reset_controls_called_(false) {}
1400 ~TestBubbleDelegateView() override
{}
1402 bool ShouldShowCloseButton() const override
{
1403 reset_controls_called_
= true;
1407 mutable bool reset_controls_called_
;
1410 TEST_F(WidgetTest
, BubbleControlsResetOnInit
) {
1411 Widget
* anchor
= CreateTopLevelPlatformWidget();
1414 TestBubbleDelegateView
* bubble_delegate
=
1415 new TestBubbleDelegateView(anchor
->client_view());
1416 Widget
* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate
));
1417 EXPECT_TRUE(bubble_delegate
->reset_controls_called_
);
1418 bubble_widget
->Show();
1419 bubble_widget
->CloseNow();
1426 // Test to ensure that after minimize, view width is set to zero. This is only
1427 // the case for desktop widgets on Windows. Other platforms retain the window
1428 // size while minimized.
1429 TEST_F(WidgetTest
, TestViewWidthAfterMinimizingWidget
) {
1432 Widget::InitParams init_params
=
1433 CreateParams(Widget::InitParams::TYPE_WINDOW
);
1434 init_params
.show_state
= ui::SHOW_STATE_NORMAL
;
1435 gfx::Rect
initial_bounds(0, 0, 300, 400);
1436 init_params
.bounds
= initial_bounds
;
1437 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1438 init_params
.native_widget
= new PlatformDesktopNativeWidget(&widget
);
1439 widget
.Init(init_params
);
1440 NonClientView
* non_client_view
= widget
.non_client_view();
1441 NonClientFrameView
* frame_view
= new MinimumSizeFrameView(&widget
);
1442 non_client_view
->SetFrameView(frame_view
);
1443 // Setting the frame view doesn't do a layout, so force one.
1444 non_client_view
->Layout();
1446 EXPECT_NE(0, frame_view
->width());
1448 EXPECT_EQ(0, frame_view
->width());
1452 // Desktop native widget Aura tests are for non Chrome OS platforms.
1453 #if !defined(OS_CHROMEOS)
1454 // This class validates whether paints are received for a visible Widget.
1455 // To achieve this it overrides the Show and Close methods on the Widget class
1456 // and sets state whether subsequent paints are expected.
1457 class DesktopAuraTestValidPaintWidget
: public views::Widget
{
1459 DesktopAuraTestValidPaintWidget()
1460 : received_paint_(false),
1461 expect_paint_(true),
1462 received_paint_while_hidden_(false) {}
1464 ~DesktopAuraTestValidPaintWidget() override
{}
1466 void InitForTest(Widget::InitParams create_params
);
1468 void Show() override
{
1469 expect_paint_
= true;
1470 views::Widget::Show();
1473 void Close() override
{
1474 expect_paint_
= false;
1475 views::Widget::Close();
1479 expect_paint_
= false;
1480 views::Widget::Hide();
1483 void OnNativeWidgetPaint(const ui::PaintContext
& context
) override
{
1484 received_paint_
= true;
1485 EXPECT_TRUE(expect_paint_
);
1487 received_paint_while_hidden_
= true;
1488 views::Widget::OnNativeWidgetPaint(context
);
1491 bool ReadReceivedPaintAndReset() {
1492 bool result
= received_paint_
;
1493 received_paint_
= false;
1497 bool received_paint_while_hidden() const {
1498 return received_paint_while_hidden_
;
1502 bool received_paint_
;
1504 bool received_paint_while_hidden_
;
1506 DISALLOW_COPY_AND_ASSIGN(DesktopAuraTestValidPaintWidget
);
1509 void DesktopAuraTestValidPaintWidget::InitForTest(InitParams init_params
) {
1510 init_params
.bounds
= gfx::Rect(0, 0, 200, 200);
1511 init_params
.ownership
= InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1512 init_params
.native_widget
= new PlatformDesktopNativeWidget(this);
1515 View
* contents_view
= new View
;
1516 contents_view
->SetFocusable(true);
1517 SetContentsView(contents_view
);
1523 TEST_F(WidgetTest
, DesktopNativeWidgetNoPaintAfterCloseTest
) {
1524 DesktopAuraTestValidPaintWidget widget
;
1525 widget
.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS
));
1526 RunPendingMessages();
1527 EXPECT_TRUE(widget
.ReadReceivedPaintAndReset());
1528 widget
.SchedulePaintInRect(widget
.GetRestoredBounds());
1530 RunPendingMessages();
1531 EXPECT_FALSE(widget
.ReadReceivedPaintAndReset());
1532 EXPECT_FALSE(widget
.received_paint_while_hidden());
1535 TEST_F(WidgetTest
, DesktopNativeWidgetNoPaintAfterHideTest
) {
1536 DesktopAuraTestValidPaintWidget widget
;
1537 widget
.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS
));
1538 RunPendingMessages();
1539 EXPECT_TRUE(widget
.ReadReceivedPaintAndReset());
1540 widget
.SchedulePaintInRect(widget
.GetRestoredBounds());
1542 RunPendingMessages();
1543 EXPECT_FALSE(widget
.ReadReceivedPaintAndReset());
1544 EXPECT_FALSE(widget
.received_paint_while_hidden());
1548 // Test to ensure that the aura Window's visiblity state is set to visible if
1549 // the underlying widget is hidden and then shown.
1550 TEST_F(WidgetTest
, TestWindowVisibilityAfterHide
) {
1553 Widget::InitParams init_params
=
1554 CreateParams(Widget::InitParams::TYPE_WINDOW
);
1555 init_params
.show_state
= ui::SHOW_STATE_NORMAL
;
1556 gfx::Rect
initial_bounds(0, 0, 300, 400);
1557 init_params
.bounds
= initial_bounds
;
1558 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1559 init_params
.native_widget
= new PlatformDesktopNativeWidget(&widget
);
1560 widget
.Init(init_params
);
1561 NonClientView
* non_client_view
= widget
.non_client_view();
1562 NonClientFrameView
* frame_view
= new MinimumSizeFrameView(&widget
);
1563 non_client_view
->SetFrameView(frame_view
);
1566 EXPECT_TRUE(IsNativeWindowVisible(widget
.GetNativeWindow()));
1568 EXPECT_FALSE(IsNativeWindowVisible(widget
.GetNativeWindow()));
1570 EXPECT_TRUE(IsNativeWindowVisible(widget
.GetNativeWindow()));
1573 #endif // !defined(OS_CHROMEOS)
1575 // Tests that wheel events generated from scroll events are targetted to the
1576 // views under the cursor when the focused view does not processed them.
1577 TEST_F(WidgetTest
, WheelEventsFromScrollEventTarget
) {
1578 EventCountView
* cursor_view
= new EventCountView
;
1579 cursor_view
->SetBounds(60, 0, 50, 40);
1581 Widget
* widget
= CreateTopLevelPlatformWidget();
1582 widget
->GetRootView()->AddChildView(cursor_view
);
1584 // Generate a scroll event on the cursor view.
1585 ui::ScrollEvent
scroll(ui::ET_SCROLL
,
1587 ui::EventTimeForNow(),
1592 widget
->OnScrollEvent(&scroll
);
1594 EXPECT_EQ(1, cursor_view
->GetEventCount(ui::ET_SCROLL
));
1595 EXPECT_EQ(1, cursor_view
->GetEventCount(ui::ET_MOUSEWHEEL
));
1597 cursor_view
->ResetCounts();
1599 ui::ScrollEvent
scroll2(ui::ET_SCROLL
,
1601 ui::EventTimeForNow(),
1606 widget
->OnScrollEvent(&scroll2
);
1608 EXPECT_EQ(0, cursor_view
->GetEventCount(ui::ET_SCROLL
));
1609 EXPECT_EQ(0, cursor_view
->GetEventCount(ui::ET_MOUSEWHEEL
));
1614 // Tests that if a scroll-begin gesture is not handled, then subsequent scroll
1615 // events are not dispatched to any view.
1616 TEST_F(WidgetTest
, GestureScrollEventDispatching
) {
1617 EventCountView
* noscroll_view
= new EventCountView
;
1618 EventCountView
* scroll_view
= new ScrollableEventCountView
;
1620 noscroll_view
->SetBounds(0, 0, 50, 40);
1621 scroll_view
->SetBounds(60, 0, 40, 40);
1623 Widget
* widget
= CreateTopLevelPlatformWidget();
1624 widget
->GetRootView()->AddChildView(noscroll_view
);
1625 widget
->GetRootView()->AddChildView(scroll_view
);
1628 ui::GestureEvent
begin(
1633 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN
));
1634 widget
->OnGestureEvent(&begin
);
1635 ui::GestureEvent
update(
1640 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE
, 20, 10));
1641 widget
->OnGestureEvent(&update
);
1642 ui::GestureEvent
end(25,
1646 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END
));
1647 widget
->OnGestureEvent(&end
);
1649 EXPECT_EQ(1, noscroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
1650 EXPECT_EQ(0, noscroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
1651 EXPECT_EQ(0, noscroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
1655 ui::GestureEvent
begin(
1660 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN
));
1661 widget
->OnGestureEvent(&begin
);
1662 ui::GestureEvent
update(
1667 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE
, 20, 10));
1668 widget
->OnGestureEvent(&update
);
1669 ui::GestureEvent
end(85,
1673 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END
));
1674 widget
->OnGestureEvent(&end
);
1676 EXPECT_EQ(1, scroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
1677 EXPECT_EQ(1, scroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
1678 EXPECT_EQ(1, scroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
1684 // Tests that event-handlers installed on the RootView get triggered correctly.
1685 // TODO(tdanderson): Clean up this test as part of crbug.com/355680.
1686 TEST_F(WidgetTest
, EventHandlersOnRootView
) {
1687 Widget
* widget
= CreateTopLevelNativeWidget();
1688 View
* root_view
= widget
->GetRootView();
1690 scoped_ptr
<EventCountView
> view(new EventCountView());
1691 view
->set_owned_by_client();
1692 view
->SetBounds(0, 0, 20, 20);
1693 root_view
->AddChildView(view
.get());
1695 EventCountHandler h1
;
1696 root_view
->AddPreTargetHandler(&h1
);
1698 EventCountHandler h2
;
1699 root_view
->AddPostTargetHandler(&h2
);
1701 widget
->SetBounds(gfx::Rect(0, 0, 100, 100));
1704 // Dispatch a ui::ET_SCROLL event. The event remains unhandled and should
1705 // bubble up the views hierarchy to be re-dispatched on the root view.
1706 ui::ScrollEvent
scroll(ui::ET_SCROLL
,
1708 ui::EventTimeForNow(),
1713 widget
->OnScrollEvent(&scroll
);
1714 EXPECT_EQ(2, h1
.GetEventCount(ui::ET_SCROLL
));
1715 EXPECT_EQ(1, view
->GetEventCount(ui::ET_SCROLL
));
1716 EXPECT_EQ(2, h2
.GetEventCount(ui::ET_SCROLL
));
1718 // Unhandled scroll events are turned into wheel events and re-dispatched.
1719 EXPECT_EQ(1, h1
.GetEventCount(ui::ET_MOUSEWHEEL
));
1720 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSEWHEEL
));
1721 EXPECT_EQ(1, h2
.GetEventCount(ui::ET_MOUSEWHEEL
));
1724 view
->ResetCounts();
1727 // Dispatch a ui::ET_SCROLL_FLING_START event. The event remains unhandled and
1728 // should bubble up the views hierarchy to be re-dispatched on the root view.
1729 ui::ScrollEvent
fling(ui::ET_SCROLL_FLING_START
,
1731 ui::EventTimeForNow(),
1736 widget
->OnScrollEvent(&fling
);
1737 EXPECT_EQ(2, h1
.GetEventCount(ui::ET_SCROLL_FLING_START
));
1738 EXPECT_EQ(1, view
->GetEventCount(ui::ET_SCROLL_FLING_START
));
1739 EXPECT_EQ(2, h2
.GetEventCount(ui::ET_SCROLL_FLING_START
));
1741 // Unhandled scroll events which are not of type ui::ET_SCROLL should not
1742 // be turned into wheel events and re-dispatched.
1743 EXPECT_EQ(0, h1
.GetEventCount(ui::ET_MOUSEWHEEL
));
1744 EXPECT_EQ(0, view
->GetEventCount(ui::ET_MOUSEWHEEL
));
1745 EXPECT_EQ(0, h2
.GetEventCount(ui::ET_MOUSEWHEEL
));
1748 view
->ResetCounts();
1751 // Change the handle mode of |view| so that events are marked as handled at
1752 // the target phase.
1753 view
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
1755 // Dispatch a ui::ET_GESTURE_TAP_DOWN and a ui::ET_GESTURE_TAP_CANCEL event.
1756 // The events are handled at the target phase and should not reach the
1757 // post-target handler.
1758 ui::GestureEvent
tap_down(5,
1761 ui::EventTimeForNow(),
1762 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN
));
1763 widget
->OnGestureEvent(&tap_down
);
1764 EXPECT_EQ(1, h1
.GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
1765 EXPECT_EQ(1, view
->GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
1766 EXPECT_EQ(0, h2
.GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
1768 ui::GestureEvent
tap_cancel(
1772 ui::EventTimeForNow(),
1773 ui::GestureEventDetails(ui::ET_GESTURE_TAP_CANCEL
));
1774 widget
->OnGestureEvent(&tap_cancel
);
1775 EXPECT_EQ(1, h1
.GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
1776 EXPECT_EQ(1, view
->GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
1777 EXPECT_EQ(0, h2
.GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
1780 view
->ResetCounts();
1783 // Dispatch a ui::ET_SCROLL event. The event is handled at the target phase
1784 // and should not reach the post-target handler.
1785 ui::ScrollEvent
consumed_scroll(ui::ET_SCROLL
,
1787 ui::EventTimeForNow(),
1792 widget
->OnScrollEvent(&consumed_scroll
);
1793 EXPECT_EQ(1, h1
.GetEventCount(ui::ET_SCROLL
));
1794 EXPECT_EQ(1, view
->GetEventCount(ui::ET_SCROLL
));
1795 EXPECT_EQ(0, h2
.GetEventCount(ui::ET_SCROLL
));
1797 // Handled scroll events are not turned into wheel events and re-dispatched.
1798 EXPECT_EQ(0, h1
.GetEventCount(ui::ET_MOUSEWHEEL
));
1799 EXPECT_EQ(0, view
->GetEventCount(ui::ET_MOUSEWHEEL
));
1800 EXPECT_EQ(0, h2
.GetEventCount(ui::ET_MOUSEWHEEL
));
1805 TEST_F(WidgetTest
, SynthesizeMouseMoveEvent
) {
1806 Widget
* widget
= CreateTopLevelNativeWidget();
1807 View
* root_view
= widget
->GetRootView();
1809 EventCountView
* v1
= new EventCountView();
1810 v1
->SetBounds(0, 0, 10, 10);
1811 root_view
->AddChildView(v1
);
1812 EventCountView
* v2
= new EventCountView();
1813 v2
->SetBounds(0, 10, 10, 10);
1814 root_view
->AddChildView(v2
);
1816 gfx::Point
cursor_location(5, 5);
1817 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
, cursor_location
, cursor_location
,
1818 ui::EventTimeForNow(), ui::EF_NONE
, ui::EF_NONE
);
1819 widget
->OnMouseEvent(&move
);
1821 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_MOUSE_ENTERED
));
1822 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_MOUSE_ENTERED
));
1825 v2
->SetBounds(0, 0, 10, 10);
1826 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_MOUSE_ENTERED
));
1828 widget
->SynthesizeMouseMoveEvent();
1829 EXPECT_EQ(1, v2
->GetEventCount(ui::ET_MOUSE_ENTERED
));
1832 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
1833 #if !defined(OS_MACOSX) || defined(USE_AURA)
1837 // ui::EventHandler which handles all mouse press events.
1838 class MousePressEventConsumer
: public ui::EventHandler
{
1840 MousePressEventConsumer() {}
1843 // ui::EventHandler:
1844 void OnMouseEvent(ui::MouseEvent
* event
) override
{
1845 if (event
->type() == ui::ET_MOUSE_PRESSED
)
1846 event
->SetHandled();
1849 DISALLOW_COPY_AND_ASSIGN(MousePressEventConsumer
);
1854 // Test that mouse presses and mouse releases are dispatched normally when a
1856 TEST_F(WidgetTest
, MouseEventDispatchWhileTouchIsDown
) {
1857 Widget
* widget
= CreateTopLevelNativeWidget();
1859 widget
->SetSize(gfx::Size(300, 300));
1861 EventCountView
* event_count_view
= new EventCountView();
1862 event_count_view
->SetBounds(0, 0, 300, 300);
1863 widget
->GetRootView()->AddChildView(event_count_view
);
1865 MousePressEventConsumer consumer
;
1866 event_count_view
->AddPostTargetHandler(&consumer
);
1868 ui::test::EventGenerator
generator(GetContext(), widget
->GetNativeWindow());
1869 generator
.PressTouch();
1870 generator
.ClickLeftButton();
1872 EXPECT_EQ(1, event_count_view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
1873 EXPECT_EQ(1, event_count_view
->GetEventCount(ui::ET_MOUSE_RELEASED
));
1878 #endif // !defined(OS_MACOSX) || defined(USE_AURA)
1880 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget
1882 TEST_F(WidgetTest
, SingleWindowClosing
) {
1883 TestDesktopWidgetDelegate delegate
;
1884 delegate
.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW
));
1885 EXPECT_EQ(0, delegate
.window_closing_count());
1886 delegate
.GetWidget()->CloseNow();
1887 EXPECT_EQ(1, delegate
.window_closing_count());
1890 class WidgetWindowTitleTest
: public WidgetTest
{
1892 void RunTest(bool desktop_native_widget
) {
1893 Widget
* widget
= new Widget(); // Destroyed by CloseNow() below.
1894 Widget::InitParams init_params
=
1895 CreateParams(Widget::InitParams::TYPE_WINDOW
);
1896 widget
->Init(init_params
);
1898 #if !defined(OS_CHROMEOS)
1899 if (desktop_native_widget
)
1900 init_params
.native_widget
= new PlatformDesktopNativeWidget(widget
);
1902 DCHECK(!desktop_native_widget
)
1903 << "DesktopNativeWidget does not exist on non-Aura or on ChromeOS.";
1906 internal::NativeWidgetPrivate
* native_widget
=
1907 widget
->native_widget_private();
1909 base::string16 empty
;
1910 base::string16
s1(base::UTF8ToUTF16("Title1"));
1911 base::string16
s2(base::UTF8ToUTF16("Title2"));
1912 base::string16
s3(base::UTF8ToUTF16("TitleLong"));
1914 // The widget starts with no title, setting empty should not change
1916 EXPECT_FALSE(native_widget
->SetWindowTitle(empty
));
1917 // Setting the title to something non-empty should cause a change.
1918 EXPECT_TRUE(native_widget
->SetWindowTitle(s1
));
1919 // Setting the title to something else with the same length should cause a
1921 EXPECT_TRUE(native_widget
->SetWindowTitle(s2
));
1922 // Setting the title to something else with a different length should cause
1924 EXPECT_TRUE(native_widget
->SetWindowTitle(s3
));
1925 // Setting the title to the same thing twice should not cause a change.
1926 EXPECT_FALSE(native_widget
->SetWindowTitle(s3
));
1932 TEST_F(WidgetWindowTitleTest
, SetWindowTitleChanged_NativeWidget
) {
1933 // Use the default NativeWidget.
1934 bool desktop_native_widget
= false;
1935 RunTest(desktop_native_widget
);
1938 // DesktopNativeWidget does not exist on non-Aura or on ChromeOS.
1939 #if !defined(OS_CHROMEOS)
1940 TEST_F(WidgetWindowTitleTest
, SetWindowTitleChanged_DesktopNativeWidget
) {
1941 // Override to use a DesktopNativeWidget.
1942 bool desktop_native_widget
= true;
1943 RunTest(desktop_native_widget
);
1945 #endif // !OS_CHROMEOS
1947 TEST_F(WidgetTest
, WidgetDeleted_InOnMousePressed
) {
1948 Widget
* widget
= new Widget
;
1949 Widget::InitParams params
=
1950 CreateParams(views::Widget::InitParams::TYPE_POPUP
);
1951 widget
->Init(params
);
1953 widget
->SetContentsView(new CloseWidgetView(ui::ET_MOUSE_PRESSED
));
1955 widget
->SetSize(gfx::Size(100, 100));
1958 ui::test::EventGenerator
generator(GetContext(), widget
->GetNativeWindow());
1960 WidgetDeletionObserver
deletion_observer(widget
);
1961 generator
.ClickLeftButton();
1962 EXPECT_FALSE(deletion_observer
.IsWidgetAlive());
1964 // Yay we did not crash!
1967 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
1968 #if !defined(OS_MACOSX) || defined(USE_AURA)
1970 TEST_F(WidgetTest
, WidgetDeleted_InDispatchGestureEvent
) {
1971 Widget
* widget
= new Widget
;
1972 Widget::InitParams params
=
1973 CreateParams(views::Widget::InitParams::TYPE_POPUP
);
1974 widget
->Init(params
);
1976 widget
->SetContentsView(new CloseWidgetView(ui::ET_GESTURE_TAP_DOWN
));
1978 widget
->SetSize(gfx::Size(100, 100));
1981 ui::test::EventGenerator
generator(GetContext(), widget
->GetNativeWindow());
1983 WidgetDeletionObserver
deletion_observer(widget
);
1984 generator
.GestureTapAt(widget
->GetWindowBoundsInScreen().CenterPoint());
1985 EXPECT_FALSE(deletion_observer
.IsWidgetAlive());
1987 // Yay we did not crash!
1990 #endif // !defined(OS_MACOSX) || defined(USE_AURA)
1992 // See description of RunGetNativeThemeFromDestructor() for details.
1993 class GetNativeThemeFromDestructorView
: public WidgetDelegateView
{
1995 GetNativeThemeFromDestructorView() {}
1996 ~GetNativeThemeFromDestructorView() override
{ VerifyNativeTheme(); }
1998 View
* GetContentsView() override
{ return this; }
2001 void VerifyNativeTheme() {
2002 ASSERT_TRUE(GetNativeTheme() != NULL
);
2005 DISALLOW_COPY_AND_ASSIGN(GetNativeThemeFromDestructorView
);
2008 // Verifies GetNativeTheme() from the destructor of a WidgetDelegateView doesn't
2009 // crash. |is_first_run| is true if this is the first call. A return value of
2010 // true indicates this should be run again with a value of false.
2011 // First run uses DesktopNativeWidgetAura (if possible). Second run doesn't.
2012 bool RunGetNativeThemeFromDestructor(const Widget::InitParams
& in_params
,
2013 bool is_first_run
) {
2014 bool needs_second_run
= false;
2015 // Destroyed by CloseNow() below.
2016 Widget
* widget
= new Widget
;
2017 Widget::InitParams
params(in_params
);
2018 // Deletes itself when the Widget is destroyed.
2019 params
.delegate
= new GetNativeThemeFromDestructorView
;
2020 #if !defined(OS_CHROMEOS)
2022 params
.native_widget
= new PlatformDesktopNativeWidget(widget
);
2023 needs_second_run
= true;
2026 widget
->Init(params
);
2028 return needs_second_run
;
2031 // See description of RunGetNativeThemeFromDestructor() for details.
2032 TEST_F(WidgetTest
, GetNativeThemeFromDestructor
) {
2033 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
2034 if (RunGetNativeThemeFromDestructor(params
, true))
2035 RunGetNativeThemeFromDestructor(params
, false);
2038 // Used by HideCloseDestroy. Allows setting a boolean when the widget is
2040 class CloseDestroysWidget
: public Widget
{
2042 explicit CloseDestroysWidget(bool* destroyed
)
2043 : destroyed_(destroyed
) {
2046 ~CloseDestroysWidget() override
{
2049 base::MessageLoop::current()->QuitNow();
2053 void Detach() { destroyed_
= NULL
; }
2056 // If non-null set to true from destructor.
2059 DISALLOW_COPY_AND_ASSIGN(CloseDestroysWidget
);
2062 // An observer that registers that an animation has ended.
2063 class AnimationEndObserver
: public ui::ImplicitAnimationObserver
{
2065 AnimationEndObserver() : animation_completed_(false) {}
2066 ~AnimationEndObserver() override
{}
2068 bool animation_completed() const { return animation_completed_
; }
2070 // ui::ImplicitAnimationObserver:
2071 void OnImplicitAnimationsCompleted() override
{ animation_completed_
= true; }
2074 bool animation_completed_
;
2076 DISALLOW_COPY_AND_ASSIGN(AnimationEndObserver
);
2079 // An observer that registers the bounds of a widget on destruction.
2080 class WidgetBoundsObserver
: public WidgetObserver
{
2082 WidgetBoundsObserver() {}
2083 ~WidgetBoundsObserver() override
{}
2085 gfx::Rect
bounds() { return bounds_
; }
2088 void OnWidgetDestroying(Widget
* widget
) override
{
2089 bounds_
= widget
->GetWindowBoundsInScreen();
2095 DISALLOW_COPY_AND_ASSIGN(WidgetBoundsObserver
);
2098 // Verifies Close() results in destroying.
2099 TEST_F(WidgetTest
, CloseDestroys
) {
2100 bool destroyed
= false;
2101 CloseDestroysWidget
* widget
= new CloseDestroysWidget(&destroyed
);
2102 Widget::InitParams params
=
2103 CreateParams(views::Widget::InitParams::TYPE_MENU
);
2104 params
.opacity
= Widget::InitParams::OPAQUE_WINDOW
;
2105 #if !defined(OS_CHROMEOS)
2106 params
.native_widget
= new PlatformDesktopNativeWidget(widget
);
2108 widget
->Init(params
);
2112 EXPECT_FALSE(destroyed
);
2113 // Run the message loop as Close() asynchronously deletes.
2114 base::RunLoop().Run();
2115 EXPECT_TRUE(destroyed
);
2116 // Close() should destroy the widget. If not we'll cleanup to avoid leaks.
2123 // Tests that killing a widget while animating it does not crash.
2124 TEST_F(WidgetTest
, CloseWidgetWhileAnimating
) {
2125 scoped_ptr
<Widget
> widget(new Widget
);
2126 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
2127 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
2128 params
.bounds
= gfx::Rect(50, 50, 250, 250);
2129 widget
->Init(params
);
2130 AnimationEndObserver animation_observer
;
2131 WidgetBoundsObserver widget_observer
;
2132 gfx::Rect
bounds(0, 0, 50, 50);
2134 // Normal animations for tests have ZERO_DURATION, make sure we are actually
2135 // animating the movement.
2136 ui::ScopedAnimationDurationScaleMode
animation_scale_mode(
2137 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION
);
2138 ui::ScopedLayerAnimationSettings
animation_settings(
2139 widget
->GetLayer()->GetAnimator());
2140 animation_settings
.AddObserver(&animation_observer
);
2141 widget
->AddObserver(&widget_observer
);
2144 // Animate the bounds change.
2145 widget
->SetBounds(bounds
);
2147 EXPECT_FALSE(animation_observer
.animation_completed());
2149 EXPECT_TRUE(animation_observer
.animation_completed());
2150 EXPECT_EQ(widget_observer
.bounds(), bounds
);
2153 // Tests that we do not crash when a Widget is destroyed by going out of
2154 // scope (as opposed to being explicitly deleted by its NativeWidget).
2155 TEST_F(WidgetTest
, NoCrashOnWidgetDelete
) {
2156 scoped_ptr
<Widget
> widget(new Widget
);
2157 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
2158 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
2159 widget
->Init(params
);
2162 // Tests that we do not crash when a Widget is destroyed before it finishes
2163 // processing of pending input events in the message loop.
2164 TEST_F(WidgetTest
, NoCrashOnWidgetDeleteWithPendingEvents
) {
2165 scoped_ptr
<Widget
> widget(new Widget
);
2166 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_WINDOW
);
2167 params
.bounds
= gfx::Rect(0, 0, 200, 200);
2168 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
2169 widget
->Init(params
);
2172 ui::test::EventGenerator
generator(GetContext(), widget
->GetNativeWindow());
2173 generator
.MoveMouseTo(10, 10);
2175 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
2176 #if defined(OS_MACOSX) && !defined(USE_AURA)
2177 generator
.ClickLeftButton();
2179 generator
.PressTouch();
2184 // A view that consumes mouse-pressed event and gesture-tap-down events.
2185 class RootViewTestView
: public View
{
2187 RootViewTestView(): View() {}
2190 bool OnMousePressed(const ui::MouseEvent
& event
) override
{ return true; }
2192 void OnGestureEvent(ui::GestureEvent
* event
) override
{
2193 if (event
->type() == ui::ET_GESTURE_TAP_DOWN
)
2194 event
->SetHandled();
2198 // Checks if RootView::*_handler_ fields are unset when widget is hidden.
2199 // Fails on chromium.webkit Windows bot, see crbug.com/264872.
2201 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
2202 DISABLED_TestRootViewHandlersWhenHidden
2204 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
2205 TestRootViewHandlersWhenHidden
2207 TEST_F(WidgetTest
, MAYBE_DisableTestRootViewHandlersWhenHidden
) {
2208 Widget
* widget
= CreateTopLevelNativeWidget();
2209 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
2210 View
* view
= new RootViewTestView();
2211 view
->SetBounds(0, 0, 300, 300);
2212 internal::RootView
* root_view
=
2213 static_cast<internal::RootView
*>(widget
->GetRootView());
2214 root_view
->AddChildView(view
);
2216 // Check RootView::mouse_pressed_handler_.
2218 EXPECT_EQ(NULL
, GetMousePressedHandler(root_view
));
2219 gfx::Point
click_location(45, 15);
2220 ui::MouseEvent
press(ui::ET_MOUSE_PRESSED
, click_location
, click_location
,
2221 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON
,
2222 ui::EF_LEFT_MOUSE_BUTTON
);
2223 widget
->OnMouseEvent(&press
);
2224 EXPECT_EQ(view
, GetMousePressedHandler(root_view
));
2226 EXPECT_EQ(NULL
, GetMousePressedHandler(root_view
));
2228 // Check RootView::mouse_move_handler_.
2230 EXPECT_EQ(NULL
, GetMouseMoveHandler(root_view
));
2231 gfx::Point
move_location(45, 15);
2232 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
, move_location
, move_location
,
2233 ui::EventTimeForNow(), 0, 0);
2234 widget
->OnMouseEvent(&move
);
2235 EXPECT_EQ(view
, GetMouseMoveHandler(root_view
));
2237 EXPECT_EQ(NULL
, GetMouseMoveHandler(root_view
));
2239 // Check RootView::gesture_handler_.
2241 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2242 ui::GestureEvent
tap_down(15,
2246 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN
));
2247 widget
->OnGestureEvent(&tap_down
);
2248 EXPECT_EQ(view
, GetGestureHandler(root_view
));
2250 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2255 // Convenience to make constructing a GestureEvent simpler.
2256 class GestureEventForTest
: public ui::GestureEvent
{
2258 GestureEventForTest(ui::EventType type
, int x
, int y
)
2263 ui::GestureEventDetails(type
)) {}
2265 GestureEventForTest(ui::GestureEventDetails details
, int x
, int y
)
2266 : GestureEvent(x
, y
, 0, base::TimeDelta(), details
) {}
2269 // Tests that the |gesture_handler_| member in RootView is always NULL
2270 // after the dispatch of a ui::ET_GESTURE_END event corresponding to
2271 // the release of the final touch point on the screen, but that
2272 // ui::ET_GESTURE_END events corresponding to the removal of any other touch
2273 // point do not modify |gesture_handler_|.
2274 TEST_F(WidgetTest
, GestureEndEvents
) {
2275 Widget
* widget
= CreateTopLevelNativeWidget();
2276 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
2277 EventCountView
* view
= new EventCountView();
2278 view
->SetBounds(0, 0, 300, 300);
2279 internal::RootView
* root_view
=
2280 static_cast<internal::RootView
*>(widget
->GetRootView());
2281 root_view
->AddChildView(view
);
2284 // If no gesture handler is set, a ui::ET_GESTURE_END event should not set
2285 // the gesture handler.
2286 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2287 GestureEventForTest
end(ui::ET_GESTURE_END
, 15, 15);
2288 widget
->OnGestureEvent(&end
);
2289 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2291 // Change the handle mode of |view| to indicate that it would like
2292 // to handle all events, then send a GESTURE_TAP to set the gesture handler.
2293 view
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2294 GestureEventForTest
tap(ui::ET_GESTURE_TAP
, 15, 15);
2295 widget
->OnGestureEvent(&tap
);
2296 EXPECT_TRUE(tap
.handled());
2297 EXPECT_EQ(view
, GetGestureHandler(root_view
));
2299 // The gesture handler should remain unchanged on a ui::ET_GESTURE_END
2300 // corresponding to a second touch point, but should be reset to NULL by a
2301 // ui::ET_GESTURE_END corresponding to the final touch point.
2302 ui::GestureEventDetails
details(ui::ET_GESTURE_END
);
2303 details
.set_touch_points(2);
2304 GestureEventForTest
end_second_touch_point(details
, 15, 15);
2305 widget
->OnGestureEvent(&end_second_touch_point
);
2306 EXPECT_EQ(view
, GetGestureHandler(root_view
));
2308 end
= GestureEventForTest(ui::ET_GESTURE_END
, 15, 15);
2309 widget
->OnGestureEvent(&end
);
2310 EXPECT_TRUE(end
.handled());
2311 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2313 // Send a GESTURE_TAP to set the gesture handler, then change the handle
2314 // mode of |view| to indicate that it does not want to handle any
2316 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 15, 15);
2317 widget
->OnGestureEvent(&tap
);
2318 EXPECT_TRUE(tap
.handled());
2319 EXPECT_EQ(view
, GetGestureHandler(root_view
));
2320 view
->set_handle_mode(EventCountView::PROPAGATE_EVENTS
);
2322 // The gesture handler should remain unchanged on a ui::ET_GESTURE_END
2323 // corresponding to a second touch point, but should be reset to NULL by a
2324 // ui::ET_GESTURE_END corresponding to the final touch point.
2325 end_second_touch_point
= GestureEventForTest(details
, 15, 15);
2326 widget
->OnGestureEvent(&end_second_touch_point
);
2327 EXPECT_EQ(view
, GetGestureHandler(root_view
));
2329 end
= GestureEventForTest(ui::ET_GESTURE_END
, 15, 15);
2330 widget
->OnGestureEvent(&end
);
2331 EXPECT_FALSE(end
.handled());
2332 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2337 // Tests that gesture events which should not be processed (because
2338 // RootView::OnEventProcessingStarted() has marked them as handled) are not
2339 // dispatched to any views.
2340 TEST_F(WidgetTest
, GestureEventsNotProcessed
) {
2341 Widget
* widget
= CreateTopLevelNativeWidget();
2342 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
2344 // Define a hierarchy of four views (coordinates are in
2345 // their parent coordinate space).
2346 // v1 (0, 0, 300, 300)
2347 // v2 (0, 0, 100, 100)
2348 // v3 (0, 0, 50, 50)
2350 EventCountView
* v1
= new EventCountView();
2351 v1
->SetBounds(0, 0, 300, 300);
2352 EventCountView
* v2
= new EventCountView();
2353 v2
->SetBounds(0, 0, 100, 100);
2354 EventCountView
* v3
= new EventCountView();
2355 v3
->SetBounds(0, 0, 50, 50);
2356 EventCountView
* v4
= new EventCountView();
2357 v4
->SetBounds(0, 0, 10, 10);
2358 internal::RootView
* root_view
=
2359 static_cast<internal::RootView
*>(widget
->GetRootView());
2360 root_view
->AddChildView(v1
);
2361 v1
->AddChildView(v2
);
2362 v2
->AddChildView(v3
);
2363 v3
->AddChildView(v4
);
2367 // ui::ET_GESTURE_BEGIN events should never be seen by any view, but
2368 // they should be marked as handled by OnEventProcessingStarted().
2369 GestureEventForTest
begin(ui::ET_GESTURE_BEGIN
, 5, 5);
2370 widget
->OnGestureEvent(&begin
);
2371 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_BEGIN
));
2372 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_BEGIN
));
2373 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_BEGIN
));
2374 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_BEGIN
));
2375 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2376 EXPECT_TRUE(begin
.handled());
2382 // ui::ET_GESTURE_END events should not be seen by any view when there is
2383 // no default gesture handler set, but they should be marked as handled by
2384 // OnEventProcessingStarted().
2385 GestureEventForTest
end(ui::ET_GESTURE_END
, 5, 5);
2386 widget
->OnGestureEvent(&end
);
2387 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_END
));
2388 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_END
));
2389 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_END
));
2390 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_END
));
2391 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2392 EXPECT_TRUE(end
.handled());
2398 // ui::ET_GESTURE_END events not corresponding to the release of the
2399 // final touch point should never be seen by any view, but they should
2400 // be marked as handled by OnEventProcessingStarted().
2401 ui::GestureEventDetails
details(ui::ET_GESTURE_END
);
2402 details
.set_touch_points(2);
2403 GestureEventForTest
end_second_touch_point(details
, 5, 5);
2404 widget
->OnGestureEvent(&end_second_touch_point
);
2405 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_END
));
2406 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_END
));
2407 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_END
));
2408 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_END
));
2409 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2410 EXPECT_TRUE(end_second_touch_point
.handled());
2416 // ui::ET_GESTURE_SCROLL_UPDATE events should never be seen by any view when
2417 // there is no default gesture handler set, but they should be marked as
2418 // handled by OnEventProcessingStarted().
2419 GestureEventForTest
scroll_update(ui::ET_GESTURE_SCROLL_UPDATE
, 5, 5);
2420 widget
->OnGestureEvent(&scroll_update
);
2421 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2422 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2423 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2424 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2425 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2426 EXPECT_TRUE(scroll_update
.handled());
2432 // ui::ET_GESTURE_SCROLL_END events should never be seen by any view when
2433 // there is no default gesture handler set, but they should be marked as
2434 // handled by OnEventProcessingStarted().
2435 GestureEventForTest
scroll_end(ui::ET_GESTURE_SCROLL_END
, 5, 5);
2436 widget
->OnGestureEvent(&scroll_end
);
2437 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2438 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2439 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2440 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2441 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2442 EXPECT_TRUE(scroll_end
.handled());
2448 // ui::ET_SCROLL_FLING_START events should never be seen by any view when
2449 // there is no default gesture handler set, but they should be marked as
2450 // handled by OnEventProcessingStarted().
2451 GestureEventForTest
scroll_fling_start(ui::ET_SCROLL_FLING_START
, 5, 5);
2452 widget
->OnGestureEvent(&scroll_fling_start
);
2453 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_SCROLL_FLING_START
));
2454 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_SCROLL_FLING_START
));
2455 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_SCROLL_FLING_START
));
2456 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_SCROLL_FLING_START
));
2457 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2458 EXPECT_TRUE(scroll_fling_start
.handled());
2467 // Tests that a (non-scroll) gesture event is dispatched to the correct views
2468 // in a view hierarchy and that the default gesture handler in RootView is set
2470 TEST_F(WidgetTest
, GestureEventDispatch
) {
2471 Widget
* widget
= CreateTopLevelNativeWidget();
2472 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
2474 // Define a hierarchy of four views (coordinates are in
2475 // their parent coordinate space).
2476 // v1 (0, 0, 300, 300)
2477 // v2 (0, 0, 100, 100)
2478 // v3 (0, 0, 50, 50)
2480 EventCountView
* v1
= new EventCountView();
2481 v1
->SetBounds(0, 0, 300, 300);
2482 EventCountView
* v2
= new EventCountView();
2483 v2
->SetBounds(0, 0, 100, 100);
2484 EventCountView
* v3
= new EventCountView();
2485 v3
->SetBounds(0, 0, 50, 50);
2486 EventCountView
* v4
= new EventCountView();
2487 v4
->SetBounds(0, 0, 10, 10);
2488 internal::RootView
* root_view
=
2489 static_cast<internal::RootView
*>(widget
->GetRootView());
2490 root_view
->AddChildView(v1
);
2491 v1
->AddChildView(v2
);
2492 v2
->AddChildView(v3
);
2493 v3
->AddChildView(v4
);
2497 // No gesture handler is set in the root view and none of the views in the
2498 // view hierarchy handle a ui::ET_GESTURE_TAP event. In this case the tap
2499 // event should be dispatched to all views in the hierarchy, the gesture
2500 // handler should remain unset, and the event should remain unhandled.
2501 GestureEventForTest
tap(ui::ET_GESTURE_TAP
, 5, 5);
2502 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2503 widget
->OnGestureEvent(&tap
);
2504 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2505 EXPECT_EQ(1, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2506 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2507 EXPECT_EQ(1, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2508 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2509 EXPECT_FALSE(tap
.handled());
2511 // No gesture handler is set in the root view and |v1|, |v2|, and |v3| all
2512 // handle a ui::ET_GESTURE_TAP event. In this case the tap event should be
2513 // dispatched to |v4| and |v3|, the gesture handler should be set to |v3|,
2514 // and the event should be marked as handled.
2519 v1
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2520 v2
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2521 v3
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2522 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2523 widget
->OnGestureEvent(&tap
);
2524 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2525 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2526 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2527 EXPECT_EQ(1, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2528 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2529 EXPECT_TRUE(tap
.handled());
2531 // The gesture handler is set to |v3| and all views handle all gesture event
2532 // types. In this case subsequent gesture events should only be dispatched to
2533 // |v3| and marked as handled. The gesture handler should remain as |v3|.
2538 v4
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2539 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2540 widget
->OnGestureEvent(&tap
);
2541 EXPECT_TRUE(tap
.handled());
2542 GestureEventForTest
show_press(ui::ET_GESTURE_SHOW_PRESS
, 5, 5);
2543 widget
->OnGestureEvent(&show_press
);
2544 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2545 widget
->OnGestureEvent(&tap
);
2546 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2547 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2548 EXPECT_EQ(2, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2549 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2550 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_SHOW_PRESS
));
2551 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_SHOW_PRESS
));
2552 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_SHOW_PRESS
));
2553 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_SHOW_PRESS
));
2554 EXPECT_TRUE(tap
.handled());
2555 EXPECT_TRUE(show_press
.handled());
2556 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2558 // The gesture handler is set to |v3|, but |v3| does not handle
2559 // ui::ET_GESTURE_TAP events. In this case a tap gesture should be dispatched
2560 // only to |v3|, but the event should remain unhandled. The gesture handler
2561 // should remain as |v3|.
2566 v3
->set_handle_mode(EventCountView::PROPAGATE_EVENTS
);
2567 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2568 widget
->OnGestureEvent(&tap
);
2569 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2570 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2571 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2572 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2573 EXPECT_FALSE(tap
.handled());
2574 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2579 // Tests that gesture scroll events will change the default gesture handler in
2580 // RootView if the current handler to which they are dispatched does not handle
2581 // gesture scroll events.
2582 TEST_F(WidgetTest
, ScrollGestureEventDispatch
) {
2583 Widget
* widget
= CreateTopLevelNativeWidget();
2584 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
2586 // Define a hierarchy of four views (coordinates are in
2587 // their parent coordinate space).
2588 // v1 (0, 0, 300, 300)
2589 // v2 (0, 0, 100, 100)
2590 // v3 (0, 0, 50, 50)
2592 EventCountView
* v1
= new EventCountView();
2593 v1
->SetBounds(0, 0, 300, 300);
2594 EventCountView
* v2
= new EventCountView();
2595 v2
->SetBounds(0, 0, 100, 100);
2596 EventCountView
* v3
= new EventCountView();
2597 v3
->SetBounds(0, 0, 50, 50);
2598 EventCountView
* v4
= new EventCountView();
2599 v4
->SetBounds(0, 0, 10, 10);
2600 internal::RootView
* root_view
=
2601 static_cast<internal::RootView
*>(widget
->GetRootView());
2602 root_view
->AddChildView(v1
);
2603 v1
->AddChildView(v2
);
2604 v2
->AddChildView(v3
);
2605 v3
->AddChildView(v4
);
2609 // Change the handle mode of |v3| to indicate that it would like to handle
2611 v3
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2613 // When no gesture handler is set, dispatching a ui::ET_GESTURE_TAP_DOWN
2614 // should bubble up the views hierarchy until it reaches the first view
2615 // that will handle it (|v3|) and then sets the handler to |v3|.
2616 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2617 GestureEventForTest
tap_down(ui::ET_GESTURE_TAP_DOWN
, 5, 5);
2618 widget
->OnGestureEvent(&tap_down
);
2619 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
2620 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
2621 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
2622 EXPECT_EQ(1, v4
->GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
2623 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2624 EXPECT_TRUE(tap_down
.handled());
2630 // A ui::ET_GESTURE_TAP_CANCEL event should be dispatched to |v3| directly.
2631 GestureEventForTest
tap_cancel(ui::ET_GESTURE_TAP_CANCEL
, 5, 5);
2632 widget
->OnGestureEvent(&tap_cancel
);
2633 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
2634 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
2635 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
2636 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
2637 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2638 EXPECT_TRUE(tap_cancel
.handled());
2644 // Change the handle mode of |v3| to indicate that it would no longer like
2645 // to handle events, and change the mode of |v1| to indicate that it would
2646 // like to handle events.
2647 v3
->set_handle_mode(EventCountView::PROPAGATE_EVENTS
);
2648 v1
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2650 // Dispatch a ui::ET_GESTURE_SCROLL_BEGIN event. Because the current gesture
2651 // handler (|v3|) does not handle scroll events, the event should bubble up
2652 // the views hierarchy until it reaches the first view that will handle
2653 // it (|v1|) and then sets the handler to |v1|.
2654 GestureEventForTest
scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN
, 5, 5);
2655 widget
->OnGestureEvent(&scroll_begin
);
2656 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
2657 EXPECT_EQ(1, v2
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
2658 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
2659 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
2660 EXPECT_EQ(v1
, GetGestureHandler(root_view
));
2661 EXPECT_TRUE(scroll_begin
.handled());
2667 // A ui::ET_GESTURE_SCROLL_UPDATE event should be dispatched to |v1|
2669 GestureEventForTest
scroll_update(ui::ET_GESTURE_SCROLL_UPDATE
, 5, 5);
2670 widget
->OnGestureEvent(&scroll_update
);
2671 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2672 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2673 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2674 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2675 EXPECT_EQ(v1
, GetGestureHandler(root_view
));
2676 EXPECT_TRUE(scroll_update
.handled());
2682 // A ui::ET_GESTURE_SCROLL_END event should be dispatched to |v1|
2683 // directly and should not reset the gesture handler.
2684 GestureEventForTest
scroll_end(ui::ET_GESTURE_SCROLL_END
, 5, 5);
2685 widget
->OnGestureEvent(&scroll_end
);
2686 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2687 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2688 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2689 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2690 EXPECT_EQ(v1
, GetGestureHandler(root_view
));
2691 EXPECT_TRUE(scroll_end
.handled());
2697 // A ui::ET_GESTURE_PINCH_BEGIN event (which is a non-scroll event) should
2698 // still be dispatched to |v1| directly.
2699 GestureEventForTest
pinch_begin(ui::ET_GESTURE_PINCH_BEGIN
, 5, 5);
2700 widget
->OnGestureEvent(&pinch_begin
);
2701 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN
));
2702 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN
));
2703 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN
));
2704 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN
));
2705 EXPECT_EQ(v1
, GetGestureHandler(root_view
));
2706 EXPECT_TRUE(pinch_begin
.handled());
2712 // A ui::ET_GESTURE_END event should be dispatched to |v1| and should
2713 // set the gesture handler to NULL.
2714 GestureEventForTest
end(ui::ET_GESTURE_END
, 5, 5);
2715 widget
->OnGestureEvent(&end
);
2716 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_END
));
2717 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_END
));
2718 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_END
));
2719 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_END
));
2720 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2721 EXPECT_TRUE(end
.handled());
2726 // A class used in WidgetTest.GestureEventLocationWhileBubbling to verify
2727 // that when a gesture event bubbles up a View hierarchy, the location
2728 // of a gesture event seen by each View is in the local coordinate space
2730 class GestureLocationView
: public EventCountView
{
2732 GestureLocationView() {}
2733 ~GestureLocationView() override
{}
2735 void set_expected_location(gfx::Point expected_location
) {
2736 expected_location_
= expected_location
;
2740 void OnGestureEvent(ui::GestureEvent
* event
) override
{
2741 EventCountView::OnGestureEvent(event
);
2743 // Verify that the location of |event| is in the local coordinate
2745 EXPECT_EQ(expected_location_
, event
->location());
2749 // The expected location of a gesture event dispatched to |this|.
2750 gfx::Point expected_location_
;
2752 DISALLOW_COPY_AND_ASSIGN(GestureLocationView
);
2755 // Verifies that the location of a gesture event is always in the local
2756 // coordinate space of the View receiving the event while bubbling.
2757 TEST_F(WidgetTest
, GestureEventLocationWhileBubbling
) {
2758 Widget
* widget
= CreateTopLevelNativeWidget();
2759 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
2761 // Define a hierarchy of three views (coordinates shown below are in the
2762 // coordinate space of the root view, but the coordinates used for
2763 // SetBounds() are in their parent coordinate space).
2764 // v1 (50, 50, 150, 150)
2765 // v2 (100, 70, 50, 80)
2766 // v3 (120, 100, 10, 10)
2767 GestureLocationView
* v1
= new GestureLocationView();
2768 v1
->SetBounds(50, 50, 150, 150);
2769 GestureLocationView
* v2
= new GestureLocationView();
2770 v2
->SetBounds(50, 20, 50, 80);
2771 GestureLocationView
* v3
= new GestureLocationView();
2772 v3
->SetBounds(20, 30, 10, 10);
2773 internal::RootView
* root_view
=
2774 static_cast<internal::RootView
*>(widget
->GetRootView());
2775 root_view
->AddChildView(v1
);
2776 v1
->AddChildView(v2
);
2777 v2
->AddChildView(v3
);
2781 // Define a GESTURE_TAP event located at (125, 105) in root view coordinates.
2782 // This event is contained within all of |v1|, |v2|, and |v3|.
2783 gfx::Point
location_in_root(125, 105);
2784 GestureEventForTest
tap(
2785 ui::ET_GESTURE_TAP
, location_in_root
.x(), location_in_root
.y());
2787 // Calculate the location of the event in the local coordinate spaces
2788 // of each of the views.
2789 gfx::Point
location_in_v1(ConvertPointFromWidgetToView(v1
, location_in_root
));
2790 EXPECT_EQ(gfx::Point(75, 55), location_in_v1
);
2791 gfx::Point
location_in_v2(ConvertPointFromWidgetToView(v2
, location_in_root
));
2792 EXPECT_EQ(gfx::Point(25, 35), location_in_v2
);
2793 gfx::Point
location_in_v3(ConvertPointFromWidgetToView(v3
, location_in_root
));
2794 EXPECT_EQ(gfx::Point(5, 5), location_in_v3
);
2796 // Dispatch the event. When each view receives the event, its location should
2797 // be in the local coordinate space of that view (see the check made by
2798 // GestureLocationView). After dispatch is complete the event's location
2799 // should be in the root coordinate space.
2800 v1
->set_expected_location(location_in_v1
);
2801 v2
->set_expected_location(location_in_v2
);
2802 v3
->set_expected_location(location_in_v3
);
2803 widget
->OnGestureEvent(&tap
);
2804 EXPECT_EQ(location_in_root
, tap
.location());
2806 // Verify that each view did in fact see the event.
2807 EventCountView
* view1
= v1
;
2808 EventCountView
* view2
= v2
;
2809 EventCountView
* view3
= v3
;
2810 EXPECT_EQ(1, view1
->GetEventCount(ui::ET_GESTURE_TAP
));
2811 EXPECT_EQ(1, view2
->GetEventCount(ui::ET_GESTURE_TAP
));
2812 EXPECT_EQ(1, view3
->GetEventCount(ui::ET_GESTURE_TAP
));
2817 // Verifies that disabled views are permitted to be set as the default gesture
2818 // handler in RootView. Also verifies that gesture events targeted to a disabled
2819 // view are not actually dispatched to the view, but are still marked as
2821 TEST_F(WidgetTest
, DisabledGestureEventTarget
) {
2822 Widget
* widget
= CreateTopLevelNativeWidget();
2823 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
2825 // Define a hierarchy of four views (coordinates are in
2826 // their parent coordinate space).
2827 // v1 (0, 0, 300, 300)
2828 // v2 (0, 0, 100, 100)
2829 // v3 (0, 0, 50, 50)
2831 EventCountView
* v1
= new EventCountView();
2832 v1
->SetBounds(0, 0, 300, 300);
2833 EventCountView
* v2
= new EventCountView();
2834 v2
->SetBounds(0, 0, 100, 100);
2835 EventCountView
* v3
= new EventCountView();
2836 v3
->SetBounds(0, 0, 50, 50);
2837 EventCountView
* v4
= new EventCountView();
2838 v4
->SetBounds(0, 0, 10, 10);
2839 internal::RootView
* root_view
=
2840 static_cast<internal::RootView
*>(widget
->GetRootView());
2841 root_view
->AddChildView(v1
);
2842 v1
->AddChildView(v2
);
2843 v2
->AddChildView(v3
);
2844 v3
->AddChildView(v4
);
2848 // |v1|, |v2|, and |v3| all handle gesture events but |v3| is marked as
2850 v1
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2851 v2
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2852 v3
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2853 v3
->SetEnabled(false);
2855 // No gesture handler is set in the root view. In this case the tap event
2856 // should be dispatched only to |v4|, the gesture handler should be set to
2857 // |v3|, and the event should be marked as handled.
2858 GestureEventForTest
tap(ui::ET_GESTURE_TAP
, 5, 5);
2859 widget
->OnGestureEvent(&tap
);
2860 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2861 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2862 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2863 EXPECT_EQ(1, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2864 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2865 EXPECT_TRUE(tap
.handled());
2871 // A subsequent gesture event should be marked as handled but not dispatched.
2872 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2873 widget
->OnGestureEvent(&tap
);
2874 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2875 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2876 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2877 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2878 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2879 EXPECT_TRUE(tap
.handled());
2885 // A GESTURE_END should reset the default gesture handler to NULL. It should
2886 // also not be dispatched to |v3| but still marked as handled.
2887 GestureEventForTest
end(ui::ET_GESTURE_END
, 5, 5);
2888 widget
->OnGestureEvent(&end
);
2889 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_END
));
2890 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_END
));
2891 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_END
));
2892 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_END
));
2893 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2894 EXPECT_TRUE(end
.handled());
2900 // Change the handle mode of |v3| to indicate that it would no longer like
2901 // to handle events which are dispatched to it.
2902 v3
->set_handle_mode(EventCountView::PROPAGATE_EVENTS
);
2904 // No gesture handler is set in the root view. In this case the tap event
2905 // should be dispatched only to |v4| and the event should be marked as
2906 // handled. Furthermore, the gesture handler should be set to
2907 // |v3|; even though |v3| does not explicitly handle events, it is a
2908 // valid target for the tap event because it is disabled.
2909 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2910 widget
->OnGestureEvent(&tap
);
2911 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2912 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2913 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2914 EXPECT_EQ(1, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2915 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2916 EXPECT_TRUE(tap
.handled());
2922 // A GESTURE_END should reset the default gesture handler to NULL. It should
2923 // also not be dispatched to |v3| but still marked as handled.
2924 end
= GestureEventForTest(ui::ET_GESTURE_END
, 5, 5);
2925 widget
->OnGestureEvent(&end
);
2926 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_END
));
2927 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_END
));
2928 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_END
));
2929 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_END
));
2930 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2931 EXPECT_TRUE(end
.handled());
2936 // Test the result of Widget::GetAllChildWidgets().
2937 TEST_F(WidgetTest
, GetAllChildWidgets
) {
2938 // Create the following widget hierarchy:
2946 Widget
* toplevel
= CreateTopLevelPlatformWidget();
2947 Widget
* w1
= CreateChildPlatformWidget(toplevel
->GetNativeView());
2948 Widget
* w11
= CreateChildPlatformWidget(w1
->GetNativeView());
2949 Widget
* w2
= CreateChildPlatformWidget(toplevel
->GetNativeView());
2950 Widget
* w21
= CreateChildPlatformWidget(w2
->GetNativeView());
2951 Widget
* w22
= CreateChildPlatformWidget(w2
->GetNativeView());
2953 std::set
<Widget
*> expected
;
2954 expected
.insert(toplevel
);
2955 expected
.insert(w1
);
2956 expected
.insert(w11
);
2957 expected
.insert(w2
);
2958 expected
.insert(w21
);
2959 expected
.insert(w22
);
2961 std::set
<Widget
*> widgets
;
2962 Widget::GetAllChildWidgets(toplevel
->GetNativeView(), &widgets
);
2964 EXPECT_EQ(expected
.size(), widgets
.size());
2965 EXPECT_TRUE(std::equal(expected
.begin(), expected
.end(), widgets
.begin()));
2968 // Used by DestroyChildWidgetsInOrder. On destruction adds the supplied name to
2970 class DestroyedTrackingView
: public View
{
2972 DestroyedTrackingView(const std::string
& name
,
2973 std::vector
<std::string
>* add_to
)
2978 ~DestroyedTrackingView() override
{ add_to_
->push_back(name_
); }
2981 const std::string name_
;
2982 std::vector
<std::string
>* add_to_
;
2984 DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingView
);
2987 class WidgetChildDestructionTest
: public WidgetTest
{
2989 WidgetChildDestructionTest() {}
2991 // Creates a top level and a child, destroys the child and verifies the views
2992 // of the child are destroyed before the views of the parent.
2993 void RunDestroyChildWidgetsTest(bool top_level_has_desktop_native_widget_aura
,
2994 bool child_has_desktop_native_widget_aura
) {
2995 // When a View is destroyed its name is added here.
2996 std::vector
<std::string
> destroyed
;
2998 Widget
* top_level
= new Widget
;
2999 Widget::InitParams params
=
3000 CreateParams(views::Widget::InitParams::TYPE_WINDOW
);
3001 #if !defined(OS_CHROMEOS)
3002 if (top_level_has_desktop_native_widget_aura
)
3003 params
.native_widget
= new PlatformDesktopNativeWidget(top_level
);
3005 top_level
->Init(params
);
3006 top_level
->GetRootView()->AddChildView(
3007 new DestroyedTrackingView("parent", &destroyed
));
3010 Widget
* child
= new Widget
;
3011 Widget::InitParams child_params
=
3012 CreateParams(views::Widget::InitParams::TYPE_POPUP
);
3013 child_params
.parent
= top_level
->GetNativeView();
3014 #if !defined(OS_CHROMEOS)
3015 if (child_has_desktop_native_widget_aura
)
3016 child_params
.native_widget
= new PlatformDesktopNativeWidget(child
);
3018 child
->Init(child_params
);
3019 child
->GetRootView()->AddChildView(
3020 new DestroyedTrackingView("child", &destroyed
));
3023 // Should trigger destruction of the child too.
3024 top_level
->native_widget_private()->CloseNow();
3026 // Child should be destroyed first.
3027 ASSERT_EQ(2u, destroyed
.size());
3028 EXPECT_EQ("child", destroyed
[0]);
3029 EXPECT_EQ("parent", destroyed
[1]);
3033 DISALLOW_COPY_AND_ASSIGN(WidgetChildDestructionTest
);
3036 #if !defined(OS_CHROMEOS)
3037 // See description of RunDestroyChildWidgetsTest(). Parent uses
3038 // DesktopNativeWidgetAura.
3039 TEST_F(WidgetChildDestructionTest
,
3040 DestroyChildWidgetsInOrderWithDesktopNativeWidget
) {
3041 RunDestroyChildWidgetsTest(true, false);
3044 // See description of RunDestroyChildWidgetsTest(). Both parent and child use
3045 // DesktopNativeWidgetAura.
3046 TEST_F(WidgetChildDestructionTest
,
3047 DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth
) {
3048 RunDestroyChildWidgetsTest(true, true);
3050 #endif // !defined(OS_CHROMEOS)
3052 // See description of RunDestroyChildWidgetsTest().
3053 TEST_F(WidgetChildDestructionTest
, DestroyChildWidgetsInOrder
) {
3054 RunDestroyChildWidgetsTest(false, false);
3057 #if !defined(OS_CHROMEOS)
3058 // Provides functionality to create a window modal dialog.
3059 class ModalDialogDelegate
: public DialogDelegateView
{
3061 ModalDialogDelegate() {}
3062 ~ModalDialogDelegate() override
{}
3064 // WidgetDelegate overrides.
3065 ui::ModalType
GetModalType() const override
{ return ui::MODAL_TYPE_WINDOW
; }
3068 DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate
);
3071 // This test verifies that whether mouse events when a modal dialog is
3072 // displayed are eaten or recieved by the dialog.
3073 TEST_F(WidgetTest
, WindowMouseModalityTest
) {
3074 // Create a top level widget.
3075 Widget top_level_widget
;
3076 Widget::InitParams init_params
=
3077 CreateParams(Widget::InitParams::TYPE_WINDOW
);
3078 init_params
.show_state
= ui::SHOW_STATE_NORMAL
;
3079 gfx::Rect
initial_bounds(0, 0, 500, 500);
3080 init_params
.bounds
= initial_bounds
;
3081 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
3082 init_params
.native_widget
=
3083 new PlatformDesktopNativeWidget(&top_level_widget
);
3084 top_level_widget
.Init(init_params
);
3085 top_level_widget
.Show();
3086 EXPECT_TRUE(top_level_widget
.IsVisible());
3088 // Create a view and validate that a mouse moves makes it to the view.
3089 EventCountView
* widget_view
= new EventCountView();
3090 widget_view
->SetBounds(0, 0, 10, 10);
3091 top_level_widget
.GetRootView()->AddChildView(widget_view
);
3093 gfx::Point
cursor_location_main(5, 5);
3094 ui::MouseEvent
move_main(ui::ET_MOUSE_MOVED
, cursor_location_main
,
3095 cursor_location_main
, ui::EventTimeForNow(),
3096 ui::EF_NONE
, ui::EF_NONE
);
3097 ui::EventDispatchDetails details
=
3098 GetEventProcessor(&top_level_widget
)->OnEventFromSource(&move_main
);
3099 ASSERT_FALSE(details
.dispatcher_destroyed
);
3101 EXPECT_EQ(1, widget_view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
3102 widget_view
->ResetCounts();
3104 // Create a modal dialog and validate that a mouse down message makes it to
3105 // the main view within the dialog.
3107 // This instance will be destroyed when the dialog is destroyed.
3108 ModalDialogDelegate
* dialog_delegate
= new ModalDialogDelegate
;
3110 Widget
* modal_dialog_widget
= views::DialogDelegate::CreateDialogWidget(
3111 dialog_delegate
, NULL
, top_level_widget
.GetNativeView());
3112 modal_dialog_widget
->SetBounds(gfx::Rect(100, 100, 200, 200));
3113 EventCountView
* dialog_widget_view
= new EventCountView();
3114 dialog_widget_view
->SetBounds(0, 0, 50, 50);
3115 modal_dialog_widget
->GetRootView()->AddChildView(dialog_widget_view
);
3116 modal_dialog_widget
->Show();
3117 EXPECT_TRUE(modal_dialog_widget
->IsVisible());
3119 gfx::Point
cursor_location_dialog(100, 100);
3120 ui::MouseEvent
mouse_down_dialog(
3121 ui::ET_MOUSE_PRESSED
, cursor_location_dialog
, cursor_location_dialog
,
3122 ui::EventTimeForNow(), ui::EF_NONE
, ui::EF_NONE
);
3123 details
= GetEventProcessor(&top_level_widget
)->OnEventFromSource(
3124 &mouse_down_dialog
);
3125 ASSERT_FALSE(details
.dispatcher_destroyed
);
3126 EXPECT_EQ(1, dialog_widget_view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
3128 // Send a mouse move message to the main window. It should not be received by
3129 // the main window as the modal dialog is still active.
3130 gfx::Point
cursor_location_main2(6, 6);
3131 ui::MouseEvent
mouse_down_main(ui::ET_MOUSE_MOVED
, cursor_location_main2
,
3132 cursor_location_main2
, ui::EventTimeForNow(),
3133 ui::EF_NONE
, ui::EF_NONE
);
3134 details
= GetEventProcessor(&top_level_widget
)->OnEventFromSource(
3136 ASSERT_FALSE(details
.dispatcher_destroyed
);
3137 EXPECT_EQ(0, widget_view
->GetEventCount(ui::ET_MOUSE_MOVED
));
3139 modal_dialog_widget
->CloseNow();
3140 top_level_widget
.CloseNow();
3143 // Verifies nativeview visbility matches that of Widget visibility when
3144 // SetFullscreen is invoked.
3145 TEST_F(WidgetTest
, FullscreenStatePropagated
) {
3146 Widget::InitParams init_params
=
3147 CreateParams(Widget::InitParams::TYPE_WINDOW
);
3148 init_params
.show_state
= ui::SHOW_STATE_NORMAL
;
3149 init_params
.bounds
= gfx::Rect(0, 0, 500, 500);
3150 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
3153 Widget top_level_widget
;
3154 top_level_widget
.Init(init_params
);
3155 top_level_widget
.SetFullscreen(true);
3156 EXPECT_EQ(top_level_widget
.IsVisible(),
3157 IsNativeWindowVisible(top_level_widget
.GetNativeWindow()));
3158 top_level_widget
.CloseNow();
3160 #if !defined(OS_CHROMEOS)
3162 Widget top_level_widget
;
3163 init_params
.native_widget
=
3164 new PlatformDesktopNativeWidget(&top_level_widget
);
3165 top_level_widget
.Init(init_params
);
3166 top_level_widget
.SetFullscreen(true);
3167 EXPECT_EQ(top_level_widget
.IsVisible(),
3168 IsNativeWindowVisible(top_level_widget
.GetNativeWindow()));
3169 top_level_widget
.CloseNow();
3175 // Tests whether we can activate the top level widget when a modal dialog is
3177 TEST_F(WidgetTest
, WindowModalityActivationTest
) {
3178 TestDesktopWidgetDelegate widget_delegate
;
3179 widget_delegate
.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW
));
3181 Widget
* top_level_widget
= widget_delegate
.GetWidget();
3182 top_level_widget
->Show();
3183 EXPECT_TRUE(top_level_widget
->IsVisible());
3185 HWND win32_window
= views::HWNDForWidget(top_level_widget
);
3186 EXPECT_TRUE(::IsWindow(win32_window
));
3188 // This instance will be destroyed when the dialog is destroyed.
3189 ModalDialogDelegate
* dialog_delegate
= new ModalDialogDelegate
;
3191 // We should be able to activate the window even if the WidgetDelegate
3192 // says no, when a modal dialog is active.
3193 widget_delegate
.set_can_activate(false);
3195 Widget
* modal_dialog_widget
= views::DialogDelegate::CreateDialogWidget(
3196 dialog_delegate
, NULL
, top_level_widget
->GetNativeView());
3197 modal_dialog_widget
->SetBounds(gfx::Rect(100, 100, 200, 200));
3198 modal_dialog_widget
->Show();
3199 EXPECT_TRUE(modal_dialog_widget
->IsVisible());
3201 LRESULT activate_result
= ::SendMessage(
3204 reinterpret_cast<WPARAM
>(win32_window
),
3205 MAKELPARAM(WM_LBUTTONDOWN
, HTCLIENT
));
3206 EXPECT_EQ(activate_result
, MA_ACTIVATE
);
3208 modal_dialog_widget
->CloseNow();
3210 #endif // defined(OS_WIN)
3211 #endif // !defined(OS_CHROMEOS)
3215 class FullscreenAwareFrame
: public views::NonClientFrameView
{
3217 explicit FullscreenAwareFrame(views::Widget
* widget
)
3218 : widget_(widget
), fullscreen_layout_called_(false) {}
3219 ~FullscreenAwareFrame() override
{}
3221 // views::NonClientFrameView overrides:
3222 gfx::Rect
GetBoundsForClientView() const override
{ return gfx::Rect(); }
3223 gfx::Rect
GetWindowBoundsForClientBounds(
3224 const gfx::Rect
& client_bounds
) const override
{
3227 int NonClientHitTest(const gfx::Point
& point
) override
{ return HTNOWHERE
; }
3228 void GetWindowMask(const gfx::Size
& size
, gfx::Path
* window_mask
) override
{}
3229 void ResetWindowControls() override
{}
3230 void UpdateWindowIcon() override
{}
3231 void UpdateWindowTitle() override
{}
3232 void SizeConstraintsChanged() override
{}
3234 // views::View overrides:
3235 void Layout() override
{
3236 if (widget_
->IsFullscreen())
3237 fullscreen_layout_called_
= true;
3240 bool fullscreen_layout_called() const { return fullscreen_layout_called_
; }
3243 views::Widget
* widget_
;
3244 bool fullscreen_layout_called_
;
3246 DISALLOW_COPY_AND_ASSIGN(FullscreenAwareFrame
);
3251 // Tests that frame Layout is called when a widget goes fullscreen without
3252 // changing its size or title.
3253 TEST_F(WidgetTest
, FullscreenFrameLayout
) {
3254 Widget
* widget
= CreateTopLevelPlatformWidget();
3255 FullscreenAwareFrame
* frame
= new FullscreenAwareFrame(widget
);
3256 widget
->non_client_view()->SetFrameView(frame
); // Owns |frame|.
3259 RunPendingMessages();
3261 EXPECT_FALSE(frame
->fullscreen_layout_called());
3262 widget
->SetFullscreen(true);
3264 RunPendingMessages();
3266 if (IsTestingSnowLeopard()) {
3267 // Fullscreen is currently ignored on Snow Leopard.
3268 EXPECT_FALSE(frame
->fullscreen_layout_called());
3270 EXPECT_TRUE(frame
->fullscreen_layout_called());
3276 #if !defined(OS_CHROMEOS)
3279 // Trivial WidgetObserverTest that invokes Widget::IsActive() from
3280 // OnWindowDestroying.
3281 class IsActiveFromDestroyObserver
: public WidgetObserver
{
3283 IsActiveFromDestroyObserver() {}
3284 ~IsActiveFromDestroyObserver() override
{}
3285 void OnWidgetDestroying(Widget
* widget
) override
{ widget
->IsActive(); }
3288 DISALLOW_COPY_AND_ASSIGN(IsActiveFromDestroyObserver
);
3293 // Verifies Widget::IsActive() invoked from
3294 // WidgetObserver::OnWidgetDestroying() in a child widget doesn't crash.
3295 TEST_F(WidgetTest
, IsActiveFromDestroy
) {
3296 // Create two widgets, one a child of the other.
3297 IsActiveFromDestroyObserver observer
;
3298 Widget parent_widget
;
3299 Widget::InitParams parent_params
=
3300 CreateParams(Widget::InitParams::TYPE_POPUP
);
3301 parent_params
.native_widget
= new PlatformDesktopNativeWidget(&parent_widget
);
3302 parent_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
3303 parent_widget
.Init(parent_params
);
3304 parent_widget
.Show();
3306 Widget child_widget
;
3307 Widget::InitParams child_params
=
3308 CreateParams(Widget::InitParams::TYPE_POPUP
);
3309 child_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
3310 child_params
.context
= parent_widget
.GetNativeWindow();
3311 child_widget
.Init(child_params
);
3312 child_widget
.AddObserver(&observer
);
3313 child_widget
.Show();
3315 parent_widget
.CloseNow();
3317 #endif // !defined(OS_CHROMEOS)
3319 // Tests that events propagate through from the dispatcher with the correct
3320 // event type, and that the different platforms behave the same.
3321 TEST_F(WidgetTest
, MouseEventTypesViaGenerator
) {
3322 EventCountView
* view
= new EventCountView
;
3323 view
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
3324 view
->SetBounds(10, 10, 50, 40);
3326 Widget
* widget
= CreateTopLevelFramelessPlatformWidget();
3327 widget
->GetRootView()->AddChildView(view
);
3329 widget
->SetBounds(gfx::Rect(0, 0, 100, 80));
3332 ui::test::EventGenerator
generator(GetContext(), widget
->GetNativeWindow());
3333 generator
.set_current_location(gfx::Point(20, 20));
3335 generator
.ClickLeftButton();
3336 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
3337 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_RELEASED
));
3338 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON
, view
->last_flags());
3340 generator
.PressRightButton();
3341 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
3342 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_RELEASED
));
3343 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON
, view
->last_flags());
3345 generator
.ReleaseRightButton();
3346 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
3347 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_RELEASED
));
3348 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON
, view
->last_flags());
3350 // Test mouse move events.
3351 EXPECT_EQ(0, view
->GetEventCount(ui::ET_MOUSE_MOVED
));
3352 EXPECT_EQ(0, view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
3354 // Move the mouse within the view (20, 20) -> (30, 30).
3355 generator
.MoveMouseTo(gfx::Point(30, 30));
3356 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_MOVED
));
3357 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
3358 EXPECT_EQ(ui::EF_NONE
, view
->last_flags());
3360 // Move it again - entered count shouldn't change.
3361 generator
.MoveMouseTo(gfx::Point(31, 31));
3362 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_MOVED
));
3363 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
3364 EXPECT_EQ(0, view
->GetEventCount(ui::ET_MOUSE_EXITED
));
3366 // Move it off the view.
3367 generator
.MoveMouseTo(gfx::Point(5, 5));
3368 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_MOVED
));
3369 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
3370 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_EXITED
));
3373 generator
.MoveMouseTo(gfx::Point(20, 20));
3374 EXPECT_EQ(3, view
->GetEventCount(ui::ET_MOUSE_MOVED
));
3375 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
3376 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_EXITED
));
3378 // Drargging. Cover HasCapture() and NativeWidgetPrivate::IsMouseButtonDown().
3379 generator
.DragMouseTo(gfx::Point(40, 40));
3380 EXPECT_EQ(3, view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
3381 EXPECT_EQ(3, view
->GetEventCount(ui::ET_MOUSE_RELEASED
));
3382 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_DRAGGED
));
3383 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON
, view
->last_flags());
3388 // Tests that the root view is correctly set up for Widget types that do not
3389 // require a non-client view, before any other views are added to the widget.
3390 // That is, before Widget::ReorderNativeViews() is called which, if called with
3391 // a root view not set, could cause the root view to get resized to the widget.
3392 TEST_F(WidgetTest
, NonClientWindowValidAfterInit
) {
3393 Widget
* widget
= CreateTopLevelFramelessPlatformWidget();
3394 View
* root_view
= widget
->GetRootView();
3396 // Size the root view to exceed the widget bounds.
3397 const gfx::Rect
test_rect(0, 0, 500, 500);
3398 root_view
->SetBoundsRect(test_rect
);
3400 EXPECT_NE(test_rect
.size(), widget
->GetWindowBoundsInScreen().size());
3402 EXPECT_EQ(test_rect
, root_view
->bounds());
3403 widget
->ReorderNativeViews();
3404 EXPECT_EQ(test_rect
, root_view
->bounds());
3410 // This test validates that sending WM_CHAR/WM_SYSCHAR/WM_SYSDEADCHAR
3411 // messages via the WindowEventTarget interface implemented by the
3412 // HWNDMessageHandler class does not cause a crash due to an unprocessed
3414 TEST_F(WidgetTest
, CharMessagesAsKeyboardMessagesDoesNotCrash
) {
3416 Widget::InitParams params
=
3417 CreateParams(Widget::InitParams::TYPE_WINDOW
);
3418 params
.native_widget
= new PlatformDesktopNativeWidget(&widget
);
3419 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
3420 widget
.Init(params
);
3423 ui::WindowEventTarget
* target
=
3424 reinterpret_cast<ui::WindowEventTarget
*>(ui::ViewProp::GetValue(
3425 widget
.GetNativeWindow()->GetHost()->GetAcceleratedWidget(),
3426 ui::WindowEventTarget::kWin32InputEventTarget
));
3427 EXPECT_NE(nullptr, target
);
3428 bool handled
= false;
3429 target
->HandleKeyboardMessage(WM_CHAR
, 0, 0, &handled
);
3430 target
->HandleKeyboardMessage(WM_SYSCHAR
, 0, 0, &handled
);
3431 target
->HandleKeyboardMessage(WM_SYSDEADCHAR
, 0, 0, &handled
);
3437 } // namespace views