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