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_processor.h"
20 #include "ui/events/event_utils.h"
21 #include "ui/events/test/event_generator.h"
22 #include "ui/gfx/native_widget_types.h"
23 #include "ui/gfx/point.h"
24 #include "ui/views/bubble/bubble_delegate.h"
25 #include "ui/views/controls/textfield/textfield.h"
26 #include "ui/views/test/test_views_delegate.h"
27 #include "ui/views/test/widget_test.h"
28 #include "ui/views/views_delegate.h"
29 #include "ui/views/widget/native_widget_delegate.h"
30 #include "ui/views/widget/root_view.h"
31 #include "ui/views/widget/widget_deletion_observer.h"
32 #include "ui/views/window/dialog_delegate.h"
33 #include "ui/views/window/native_frame_view.h"
36 #include "ui/views/win/hwnd_util.h"
44 // TODO(tdanderson): This utility function is used in different unittest
45 // files. Move to a common location to avoid
47 gfx::Point
ConvertPointFromWidgetToView(View
* view
, const gfx::Point
& p
) {
49 View::ConvertPointToTarget(view
->GetWidget()->GetRootView(), view
, &tmp
);
55 // A view that keeps track of the events it receives, optionally consuming them.
56 class EventCountView
: public View
{
58 // Whether to call SetHandled() on events as they are received. For some event
59 // types, this will allow EventCountView to receives future events in the
60 // event sequence, such as a drag.
68 handle_mode_(PROPAGATE_EVENTS
) {}
70 ~EventCountView() override
{}
72 int GetEventCount(ui::EventType type
) {
73 return event_count_
[type
];
80 int last_flags() const {
84 void set_handle_mode(HandleMode handle_mode
) {
85 handle_mode_
= handle_mode
;
89 // Overridden from View:
90 void OnMouseMoved(const ui::MouseEvent
& event
) override
{
91 // MouseMove events are not re-dispatched from the RootView.
92 ++event_count_
[ui::ET_MOUSE_MOVED
];
96 // Overridden from ui::EventHandler:
97 void OnKeyEvent(ui::KeyEvent
* event
) override
{ RecordEvent(event
); }
98 void OnMouseEvent(ui::MouseEvent
* event
) override
{ RecordEvent(event
); }
99 void OnScrollEvent(ui::ScrollEvent
* event
) override
{ RecordEvent(event
); }
100 void OnGestureEvent(ui::GestureEvent
* event
) override
{ RecordEvent(event
); }
103 void RecordEvent(ui::Event
* event
) {
104 ++event_count_
[event
->type()];
105 last_flags_
= event
->flags();
106 if (handle_mode_
== CONSUME_EVENTS
)
110 std::map
<ui::EventType
, int> event_count_
;
112 HandleMode handle_mode_
;
114 DISALLOW_COPY_AND_ASSIGN(EventCountView
);
117 // A view that keeps track of the events it receives, and consumes all scroll
118 // gesture events and ui::ET_SCROLL events.
119 class ScrollableEventCountView
: public EventCountView
{
121 ScrollableEventCountView() {}
122 ~ScrollableEventCountView() override
{}
125 // Overridden from ui::EventHandler:
126 void OnGestureEvent(ui::GestureEvent
* event
) override
{
127 EventCountView::OnGestureEvent(event
);
128 switch (event
->type()) {
129 case ui::ET_GESTURE_SCROLL_BEGIN
:
130 case ui::ET_GESTURE_SCROLL_UPDATE
:
131 case ui::ET_GESTURE_SCROLL_END
:
132 case ui::ET_SCROLL_FLING_START
:
140 void OnScrollEvent(ui::ScrollEvent
* event
) override
{
141 EventCountView::OnScrollEvent(event
);
142 if (event
->type() == ui::ET_SCROLL
)
146 DISALLOW_COPY_AND_ASSIGN(ScrollableEventCountView
);
149 // A view that implements GetMinimumSize.
150 class MinimumSizeFrameView
: public NativeFrameView
{
152 explicit MinimumSizeFrameView(Widget
* frame
): NativeFrameView(frame
) {}
153 ~MinimumSizeFrameView() override
{}
156 // Overridden from View:
157 gfx::Size
GetMinimumSize() const override
{ return gfx::Size(300, 400); }
159 DISALLOW_COPY_AND_ASSIGN(MinimumSizeFrameView
);
162 // An event handler that simply keeps a count of the different types of events
164 class EventCountHandler
: public ui::EventHandler
{
166 EventCountHandler() {}
167 ~EventCountHandler() override
{}
169 int GetEventCount(ui::EventType type
) {
170 return event_count_
[type
];
174 event_count_
.clear();
178 // Overridden from ui::EventHandler:
179 void OnEvent(ui::Event
* event
) override
{
181 ui::EventHandler::OnEvent(event
);
185 void RecordEvent(const ui::Event
& event
) {
186 ++event_count_
[event
.type()];
189 std::map
<ui::EventType
, int> event_count_
;
191 DISALLOW_COPY_AND_ASSIGN(EventCountHandler
);
194 // Class that closes the widget (which ends up deleting it immediately) when the
195 // appropriate event is received.
196 class CloseWidgetView
: public View
{
198 explicit CloseWidgetView(ui::EventType event_type
)
199 : event_type_(event_type
) {
202 // ui::EventHandler override:
203 void OnEvent(ui::Event
* event
) override
{
204 if (event
->type() == event_type_
) {
205 // Go through NativeWidgetPrivate to simulate what happens if the OS
206 // deletes the NativeWindow out from under us.
207 GetWidget()->native_widget_private()->CloseNow();
209 View::OnEvent(event
);
210 if (!event
->IsTouchEvent())
216 const ui::EventType event_type_
;
218 DISALLOW_COPY_AND_ASSIGN(CloseWidgetView
);
221 ui::WindowShowState
GetWidgetShowState(const Widget
* widget
) {
222 // Use IsMaximized/IsMinimized/IsFullScreen instead of GetWindowPlacement
223 // because the former is implemented on all platforms but the latter is not.
224 return widget
->IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN
:
225 widget
->IsMaximized() ? ui::SHOW_STATE_MAXIMIZED
:
226 widget
->IsMinimized() ? ui::SHOW_STATE_MINIMIZED
:
227 widget
->IsActive() ? ui::SHOW_STATE_NORMAL
:
228 ui::SHOW_STATE_INACTIVE
;
231 TEST_F(WidgetTest
, WidgetInitParams
) {
232 // Widgets are not transparent by default.
233 Widget::InitParams init1
;
234 EXPECT_EQ(Widget::InitParams::INFER_OPACITY
, init1
.opacity
);
237 ////////////////////////////////////////////////////////////////////////////////
238 // Widget::GetTopLevelWidget tests.
240 TEST_F(WidgetTest
, GetTopLevelWidget_Native
) {
241 // Create a hierarchy of native widgets.
242 Widget
* toplevel
= CreateTopLevelPlatformWidget();
243 gfx::NativeView parent
= toplevel
->GetNativeView();
244 Widget
* child
= CreateChildPlatformWidget(parent
);
246 EXPECT_EQ(toplevel
, toplevel
->GetTopLevelWidget());
247 EXPECT_EQ(toplevel
, child
->GetTopLevelWidget());
249 toplevel
->CloseNow();
250 // |child| should be automatically destroyed with |toplevel|.
253 // Test if a focus manager and an inputmethod work without CHECK failure
254 // when window activation changes.
255 TEST_F(WidgetTest
, ChangeActivation
) {
256 Widget
* top1
= CreateTopLevelPlatformWidget();
257 // CreateInputMethod before activated
258 top1
->GetInputMethod();
260 RunPendingMessages();
262 Widget
* top2
= CreateTopLevelPlatformWidget();
264 RunPendingMessages();
267 RunPendingMessages();
269 // Create InputMethod after deactivated.
270 top2
->GetInputMethod();
272 RunPendingMessages();
275 RunPendingMessages();
281 // Tests visibility of child widgets.
282 TEST_F(WidgetTest
, Visibility
) {
283 Widget
* toplevel
= CreateTopLevelPlatformWidget();
284 gfx::NativeView parent
= toplevel
->GetNativeView();
285 Widget
* child
= CreateChildPlatformWidget(parent
);
287 EXPECT_FALSE(toplevel
->IsVisible());
288 EXPECT_FALSE(child
->IsVisible());
292 EXPECT_FALSE(toplevel
->IsVisible());
293 EXPECT_FALSE(child
->IsVisible());
297 EXPECT_TRUE(toplevel
->IsVisible());
298 EXPECT_TRUE(child
->IsVisible());
300 toplevel
->CloseNow();
301 // |child| should be automatically destroyed with |toplevel|.
304 ////////////////////////////////////////////////////////////////////////////////
305 // Widget ownership tests.
307 // Tests various permutations of Widget ownership specified in the
308 // InitParams::Ownership param.
310 // A WidgetTest that supplies a toplevel widget for NativeWidget to parent to.
311 class WidgetOwnershipTest
: public WidgetTest
{
313 WidgetOwnershipTest() {}
314 ~WidgetOwnershipTest() override
{}
316 void SetUp() override
{
318 desktop_widget_
= CreateTopLevelPlatformWidget();
321 void TearDown() override
{
322 desktop_widget_
->CloseNow();
323 WidgetTest::TearDown();
327 Widget
* desktop_widget_
;
329 DISALLOW_COPY_AND_ASSIGN(WidgetOwnershipTest
);
332 // A bag of state to monitor destructions.
333 struct OwnershipTestState
{
334 OwnershipTestState() : widget_deleted(false), native_widget_deleted(false) {}
337 bool native_widget_deleted
;
340 // A platform NativeWidget subclass that updates a bag of state when it is
342 class OwnershipTestNativeWidget
: public PlatformNativeWidget
{
344 OwnershipTestNativeWidget(internal::NativeWidgetDelegate
* delegate
,
345 OwnershipTestState
* state
)
346 : PlatformNativeWidget(delegate
),
349 ~OwnershipTestNativeWidget() override
{
350 state_
->native_widget_deleted
= true;
354 OwnershipTestState
* state_
;
356 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidget
);
359 // A views NativeWidget subclass that updates a bag of state when it is
361 class OwnershipTestNativeWidgetAura
: public NativeWidgetCapture
{
363 OwnershipTestNativeWidgetAura(internal::NativeWidgetDelegate
* delegate
,
364 OwnershipTestState
* state
)
365 : NativeWidgetCapture(delegate
),
368 ~OwnershipTestNativeWidgetAura() override
{
369 state_
->native_widget_deleted
= true;
373 OwnershipTestState
* state_
;
375 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetAura
);
378 // A Widget subclass that updates a bag of state when it is destroyed.
379 class OwnershipTestWidget
: public Widget
{
381 explicit OwnershipTestWidget(OwnershipTestState
* state
) : state_(state
) {}
382 ~OwnershipTestWidget() override
{ state_
->widget_deleted
= true; }
385 OwnershipTestState
* state_
;
387 DISALLOW_COPY_AND_ASSIGN(OwnershipTestWidget
);
390 // Widget owns its NativeWidget, part 1: NativeWidget is a platform-native
392 TEST_F(WidgetOwnershipTest
, Ownership_WidgetOwnsPlatformNativeWidget
) {
393 OwnershipTestState state
;
395 scoped_ptr
<Widget
> widget(new OwnershipTestWidget(&state
));
396 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
397 params
.native_widget
=
398 new OwnershipTestNativeWidgetAura(widget
.get(), &state
);
399 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
400 widget
->Init(params
);
402 // Now delete the Widget, which should delete the NativeWidget.
405 EXPECT_TRUE(state
.widget_deleted
);
406 EXPECT_TRUE(state
.native_widget_deleted
);
408 // TODO(beng): write test for this ownership scenario and the NativeWidget
409 // being deleted out from under the Widget.
412 // Widget owns its NativeWidget, part 2: NativeWidget is a NativeWidget.
413 TEST_F(WidgetOwnershipTest
, Ownership_WidgetOwnsViewsNativeWidget
) {
414 OwnershipTestState state
;
416 scoped_ptr
<Widget
> widget(new OwnershipTestWidget(&state
));
417 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
418 params
.native_widget
=
419 new OwnershipTestNativeWidgetAura(widget
.get(), &state
);
420 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
421 widget
->Init(params
);
423 // Now delete the Widget, which should delete the NativeWidget.
426 EXPECT_TRUE(state
.widget_deleted
);
427 EXPECT_TRUE(state
.native_widget_deleted
);
429 // TODO(beng): write test for this ownership scenario and the NativeWidget
430 // being deleted out from under the Widget.
433 // Widget owns its NativeWidget, part 3: NativeWidget is a NativeWidget,
434 // destroy the parent view.
435 TEST_F(WidgetOwnershipTest
,
436 Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView
) {
437 OwnershipTestState state
;
439 Widget
* toplevel
= CreateTopLevelPlatformWidget();
441 scoped_ptr
<Widget
> widget(new OwnershipTestWidget(&state
));
442 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
443 params
.native_widget
=
444 new OwnershipTestNativeWidgetAura(widget
.get(), &state
);
445 params
.parent
= toplevel
->GetNativeView();
446 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
447 widget
->Init(params
);
449 // Now close the toplevel, which deletes the view hierarchy.
450 toplevel
->CloseNow();
452 RunPendingMessages();
454 // This shouldn't delete the widget because it shouldn't be deleted
455 // from the native side.
456 EXPECT_FALSE(state
.widget_deleted
);
457 EXPECT_FALSE(state
.native_widget_deleted
);
459 // Now delete it explicitly.
462 EXPECT_TRUE(state
.widget_deleted
);
463 EXPECT_TRUE(state
.native_widget_deleted
);
466 // NativeWidget owns its Widget, part 1: NativeWidget is a platform-native
468 TEST_F(WidgetOwnershipTest
, Ownership_PlatformNativeWidgetOwnsWidget
) {
469 OwnershipTestState state
;
471 Widget
* widget
= new OwnershipTestWidget(&state
);
472 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
473 params
.native_widget
=
474 new OwnershipTestNativeWidgetAura(widget
, &state
);
475 widget
->Init(params
);
477 // Now destroy the native widget.
480 EXPECT_TRUE(state
.widget_deleted
);
481 EXPECT_TRUE(state
.native_widget_deleted
);
484 // NativeWidget owns its Widget, part 2: NativeWidget is a NativeWidget.
485 TEST_F(WidgetOwnershipTest
, Ownership_ViewsNativeWidgetOwnsWidget
) {
486 OwnershipTestState state
;
488 Widget
* toplevel
= CreateTopLevelPlatformWidget();
490 Widget
* widget
= new OwnershipTestWidget(&state
);
491 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
492 params
.native_widget
=
493 new OwnershipTestNativeWidgetAura(widget
, &state
);
494 params
.parent
= toplevel
->GetNativeView();
495 widget
->Init(params
);
497 // Now destroy the native widget. This is achieved by closing the toplevel.
498 toplevel
->CloseNow();
500 // The NativeWidget won't be deleted until after a return to the message loop
501 // so we have to run pending messages before testing the destruction status.
502 RunPendingMessages();
504 EXPECT_TRUE(state
.widget_deleted
);
505 EXPECT_TRUE(state
.native_widget_deleted
);
508 // NativeWidget owns its Widget, part 3: NativeWidget is a platform-native
509 // widget, destroyed out from under it by the OS.
510 TEST_F(WidgetOwnershipTest
,
511 Ownership_PlatformNativeWidgetOwnsWidget_NativeDestroy
) {
512 OwnershipTestState state
;
514 Widget
* widget
= new OwnershipTestWidget(&state
);
515 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
516 params
.native_widget
=
517 new OwnershipTestNativeWidgetAura(widget
, &state
);
518 widget
->Init(params
);
520 // Now simulate a destroy of the platform native widget from the OS:
521 SimulateNativeDestroy(widget
);
523 EXPECT_TRUE(state
.widget_deleted
);
524 EXPECT_TRUE(state
.native_widget_deleted
);
527 // NativeWidget owns its Widget, part 4: NativeWidget is a NativeWidget,
528 // destroyed by the view hierarchy that contains it.
529 TEST_F(WidgetOwnershipTest
,
530 Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy
) {
531 OwnershipTestState state
;
533 Widget
* toplevel
= CreateTopLevelPlatformWidget();
535 Widget
* widget
= new OwnershipTestWidget(&state
);
536 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
537 params
.native_widget
=
538 new OwnershipTestNativeWidgetAura(widget
, &state
);
539 params
.parent
= toplevel
->GetNativeView();
540 widget
->Init(params
);
542 // Destroy the widget (achieved by closing the toplevel).
543 toplevel
->CloseNow();
545 // The NativeWidget won't be deleted until after a return to the message loop
546 // so we have to run pending messages before testing the destruction status.
547 RunPendingMessages();
549 EXPECT_TRUE(state
.widget_deleted
);
550 EXPECT_TRUE(state
.native_widget_deleted
);
553 // NativeWidget owns its Widget, part 5: NativeWidget is a NativeWidget,
554 // we close it directly.
555 TEST_F(WidgetOwnershipTest
,
556 Ownership_ViewsNativeWidgetOwnsWidget_Close
) {
557 OwnershipTestState state
;
559 Widget
* toplevel
= CreateTopLevelPlatformWidget();
561 Widget
* widget
= new OwnershipTestWidget(&state
);
562 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
563 params
.native_widget
=
564 new OwnershipTestNativeWidgetAura(widget
, &state
);
565 params
.parent
= toplevel
->GetNativeView();
566 widget
->Init(params
);
568 // Destroy the widget.
570 toplevel
->CloseNow();
572 // The NativeWidget won't be deleted until after a return to the message loop
573 // so we have to run pending messages before testing the destruction status.
574 RunPendingMessages();
576 EXPECT_TRUE(state
.widget_deleted
);
577 EXPECT_TRUE(state
.native_widget_deleted
);
580 // Widget owns its NativeWidget and has a WidgetDelegateView as its contents.
581 TEST_F(WidgetOwnershipTest
,
582 Ownership_WidgetOwnsNativeWidgetWithWithWidgetDelegateView
) {
583 OwnershipTestState state
;
585 WidgetDelegateView
* delegate_view
= new WidgetDelegateView
;
587 scoped_ptr
<Widget
> widget(new OwnershipTestWidget(&state
));
588 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
589 params
.native_widget
=
590 new OwnershipTestNativeWidgetAura(widget
.get(), &state
);
591 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
592 params
.delegate
= delegate_view
;
593 widget
->Init(params
);
594 widget
->SetContentsView(delegate_view
);
596 // Now delete the Widget. There should be no crash or use-after-free.
599 EXPECT_TRUE(state
.widget_deleted
);
600 EXPECT_TRUE(state
.native_widget_deleted
);
603 ////////////////////////////////////////////////////////////////////////////////
604 // Test to verify using various Widget methods doesn't crash when the underlying
605 // NativeView is destroyed.
607 class WidgetWithDestroyedNativeViewTest
: public ViewsTestBase
{
609 WidgetWithDestroyedNativeViewTest() {}
610 ~WidgetWithDestroyedNativeViewTest() override
{}
612 void InvokeWidgetMethods(Widget
* widget
) {
613 widget
->GetNativeView();
614 widget
->GetNativeWindow();
615 ui::Accelerator accelerator
;
616 widget
->GetAccelerator(0, &accelerator
);
617 widget
->GetTopLevelWidget();
618 widget
->GetWindowBoundsInScreen();
619 widget
->GetClientAreaBoundsInScreen();
620 widget
->SetBounds(gfx::Rect(0, 0, 100, 80));
621 widget
->SetSize(gfx::Size(10, 11));
622 widget
->SetBoundsConstrained(gfx::Rect(0, 0, 120, 140));
623 widget
->SetVisibilityChangedAnimationsEnabled(false);
624 widget
->StackAtTop();
629 widget
->Deactivate();
631 widget
->DisableInactiveRendering();
632 widget
->SetAlwaysOnTop(true);
633 widget
->IsAlwaysOnTop();
637 widget
->IsMaximized();
638 widget
->IsFullscreen();
639 widget
->SetOpacity(0);
640 widget
->SetUseDragFrame(true);
641 widget
->FlashFrame(true);
643 widget
->GetThemeProvider();
644 widget
->GetNativeTheme();
645 widget
->GetFocusManager();
646 widget
->GetInputMethod();
647 widget
->SchedulePaintInRect(gfx::Rect(0, 0, 1, 2));
648 widget
->IsMouseEventsEnabled();
649 widget
->SetNativeWindowProperty("xx", widget
);
650 widget
->GetNativeWindowProperty("xx");
651 widget
->GetFocusTraversable();
653 widget
->ReorderNativeViews();
654 widget
->SetCapture(widget
->GetRootView());
655 widget
->ReleaseCapture();
656 widget
->HasCapture();
657 widget
->GetWorkAreaBoundsInScreen();
658 widget
->IsTranslucentWindowOpacitySupported();
662 DISALLOW_COPY_AND_ASSIGN(WidgetWithDestroyedNativeViewTest
);
665 TEST_F(WidgetWithDestroyedNativeViewTest
, Test
) {
668 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
669 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
673 widget
.native_widget_private()->CloseNow();
674 InvokeWidgetMethods(&widget
);
676 #if !defined(OS_CHROMEOS)
679 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
680 params
.native_widget
= new PlatformDesktopNativeWidget(&widget
);
681 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
685 widget
.native_widget_private()->CloseNow();
686 InvokeWidgetMethods(&widget
);
691 ////////////////////////////////////////////////////////////////////////////////
692 // Widget observer tests.
695 class WidgetObserverTest
: public WidgetTest
, public WidgetObserver
{
699 widget_closed_(NULL
),
700 widget_activated_(NULL
),
702 widget_hidden_(NULL
),
703 widget_bounds_changed_(NULL
) {
706 ~WidgetObserverTest() override
{}
708 // Overridden from WidgetObserver:
709 void OnWidgetDestroying(Widget
* widget
) override
{
710 if (active_
== widget
)
712 widget_closed_
= widget
;
715 void OnWidgetActivationChanged(Widget
* widget
, bool active
) override
{
717 if (widget_activated_
)
718 widget_activated_
->Deactivate();
719 widget_activated_
= widget
;
722 if (widget_activated_
== widget
)
723 widget_activated_
= NULL
;
724 widget_deactivated_
= widget
;
728 void OnWidgetVisibilityChanged(Widget
* widget
, bool visible
) override
{
730 widget_shown_
= widget
;
732 widget_hidden_
= widget
;
735 void OnWidgetBoundsChanged(Widget
* widget
,
736 const gfx::Rect
& new_bounds
) override
{
737 widget_bounds_changed_
= widget
;
742 widget_closed_
= NULL
;
743 widget_activated_
= NULL
;
744 widget_deactivated_
= NULL
;
745 widget_shown_
= NULL
;
746 widget_hidden_
= NULL
;
747 widget_bounds_changed_
= NULL
;
750 Widget
* NewWidget() {
751 Widget
* widget
= CreateTopLevelNativeWidget();
752 widget
->AddObserver(this);
756 const Widget
* active() const { return active_
; }
757 const Widget
* widget_closed() const { return widget_closed_
; }
758 const Widget
* widget_activated() const { return widget_activated_
; }
759 const Widget
* widget_deactivated() const { return widget_deactivated_
; }
760 const Widget
* widget_shown() const { return widget_shown_
; }
761 const Widget
* widget_hidden() const { return widget_hidden_
; }
762 const Widget
* widget_bounds_changed() const { return widget_bounds_changed_
; }
767 Widget
* widget_closed_
;
768 Widget
* widget_activated_
;
769 Widget
* widget_deactivated_
;
770 Widget
* widget_shown_
;
771 Widget
* widget_hidden_
;
772 Widget
* widget_bounds_changed_
;
775 TEST_F(WidgetObserverTest
, DISABLED_ActivationChange
) {
776 Widget
* toplevel
= CreateTopLevelPlatformWidget();
778 Widget
* toplevel1
= NewWidget();
779 Widget
* toplevel2
= NewWidget();
786 toplevel1
->Activate();
788 RunPendingMessages();
789 EXPECT_EQ(toplevel1
, widget_activated());
791 toplevel2
->Activate();
792 RunPendingMessages();
793 EXPECT_EQ(toplevel1
, widget_deactivated());
794 EXPECT_EQ(toplevel2
, widget_activated());
795 EXPECT_EQ(toplevel2
, active());
797 toplevel
->CloseNow();
800 TEST_F(WidgetObserverTest
, DISABLED_VisibilityChange
) {
801 Widget
* toplevel
= CreateTopLevelPlatformWidget();
803 Widget
* child1
= NewWidget();
804 Widget
* child2
= NewWidget();
813 EXPECT_EQ(child1
, widget_hidden());
816 EXPECT_EQ(child2
, widget_hidden());
819 EXPECT_EQ(child1
, widget_shown());
822 EXPECT_EQ(child2
, widget_shown());
824 toplevel
->CloseNow();
827 TEST_F(WidgetObserverTest
, DestroyBubble
) {
828 Widget
* anchor
= CreateTopLevelPlatformWidget();
831 BubbleDelegateView
* bubble_delegate
=
832 new BubbleDelegateView(anchor
->client_view(), BubbleBorder::NONE
);
833 Widget
* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate
));
834 bubble_widget
->Show();
835 bubble_widget
->CloseNow();
841 TEST_F(WidgetObserverTest
, WidgetBoundsChanged
) {
842 Widget
* child1
= NewWidget();
843 Widget
* child2
= NewWidget();
845 child1
->OnNativeWidgetMove();
846 EXPECT_EQ(child1
, widget_bounds_changed());
848 child2
->OnNativeWidgetMove();
849 EXPECT_EQ(child2
, widget_bounds_changed());
851 child1
->OnNativeWidgetSizeChanged(gfx::Size());
852 EXPECT_EQ(child1
, widget_bounds_changed());
854 child2
->OnNativeWidgetSizeChanged(gfx::Size());
855 EXPECT_EQ(child2
, widget_bounds_changed());
858 // An extension to WidgetBoundsChanged to ensure notifications are forwarded
859 // by the NativeWidget implementation.
860 TEST_F(WidgetObserverTest
, WidgetBoundsChangedNative
) {
861 // Don't use NewWidget(), so that the Init() flow can be observed to ensure
862 // consistency across platforms.
863 Widget
* widget
= new Widget(); // Note: owned by NativeWidget.
864 widget
->AddObserver(this);
866 EXPECT_FALSE(widget_bounds_changed());
868 // Init causes a bounds change, even while not showing.
869 widget
->Init(CreateParams(Widget::InitParams::TYPE_WINDOW
));
870 EXPECT_TRUE(widget_bounds_changed());
873 // Resizing while hidden, triggers a change.
874 widget
->SetSize(gfx::Size(160, 100));
875 EXPECT_FALSE(widget
->IsVisible());
876 EXPECT_TRUE(widget_bounds_changed());
879 // Setting the same size does nothing.
880 widget
->SetSize(gfx::Size(160, 100));
881 EXPECT_FALSE(widget_bounds_changed());
884 // Showing does nothing to the bounds.
886 EXPECT_TRUE(widget
->IsVisible());
887 EXPECT_FALSE(widget_bounds_changed());
890 // Resizing while shown.
891 widget
->SetSize(gfx::Size(170, 100));
892 EXPECT_TRUE(widget_bounds_changed());
895 // Resize to the same thing while shown does nothing.
896 widget
->SetSize(gfx::Size(170, 100));
897 EXPECT_FALSE(widget_bounds_changed());
900 // No bounds change when closing.
902 EXPECT_FALSE(widget_bounds_changed());
905 // Tests that SetBounds() and GetWindowBoundsInScreen() is symmetric when the
906 // widget is visible and not maximized or fullscreen.
907 TEST_F(WidgetTest
, GetWindowBoundsInScreen
) {
908 // Choose test coordinates away from edges and dimensions that are "small"
909 // (but not too small) to ensure the OS doesn't try to adjust them.
910 const gfx::Rect
kTestBounds(150, 150, 400, 300);
911 const gfx::Size
kTestSize(200, 180);
913 // First test a toplevel widget.
914 Widget
* widget
= CreateTopLevelPlatformWidget();
917 EXPECT_NE(kTestSize
.ToString(),
918 widget
->GetWindowBoundsInScreen().size().ToString());
919 widget
->SetSize(kTestSize
);
920 EXPECT_EQ(kTestSize
.ToString(),
921 widget
->GetWindowBoundsInScreen().size().ToString());
923 EXPECT_NE(kTestBounds
.ToString(),
924 widget
->GetWindowBoundsInScreen().ToString());
925 widget
->SetBounds(kTestBounds
);
926 EXPECT_EQ(kTestBounds
.ToString(),
927 widget
->GetWindowBoundsInScreen().ToString());
929 // Changing just the size should not change the origin.
930 widget
->SetSize(kTestSize
);
931 EXPECT_EQ(kTestBounds
.origin().ToString(),
932 widget
->GetWindowBoundsInScreen().origin().ToString());
936 // Same tests with a frameless window.
937 widget
= CreateTopLevelFramelessPlatformWidget();
940 EXPECT_NE(kTestSize
.ToString(),
941 widget
->GetWindowBoundsInScreen().size().ToString());
942 widget
->SetSize(kTestSize
);
943 EXPECT_EQ(kTestSize
.ToString(),
944 widget
->GetWindowBoundsInScreen().size().ToString());
946 EXPECT_NE(kTestBounds
.ToString(),
947 widget
->GetWindowBoundsInScreen().ToString());
948 widget
->SetBounds(kTestBounds
);
949 EXPECT_EQ(kTestBounds
.ToString(),
950 widget
->GetWindowBoundsInScreen().ToString());
952 // For a frameless widget, the client bounds should also match.
953 EXPECT_EQ(kTestBounds
.ToString(),
954 widget
->GetClientAreaBoundsInScreen().ToString());
956 // Verify origin is stable for a frameless window as well.
957 widget
->SetSize(kTestSize
);
958 EXPECT_EQ(kTestBounds
.origin().ToString(),
959 widget
->GetWindowBoundsInScreen().origin().ToString());
964 // Before being enabled on Mac, this was #ifdef(false).
965 // TODO(tapted): Fix this for DesktopNativeWidgets on other platforms.
966 #if defined(OS_MACOSX)
967 // Aura needs shell to maximize/fullscreen window.
968 // NativeWidgetGtk doesn't implement GetRestoredBounds.
969 TEST_F(WidgetTest
, GetRestoredBounds
) {
970 Widget
* toplevel
= CreateTopLevelPlatformWidget();
971 EXPECT_EQ(toplevel
->GetWindowBoundsInScreen().ToString(),
972 toplevel
->GetRestoredBounds().ToString());
974 toplevel
->Maximize();
975 RunPendingMessages();
976 #if defined(OS_MACOSX)
977 // Current expectation on Mac is to do nothing on Maximize.
978 EXPECT_EQ(toplevel
->GetWindowBoundsInScreen().ToString(),
979 toplevel
->GetRestoredBounds().ToString());
981 EXPECT_NE(toplevel
->GetWindowBoundsInScreen().ToString(),
982 toplevel
->GetRestoredBounds().ToString());
984 EXPECT_GT(toplevel
->GetRestoredBounds().width(), 0);
985 EXPECT_GT(toplevel
->GetRestoredBounds().height(), 0);
988 RunPendingMessages();
989 EXPECT_EQ(toplevel
->GetWindowBoundsInScreen().ToString(),
990 toplevel
->GetRestoredBounds().ToString());
992 toplevel
->SetFullscreen(true);
993 RunPendingMessages();
994 EXPECT_NE(toplevel
->GetWindowBoundsInScreen().ToString(),
995 toplevel
->GetRestoredBounds().ToString());
996 EXPECT_GT(toplevel
->GetRestoredBounds().width(), 0);
997 EXPECT_GT(toplevel
->GetRestoredBounds().height(), 0);
1001 // Test that window state is not changed after getting out of full screen.
1002 TEST_F(WidgetTest
, ExitFullscreenRestoreState
) {
1003 Widget
* toplevel
= CreateTopLevelPlatformWidget();
1006 RunPendingMessages();
1008 // This should be a normal state window.
1009 EXPECT_EQ(ui::SHOW_STATE_NORMAL
, GetWidgetShowState(toplevel
));
1011 toplevel
->SetFullscreen(true);
1012 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN
, GetWidgetShowState(toplevel
));
1013 toplevel
->SetFullscreen(false);
1014 EXPECT_NE(ui::SHOW_STATE_FULLSCREEN
, GetWidgetShowState(toplevel
));
1016 // And it should still be in normal state after getting out of full screen.
1017 EXPECT_EQ(ui::SHOW_STATE_NORMAL
, GetWidgetShowState(toplevel
));
1019 // On Mac, a "maximized" state is indistinguishable from a window that just
1020 // fills the screen, so nothing to check there.
1021 #if !defined(OS_MACOSX)
1022 // Now, make it maximized.
1023 toplevel
->Maximize();
1024 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED
, GetWidgetShowState(toplevel
));
1026 toplevel
->SetFullscreen(true);
1027 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN
, GetWidgetShowState(toplevel
));
1028 toplevel
->SetFullscreen(false);
1029 EXPECT_NE(ui::SHOW_STATE_FULLSCREEN
, GetWidgetShowState(toplevel
));
1031 // And it stays maximized after getting out of full screen.
1032 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED
, GetWidgetShowState(toplevel
));
1037 RunPendingMessages();
1040 // The key-event propagation from Widget happens differently on aura and
1041 // non-aura systems because of the difference in IME. So this test works only on
1043 TEST_F(WidgetTest
, KeyboardInputEvent
) {
1044 Widget
* toplevel
= CreateTopLevelPlatformWidget();
1045 View
* container
= toplevel
->client_view();
1047 Textfield
* textfield
= new Textfield();
1048 textfield
->SetText(base::ASCIIToUTF16("some text"));
1049 container
->AddChildView(textfield
);
1051 textfield
->RequestFocus();
1053 // The press gets handled. The release doesn't have an effect.
1054 ui::KeyEvent
backspace_p(ui::ET_KEY_PRESSED
, ui::VKEY_DELETE
, ui::EF_NONE
);
1055 toplevel
->OnKeyEvent(&backspace_p
);
1056 EXPECT_TRUE(backspace_p
.stopped_propagation());
1057 ui::KeyEvent
backspace_r(ui::ET_KEY_RELEASED
, ui::VKEY_DELETE
, ui::EF_NONE
);
1058 toplevel
->OnKeyEvent(&backspace_r
);
1059 EXPECT_FALSE(backspace_r
.handled());
1064 // Verifies bubbles result in a focus lost when shown.
1065 // TODO(msw): this tests relies on focus, it needs to be in
1066 // interactive_ui_tests.
1067 TEST_F(WidgetTest
, DISABLED_FocusChangesOnBubble
) {
1068 // Create a widget, show and activate it and focus the contents view.
1069 View
* contents_view
= new View
;
1070 contents_view
->SetFocusable(true);
1072 Widget::InitParams init_params
=
1073 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS
);
1074 init_params
.bounds
= gfx::Rect(0, 0, 200, 200);
1075 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1076 #if !defined(OS_CHROMEOS)
1077 init_params
.native_widget
= new PlatformDesktopNativeWidget(&widget
);
1079 widget
.Init(init_params
);
1080 widget
.SetContentsView(contents_view
);
1083 contents_view
->RequestFocus();
1084 EXPECT_TRUE(contents_view
->HasFocus());
1087 BubbleDelegateView
* bubble_delegate_view
=
1088 new BubbleDelegateView(contents_view
, BubbleBorder::TOP_LEFT
);
1089 bubble_delegate_view
->SetFocusable(true);
1090 BubbleDelegateView::CreateBubble(bubble_delegate_view
)->Show();
1091 bubble_delegate_view
->RequestFocus();
1093 // |contents_view_| should no longer have focus.
1094 EXPECT_FALSE(contents_view
->HasFocus());
1095 EXPECT_TRUE(bubble_delegate_view
->HasFocus());
1097 bubble_delegate_view
->GetWidget()->CloseNow();
1099 // Closing the bubble should result in focus going back to the contents view.
1100 EXPECT_TRUE(contents_view
->HasFocus());
1103 class TestBubbleDelegateView
: public BubbleDelegateView
{
1105 TestBubbleDelegateView(View
* anchor
)
1106 : BubbleDelegateView(anchor
, BubbleBorder::NONE
),
1107 reset_controls_called_(false) {}
1108 ~TestBubbleDelegateView() override
{}
1110 bool ShouldShowCloseButton() const override
{
1111 reset_controls_called_
= true;
1115 mutable bool reset_controls_called_
;
1118 TEST_F(WidgetTest
, BubbleControlsResetOnInit
) {
1119 Widget
* anchor
= CreateTopLevelPlatformWidget();
1122 TestBubbleDelegateView
* bubble_delegate
=
1123 new TestBubbleDelegateView(anchor
->client_view());
1124 Widget
* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate
));
1125 EXPECT_TRUE(bubble_delegate
->reset_controls_called_
);
1126 bubble_widget
->Show();
1127 bubble_widget
->CloseNow();
1133 // Desktop native widget Aura tests are for non Chrome OS platforms.
1134 #if !defined(OS_CHROMEOS)
1135 // Test to ensure that after minimize, view width is set to zero.
1136 TEST_F(WidgetTest
, TestViewWidthAfterMinimizingWidget
) {
1139 Widget::InitParams init_params
=
1140 CreateParams(Widget::InitParams::TYPE_WINDOW
);
1141 init_params
.show_state
= ui::SHOW_STATE_NORMAL
;
1142 gfx::Rect
initial_bounds(0, 0, 300, 400);
1143 init_params
.bounds
= initial_bounds
;
1144 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1145 init_params
.native_widget
= new PlatformDesktopNativeWidget(&widget
);
1146 widget
.Init(init_params
);
1147 NonClientView
* non_client_view
= widget
.non_client_view();
1148 NonClientFrameView
* frame_view
= new MinimumSizeFrameView(&widget
);
1149 non_client_view
->SetFrameView(frame_view
);
1152 EXPECT_EQ(0, frame_view
->width());
1155 // This class validates whether paints are received for a visible Widget.
1156 // To achieve this it overrides the Show and Close methods on the Widget class
1157 // and sets state whether subsequent paints are expected.
1158 class DesktopAuraTestValidPaintWidget
: public views::Widget
{
1160 DesktopAuraTestValidPaintWidget()
1161 : received_paint_(false),
1162 expect_paint_(true),
1163 received_paint_while_hidden_(false) {}
1165 ~DesktopAuraTestValidPaintWidget() override
{}
1167 void InitForTest(Widget::InitParams create_params
);
1169 void Show() override
{
1170 expect_paint_
= true;
1171 views::Widget::Show();
1174 void Close() override
{
1175 expect_paint_
= false;
1176 views::Widget::Close();
1180 expect_paint_
= false;
1181 views::Widget::Hide();
1184 void OnNativeWidgetPaint(gfx::Canvas
* canvas
) override
{
1185 received_paint_
= true;
1186 EXPECT_TRUE(expect_paint_
);
1188 received_paint_while_hidden_
= true;
1189 views::Widget::OnNativeWidgetPaint(canvas
);
1192 bool ReadReceivedPaintAndReset() {
1193 bool result
= received_paint_
;
1194 received_paint_
= false;
1198 bool received_paint_while_hidden() const {
1199 return received_paint_while_hidden_
;
1203 bool received_paint_
;
1205 bool received_paint_while_hidden_
;
1207 DISALLOW_COPY_AND_ASSIGN(DesktopAuraTestValidPaintWidget
);
1210 void DesktopAuraTestValidPaintWidget::InitForTest(InitParams init_params
) {
1211 init_params
.bounds
= gfx::Rect(0, 0, 200, 200);
1212 init_params
.ownership
= InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1213 init_params
.native_widget
= new PlatformDesktopNativeWidget(this);
1216 View
* contents_view
= new View
;
1217 contents_view
->SetFocusable(true);
1218 SetContentsView(contents_view
);
1224 TEST_F(WidgetTest
, DesktopNativeWidgetNoPaintAfterCloseTest
) {
1225 DesktopAuraTestValidPaintWidget widget
;
1226 widget
.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS
));
1227 RunPendingMessages();
1228 EXPECT_TRUE(widget
.ReadReceivedPaintAndReset());
1229 widget
.SchedulePaintInRect(widget
.GetRestoredBounds());
1231 RunPendingMessages();
1232 EXPECT_FALSE(widget
.ReadReceivedPaintAndReset());
1233 EXPECT_FALSE(widget
.received_paint_while_hidden());
1236 TEST_F(WidgetTest
, DesktopNativeWidgetNoPaintAfterHideTest
) {
1237 DesktopAuraTestValidPaintWidget widget
;
1238 widget
.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS
));
1239 RunPendingMessages();
1240 EXPECT_TRUE(widget
.ReadReceivedPaintAndReset());
1241 widget
.SchedulePaintInRect(widget
.GetRestoredBounds());
1243 RunPendingMessages();
1244 EXPECT_FALSE(widget
.ReadReceivedPaintAndReset());
1245 EXPECT_FALSE(widget
.received_paint_while_hidden());
1249 // Test to ensure that the aura Window's visiblity state is set to visible if
1250 // the underlying widget is hidden and then shown.
1251 TEST_F(WidgetTest
, TestWindowVisibilityAfterHide
) {
1254 Widget::InitParams init_params
=
1255 CreateParams(Widget::InitParams::TYPE_WINDOW
);
1256 init_params
.show_state
= ui::SHOW_STATE_NORMAL
;
1257 gfx::Rect
initial_bounds(0, 0, 300, 400);
1258 init_params
.bounds
= initial_bounds
;
1259 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1260 init_params
.native_widget
= new PlatformDesktopNativeWidget(&widget
);
1261 widget
.Init(init_params
);
1262 NonClientView
* non_client_view
= widget
.non_client_view();
1263 NonClientFrameView
* frame_view
= new MinimumSizeFrameView(&widget
);
1264 non_client_view
->SetFrameView(frame_view
);
1267 EXPECT_TRUE(IsNativeWindowVisible(widget
.GetNativeWindow()));
1269 EXPECT_FALSE(IsNativeWindowVisible(widget
.GetNativeWindow()));
1271 EXPECT_TRUE(IsNativeWindowVisible(widget
.GetNativeWindow()));
1274 // The following code verifies we can correctly destroy a Widget from a mouse
1275 // enter/exit. We could test move/drag/enter/exit but in general we don't run
1276 // nested message loops from such events, nor has the code ever really dealt
1277 // with this situation.
1279 // Generates two moves (first generates enter, second real move), a press, drag
1280 // and release stopping at |last_event_type|.
1281 void GenerateMouseEvents(Widget
* widget
, ui::EventType last_event_type
) {
1282 const gfx::Rect
screen_bounds(widget
->GetWindowBoundsInScreen());
1283 ui::MouseEvent
move_event(ui::ET_MOUSE_MOVED
, screen_bounds
.CenterPoint(),
1284 screen_bounds
.CenterPoint(), 0, 0);
1285 ui::EventProcessor
* dispatcher
= WidgetTest::GetEventProcessor(widget
);
1286 ui::EventDispatchDetails details
= dispatcher
->OnEventFromSource(&move_event
);
1287 if (last_event_type
== ui::ET_MOUSE_ENTERED
|| details
.dispatcher_destroyed
)
1289 details
= dispatcher
->OnEventFromSource(&move_event
);
1290 if (last_event_type
== ui::ET_MOUSE_MOVED
|| details
.dispatcher_destroyed
)
1293 ui::MouseEvent
press_event(ui::ET_MOUSE_PRESSED
, screen_bounds
.CenterPoint(),
1294 screen_bounds
.CenterPoint(), 0, 0);
1295 details
= dispatcher
->OnEventFromSource(&press_event
);
1296 if (last_event_type
== ui::ET_MOUSE_PRESSED
|| details
.dispatcher_destroyed
)
1299 gfx::Point
end_point(screen_bounds
.CenterPoint());
1300 end_point
.Offset(1, 1);
1301 ui::MouseEvent
drag_event(ui::ET_MOUSE_DRAGGED
, end_point
, end_point
, 0, 0);
1302 details
= dispatcher
->OnEventFromSource(&drag_event
);
1303 if (last_event_type
== ui::ET_MOUSE_DRAGGED
|| details
.dispatcher_destroyed
)
1306 ui::MouseEvent
release_event(ui::ET_MOUSE_RELEASED
, end_point
, end_point
, 0,
1308 details
= dispatcher
->OnEventFromSource(&release_event
);
1309 if (details
.dispatcher_destroyed
)
1313 // Creates a widget and invokes GenerateMouseEvents() with |last_event_type|.
1314 void RunCloseWidgetDuringDispatchTest(WidgetTest
* test
,
1315 ui::EventType last_event_type
) {
1316 // |widget| is deleted by CloseWidgetView.
1317 Widget
* widget
= new Widget
;
1318 Widget::InitParams params
=
1319 test
->CreateParams(Widget::InitParams::TYPE_POPUP
);
1320 params
.native_widget
= new PlatformDesktopNativeWidget(widget
);
1321 params
.bounds
= gfx::Rect(0, 0, 50, 100);
1322 widget
->Init(params
);
1323 widget
->SetContentsView(new CloseWidgetView(last_event_type
));
1325 GenerateMouseEvents(widget
, last_event_type
);
1328 // Verifies deleting the widget from a mouse pressed event doesn't crash.
1329 TEST_F(WidgetTest
, CloseWidgetDuringMousePress
) {
1330 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_PRESSED
);
1333 // Verifies deleting the widget from a mouse released event doesn't crash.
1334 TEST_F(WidgetTest
, CloseWidgetDuringMouseReleased
) {
1335 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_RELEASED
);
1338 #endif // !defined(OS_CHROMEOS)
1340 // Tests that wheel events generated from scroll events are targetted to the
1341 // views under the cursor when the focused view does not processed them.
1342 TEST_F(WidgetTest
, WheelEventsFromScrollEventTarget
) {
1343 EventCountView
* cursor_view
= new EventCountView
;
1344 cursor_view
->SetBounds(60, 0, 50, 40);
1346 Widget
* widget
= CreateTopLevelPlatformWidget();
1347 widget
->GetRootView()->AddChildView(cursor_view
);
1349 // Generate a scroll event on the cursor view.
1350 ui::ScrollEvent
scroll(ui::ET_SCROLL
,
1352 ui::EventTimeForNow(),
1357 widget
->OnScrollEvent(&scroll
);
1359 EXPECT_EQ(1, cursor_view
->GetEventCount(ui::ET_SCROLL
));
1360 EXPECT_EQ(1, cursor_view
->GetEventCount(ui::ET_MOUSEWHEEL
));
1362 cursor_view
->ResetCounts();
1364 ui::ScrollEvent
scroll2(ui::ET_SCROLL
,
1366 ui::EventTimeForNow(),
1371 widget
->OnScrollEvent(&scroll2
);
1373 EXPECT_EQ(0, cursor_view
->GetEventCount(ui::ET_SCROLL
));
1374 EXPECT_EQ(0, cursor_view
->GetEventCount(ui::ET_MOUSEWHEEL
));
1379 // Tests that if a scroll-begin gesture is not handled, then subsequent scroll
1380 // events are not dispatched to any view.
1381 TEST_F(WidgetTest
, GestureScrollEventDispatching
) {
1382 EventCountView
* noscroll_view
= new EventCountView
;
1383 EventCountView
* scroll_view
= new ScrollableEventCountView
;
1385 noscroll_view
->SetBounds(0, 0, 50, 40);
1386 scroll_view
->SetBounds(60, 0, 40, 40);
1388 Widget
* widget
= CreateTopLevelPlatformWidget();
1389 widget
->GetRootView()->AddChildView(noscroll_view
);
1390 widget
->GetRootView()->AddChildView(scroll_view
);
1393 ui::GestureEvent
begin(
1398 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN
));
1399 widget
->OnGestureEvent(&begin
);
1400 ui::GestureEvent
update(
1405 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE
, 20, 10));
1406 widget
->OnGestureEvent(&update
);
1407 ui::GestureEvent
end(25,
1411 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END
));
1412 widget
->OnGestureEvent(&end
);
1414 EXPECT_EQ(1, noscroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
1415 EXPECT_EQ(0, noscroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
1416 EXPECT_EQ(0, noscroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
1420 ui::GestureEvent
begin(
1425 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN
));
1426 widget
->OnGestureEvent(&begin
);
1427 ui::GestureEvent
update(
1432 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE
, 20, 10));
1433 widget
->OnGestureEvent(&update
);
1434 ui::GestureEvent
end(85,
1438 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END
));
1439 widget
->OnGestureEvent(&end
);
1441 EXPECT_EQ(1, scroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
1442 EXPECT_EQ(1, scroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
1443 EXPECT_EQ(1, scroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
1449 // Tests that event-handlers installed on the RootView get triggered correctly.
1450 // TODO(tdanderson): Clean up this test as part of crbug.com/355680.
1451 TEST_F(WidgetTest
, EventHandlersOnRootView
) {
1452 Widget
* widget
= CreateTopLevelNativeWidget();
1453 View
* root_view
= widget
->GetRootView();
1455 scoped_ptr
<EventCountView
> view(new EventCountView());
1456 view
->set_owned_by_client();
1457 view
->SetBounds(0, 0, 20, 20);
1458 root_view
->AddChildView(view
.get());
1460 EventCountHandler h1
;
1461 root_view
->AddPreTargetHandler(&h1
);
1463 EventCountHandler h2
;
1464 root_view
->AddPostTargetHandler(&h2
);
1466 widget
->SetBounds(gfx::Rect(0, 0, 100, 100));
1469 // Dispatch a ui::ET_SCROLL event. The event remains unhandled and should
1470 // bubble up the views hierarchy to be re-dispatched on the root view.
1471 ui::ScrollEvent
scroll(ui::ET_SCROLL
,
1473 ui::EventTimeForNow(),
1478 widget
->OnScrollEvent(&scroll
);
1479 EXPECT_EQ(2, h1
.GetEventCount(ui::ET_SCROLL
));
1480 EXPECT_EQ(1, view
->GetEventCount(ui::ET_SCROLL
));
1481 EXPECT_EQ(2, h2
.GetEventCount(ui::ET_SCROLL
));
1483 // Unhandled scroll events are turned into wheel events and re-dispatched.
1484 EXPECT_EQ(1, h1
.GetEventCount(ui::ET_MOUSEWHEEL
));
1485 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSEWHEEL
));
1486 EXPECT_EQ(1, h2
.GetEventCount(ui::ET_MOUSEWHEEL
));
1489 view
->ResetCounts();
1492 // Dispatch a ui::ET_SCROLL_FLING_START event. The event remains unhandled and
1493 // should bubble up the views hierarchy to be re-dispatched on the root view.
1494 ui::ScrollEvent
fling(ui::ET_SCROLL_FLING_START
,
1496 ui::EventTimeForNow(),
1501 widget
->OnScrollEvent(&fling
);
1502 EXPECT_EQ(2, h1
.GetEventCount(ui::ET_SCROLL_FLING_START
));
1503 EXPECT_EQ(1, view
->GetEventCount(ui::ET_SCROLL_FLING_START
));
1504 EXPECT_EQ(2, h2
.GetEventCount(ui::ET_SCROLL_FLING_START
));
1506 // Unhandled scroll events which are not of type ui::ET_SCROLL should not
1507 // be turned into wheel events and re-dispatched.
1508 EXPECT_EQ(0, h1
.GetEventCount(ui::ET_MOUSEWHEEL
));
1509 EXPECT_EQ(0, view
->GetEventCount(ui::ET_MOUSEWHEEL
));
1510 EXPECT_EQ(0, h2
.GetEventCount(ui::ET_MOUSEWHEEL
));
1513 view
->ResetCounts();
1516 // Change the handle mode of |view| so that events are marked as handled at
1517 // the target phase.
1518 view
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
1520 // Dispatch a ui::ET_GESTURE_TAP_DOWN and a ui::ET_GESTURE_TAP_CANCEL event.
1521 // The events are handled at the target phase and should not reach the
1522 // post-target handler.
1523 ui::GestureEvent
tap_down(5,
1526 ui::EventTimeForNow(),
1527 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN
));
1528 widget
->OnGestureEvent(&tap_down
);
1529 EXPECT_EQ(1, h1
.GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
1530 EXPECT_EQ(1, view
->GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
1531 EXPECT_EQ(0, h2
.GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
1533 ui::GestureEvent
tap_cancel(
1537 ui::EventTimeForNow(),
1538 ui::GestureEventDetails(ui::ET_GESTURE_TAP_CANCEL
));
1539 widget
->OnGestureEvent(&tap_cancel
);
1540 EXPECT_EQ(1, h1
.GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
1541 EXPECT_EQ(1, view
->GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
1542 EXPECT_EQ(0, h2
.GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
1545 view
->ResetCounts();
1548 // Dispatch a ui::ET_SCROLL event. The event is handled at the target phase
1549 // and should not reach the post-target handler.
1550 ui::ScrollEvent
consumed_scroll(ui::ET_SCROLL
,
1552 ui::EventTimeForNow(),
1557 widget
->OnScrollEvent(&consumed_scroll
);
1558 EXPECT_EQ(1, h1
.GetEventCount(ui::ET_SCROLL
));
1559 EXPECT_EQ(1, view
->GetEventCount(ui::ET_SCROLL
));
1560 EXPECT_EQ(0, h2
.GetEventCount(ui::ET_SCROLL
));
1562 // Handled scroll events are not turned into wheel events and re-dispatched.
1563 EXPECT_EQ(0, h1
.GetEventCount(ui::ET_MOUSEWHEEL
));
1564 EXPECT_EQ(0, view
->GetEventCount(ui::ET_MOUSEWHEEL
));
1565 EXPECT_EQ(0, h2
.GetEventCount(ui::ET_MOUSEWHEEL
));
1570 TEST_F(WidgetTest
, SynthesizeMouseMoveEvent
) {
1571 Widget
* widget
= CreateTopLevelNativeWidget();
1572 View
* root_view
= widget
->GetRootView();
1574 EventCountView
* v1
= new EventCountView();
1575 v1
->SetBounds(0, 0, 10, 10);
1576 root_view
->AddChildView(v1
);
1577 EventCountView
* v2
= new EventCountView();
1578 v2
->SetBounds(0, 10, 10, 10);
1579 root_view
->AddChildView(v2
);
1581 gfx::Point
cursor_location(5, 5);
1582 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
, cursor_location
, cursor_location
,
1583 ui::EF_NONE
, ui::EF_NONE
);
1584 widget
->OnMouseEvent(&move
);
1586 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_MOUSE_ENTERED
));
1587 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_MOUSE_ENTERED
));
1590 v2
->SetBounds(0, 0, 10, 10);
1591 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_MOUSE_ENTERED
));
1593 widget
->SynthesizeMouseMoveEvent();
1594 EXPECT_EQ(1, v2
->GetEventCount(ui::ET_MOUSE_ENTERED
));
1599 // ui::EventHandler which handles all mouse press events.
1600 class MousePressEventConsumer
: public ui::EventHandler
{
1602 explicit MousePressEventConsumer() {
1605 ~MousePressEventConsumer() override
{}
1608 // ui::EventHandler:
1609 void OnMouseEvent(ui::MouseEvent
* event
) override
{
1610 if (event
->type() == ui::ET_MOUSE_PRESSED
)
1611 event
->SetHandled();
1614 DISALLOW_COPY_AND_ASSIGN(MousePressEventConsumer
);
1619 // Test that mouse presses and mouse releases are dispatched normally when a
1621 TEST_F(WidgetTest
, MouseEventDispatchWhileTouchIsDown
) {
1622 Widget
* widget
= CreateTopLevelNativeWidget();
1624 widget
->SetSize(gfx::Size(300, 300));
1626 EventCountView
* event_count_view
= new EventCountView();
1627 event_count_view
->SetBounds(0, 0, 300, 300);
1628 widget
->GetRootView()->AddChildView(event_count_view
);
1630 MousePressEventConsumer consumer
;
1631 event_count_view
->AddPostTargetHandler(&consumer
);
1633 ui::test::EventGenerator
generator(GetContext(), widget
->GetNativeWindow());
1634 generator
.PressTouch();
1635 generator
.ClickLeftButton();
1637 EXPECT_EQ(1, event_count_view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
1638 EXPECT_EQ(1, event_count_view
->GetEventCount(ui::ET_MOUSE_RELEASED
));
1643 // Used by SingleWindowClosing to count number of times WindowClosing() has
1645 class ClosingDelegate
: public WidgetDelegate
{
1647 ClosingDelegate() : count_(0), widget_(NULL
) {}
1649 int count() const { return count_
; }
1651 void set_widget(views::Widget
* widget
) { widget_
= widget
; }
1653 // WidgetDelegate overrides:
1654 Widget
* GetWidget() override
{ return widget_
; }
1655 const Widget
* GetWidget() const override
{ return widget_
; }
1656 void WindowClosing() override
{ count_
++; }
1660 views::Widget
* widget_
;
1662 DISALLOW_COPY_AND_ASSIGN(ClosingDelegate
);
1665 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget
1667 TEST_F(WidgetTest
, SingleWindowClosing
) {
1668 scoped_ptr
<ClosingDelegate
> delegate(new ClosingDelegate());
1669 Widget
* widget
= new Widget(); // Destroyed by CloseNow() below.
1670 Widget::InitParams init_params
=
1671 CreateParams(Widget::InitParams::TYPE_WINDOW
);
1672 init_params
.bounds
= gfx::Rect(0, 0, 200, 200);
1673 init_params
.delegate
= delegate
.get();
1674 #if !defined(OS_CHROMEOS)
1675 init_params
.native_widget
= new PlatformDesktopNativeWidget(widget
);
1677 widget
->Init(init_params
);
1678 EXPECT_EQ(0, delegate
->count());
1680 EXPECT_EQ(1, delegate
->count());
1683 class WidgetWindowTitleTest
: public WidgetTest
{
1685 void RunTest(bool desktop_native_widget
) {
1686 Widget
* widget
= new Widget(); // Destroyed by CloseNow() below.
1687 Widget::InitParams init_params
=
1688 CreateParams(Widget::InitParams::TYPE_WINDOW
);
1689 widget
->Init(init_params
);
1691 #if !defined(OS_CHROMEOS)
1692 if (desktop_native_widget
)
1693 init_params
.native_widget
= new PlatformDesktopNativeWidget(widget
);
1695 DCHECK(!desktop_native_widget
)
1696 << "DesktopNativeWidget does not exist on non-Aura or on ChromeOS.";
1699 internal::NativeWidgetPrivate
* native_widget
=
1700 widget
->native_widget_private();
1702 base::string16 empty
;
1703 base::string16
s1(base::UTF8ToUTF16("Title1"));
1704 base::string16
s2(base::UTF8ToUTF16("Title2"));
1705 base::string16
s3(base::UTF8ToUTF16("TitleLong"));
1707 // The widget starts with no title, setting empty should not change
1709 EXPECT_FALSE(native_widget
->SetWindowTitle(empty
));
1710 // Setting the title to something non-empty should cause a change.
1711 EXPECT_TRUE(native_widget
->SetWindowTitle(s1
));
1712 // Setting the title to something else with the same length should cause a
1714 EXPECT_TRUE(native_widget
->SetWindowTitle(s2
));
1715 // Setting the title to something else with a different length should cause
1717 EXPECT_TRUE(native_widget
->SetWindowTitle(s3
));
1718 // Setting the title to the same thing twice should not cause a change.
1719 EXPECT_FALSE(native_widget
->SetWindowTitle(s3
));
1725 TEST_F(WidgetWindowTitleTest
, SetWindowTitleChanged_NativeWidget
) {
1726 // Use the default NativeWidget.
1727 bool desktop_native_widget
= false;
1728 RunTest(desktop_native_widget
);
1731 // DesktopNativeWidget does not exist on non-Aura or on ChromeOS.
1732 #if !defined(OS_CHROMEOS)
1733 TEST_F(WidgetWindowTitleTest
, SetWindowTitleChanged_DesktopNativeWidget
) {
1734 // Override to use a DesktopNativeWidget.
1735 bool desktop_native_widget
= true;
1736 RunTest(desktop_native_widget
);
1738 #endif // !OS_CHROMEOS
1740 TEST_F(WidgetTest
, WidgetDeleted_InOnMousePressed
) {
1741 Widget
* widget
= new Widget
;
1742 Widget::InitParams params
=
1743 CreateParams(views::Widget::InitParams::TYPE_POPUP
);
1744 widget
->Init(params
);
1746 widget
->SetContentsView(new CloseWidgetView(ui::ET_MOUSE_PRESSED
));
1748 widget
->SetSize(gfx::Size(100, 100));
1751 ui::test::EventGenerator
generator(GetContext(), widget
->GetNativeWindow());
1753 WidgetDeletionObserver
deletion_observer(widget
);
1754 generator
.ClickLeftButton();
1755 EXPECT_FALSE(deletion_observer
.IsWidgetAlive());
1757 // Yay we did not crash!
1760 TEST_F(WidgetTest
, WidgetDeleted_InDispatchGestureEvent
) {
1761 Widget
* widget
= new Widget
;
1762 Widget::InitParams params
=
1763 CreateParams(views::Widget::InitParams::TYPE_POPUP
);
1764 widget
->Init(params
);
1766 widget
->SetContentsView(new CloseWidgetView(ui::ET_GESTURE_TAP_DOWN
));
1768 widget
->SetSize(gfx::Size(100, 100));
1771 ui::test::EventGenerator
generator(GetContext(), widget
->GetNativeWindow());
1773 WidgetDeletionObserver
deletion_observer(widget
);
1774 generator
.GestureTapAt(widget
->GetWindowBoundsInScreen().CenterPoint());
1775 EXPECT_FALSE(deletion_observer
.IsWidgetAlive());
1777 // Yay we did not crash!
1780 // See description of RunGetNativeThemeFromDestructor() for details.
1781 class GetNativeThemeFromDestructorView
: public WidgetDelegateView
{
1783 GetNativeThemeFromDestructorView() {}
1784 ~GetNativeThemeFromDestructorView() override
{ VerifyNativeTheme(); }
1786 View
* GetContentsView() override
{ return this; }
1789 void VerifyNativeTheme() {
1790 ASSERT_TRUE(GetNativeTheme() != NULL
);
1793 DISALLOW_COPY_AND_ASSIGN(GetNativeThemeFromDestructorView
);
1796 // Verifies GetNativeTheme() from the destructor of a WidgetDelegateView doesn't
1797 // crash. |is_first_run| is true if this is the first call. A return value of
1798 // true indicates this should be run again with a value of false.
1799 // First run uses DesktopNativeWidgetAura (if possible). Second run doesn't.
1800 bool RunGetNativeThemeFromDestructor(const Widget::InitParams
& in_params
,
1801 bool is_first_run
) {
1802 bool needs_second_run
= false;
1803 // Destroyed by CloseNow() below.
1804 Widget
* widget
= new Widget
;
1805 Widget::InitParams
params(in_params
);
1806 // Deletes itself when the Widget is destroyed.
1807 params
.delegate
= new GetNativeThemeFromDestructorView
;
1808 #if !defined(OS_CHROMEOS)
1810 params
.native_widget
= new PlatformDesktopNativeWidget(widget
);
1811 needs_second_run
= true;
1814 widget
->Init(params
);
1816 return needs_second_run
;
1819 // See description of RunGetNativeThemeFromDestructor() for details.
1820 TEST_F(WidgetTest
, GetNativeThemeFromDestructor
) {
1821 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
1822 if (RunGetNativeThemeFromDestructor(params
, true))
1823 RunGetNativeThemeFromDestructor(params
, false);
1826 // Used by HideCloseDestroy. Allows setting a boolean when the widget is
1828 class CloseDestroysWidget
: public Widget
{
1830 explicit CloseDestroysWidget(bool* destroyed
)
1831 : destroyed_(destroyed
) {
1834 ~CloseDestroysWidget() override
{
1837 base::MessageLoop::current()->QuitNow();
1841 void Detach() { destroyed_
= NULL
; }
1844 // If non-null set to true from destructor.
1847 DISALLOW_COPY_AND_ASSIGN(CloseDestroysWidget
);
1850 // An observer that registers that an animation has ended.
1851 class AnimationEndObserver
: public ui::ImplicitAnimationObserver
{
1853 AnimationEndObserver() : animation_completed_(false) {}
1854 ~AnimationEndObserver() override
{}
1856 bool animation_completed() const { return animation_completed_
; }
1858 // ui::ImplicitAnimationObserver:
1859 void OnImplicitAnimationsCompleted() override
{ animation_completed_
= true; }
1862 bool animation_completed_
;
1864 DISALLOW_COPY_AND_ASSIGN(AnimationEndObserver
);
1867 // An observer that registers the bounds of a widget on destruction.
1868 class WidgetBoundsObserver
: public WidgetObserver
{
1870 WidgetBoundsObserver() {}
1871 ~WidgetBoundsObserver() override
{}
1873 gfx::Rect
bounds() { return bounds_
; }
1876 void OnWidgetDestroying(Widget
* widget
) override
{
1877 bounds_
= widget
->GetWindowBoundsInScreen();
1883 DISALLOW_COPY_AND_ASSIGN(WidgetBoundsObserver
);
1886 // Verifies Close() results in destroying.
1887 TEST_F(WidgetTest
, CloseDestroys
) {
1888 bool destroyed
= false;
1889 CloseDestroysWidget
* widget
= new CloseDestroysWidget(&destroyed
);
1890 Widget::InitParams params
=
1891 CreateParams(views::Widget::InitParams::TYPE_MENU
);
1892 params
.opacity
= Widget::InitParams::OPAQUE_WINDOW
;
1893 #if !defined(OS_CHROMEOS)
1894 params
.native_widget
= new PlatformDesktopNativeWidget(widget
);
1896 widget
->Init(params
);
1900 EXPECT_FALSE(destroyed
);
1901 // Run the message loop as Close() asynchronously deletes.
1902 base::RunLoop().Run();
1903 EXPECT_TRUE(destroyed
);
1904 // Close() should destroy the widget. If not we'll cleanup to avoid leaks.
1911 // Tests that killing a widget while animating it does not crash.
1912 TEST_F(WidgetTest
, CloseWidgetWhileAnimating
) {
1913 scoped_ptr
<Widget
> widget(new Widget
);
1914 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
1915 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1916 params
.bounds
= gfx::Rect(50, 50, 250, 250);
1917 widget
->Init(params
);
1918 AnimationEndObserver animation_observer
;
1919 WidgetBoundsObserver widget_observer
;
1920 gfx::Rect
bounds(0, 0, 50, 50);
1922 // Normal animations for tests have ZERO_DURATION, make sure we are actually
1923 // animating the movement.
1924 ui::ScopedAnimationDurationScaleMode
animation_scale_mode(
1925 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION
);
1926 ui::ScopedLayerAnimationSettings
animation_settings(
1927 widget
->GetLayer()->GetAnimator());
1928 animation_settings
.AddObserver(&animation_observer
);
1929 widget
->AddObserver(&widget_observer
);
1932 // Animate the bounds change.
1933 widget
->SetBounds(bounds
);
1935 EXPECT_FALSE(animation_observer
.animation_completed());
1937 EXPECT_TRUE(animation_observer
.animation_completed());
1938 EXPECT_EQ(widget_observer
.bounds(), bounds
);
1941 // A view that consumes mouse-pressed event and gesture-tap-down events.
1942 class RootViewTestView
: public View
{
1944 RootViewTestView(): View() {}
1947 bool OnMousePressed(const ui::MouseEvent
& event
) override
{ return true; }
1949 void OnGestureEvent(ui::GestureEvent
* event
) override
{
1950 if (event
->type() == ui::ET_GESTURE_TAP_DOWN
)
1951 event
->SetHandled();
1955 // Checks if RootView::*_handler_ fields are unset when widget is hidden.
1956 // Fails on chromium.webkit Windows bot, see crbug.com/264872.
1958 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1959 DISABLED_TestRootViewHandlersWhenHidden
1961 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1962 TestRootViewHandlersWhenHidden
1964 TEST_F(WidgetTest
, MAYBE_DisableTestRootViewHandlersWhenHidden
) {
1965 Widget
* widget
= CreateTopLevelNativeWidget();
1966 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
1967 View
* view
= new RootViewTestView();
1968 view
->SetBounds(0, 0, 300, 300);
1969 internal::RootView
* root_view
=
1970 static_cast<internal::RootView
*>(widget
->GetRootView());
1971 root_view
->AddChildView(view
);
1973 // Check RootView::mouse_pressed_handler_.
1975 EXPECT_EQ(NULL
, GetMousePressedHandler(root_view
));
1976 gfx::Point
click_location(45, 15);
1977 ui::MouseEvent
press(ui::ET_MOUSE_PRESSED
, click_location
, click_location
,
1978 ui::EF_LEFT_MOUSE_BUTTON
, ui::EF_LEFT_MOUSE_BUTTON
);
1979 widget
->OnMouseEvent(&press
);
1980 EXPECT_EQ(view
, GetMousePressedHandler(root_view
));
1982 EXPECT_EQ(NULL
, GetMousePressedHandler(root_view
));
1984 // Check RootView::mouse_move_handler_.
1986 EXPECT_EQ(NULL
, GetMouseMoveHandler(root_view
));
1987 gfx::Point
move_location(45, 15);
1988 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
, move_location
, move_location
, 0, 0);
1989 widget
->OnMouseEvent(&move
);
1990 EXPECT_EQ(view
, GetMouseMoveHandler(root_view
));
1992 EXPECT_EQ(NULL
, GetMouseMoveHandler(root_view
));
1994 // Check RootView::gesture_handler_.
1996 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
1997 ui::GestureEvent
tap_down(15,
2001 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN
));
2002 widget
->OnGestureEvent(&tap_down
);
2003 EXPECT_EQ(view
, GetGestureHandler(root_view
));
2005 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2010 // Convenience to make constructing a GestureEvent simpler.
2011 class GestureEventForTest
: public ui::GestureEvent
{
2013 GestureEventForTest(ui::EventType type
, int x
, int y
)
2018 ui::GestureEventDetails(type
)) {}
2020 GestureEventForTest(ui::GestureEventDetails details
, int x
, int y
)
2021 : GestureEvent(x
, y
, 0, base::TimeDelta(), details
) {}
2024 // Tests that the |gesture_handler_| member in RootView is always NULL
2025 // after the dispatch of a ui::ET_GESTURE_END event corresponding to
2026 // the release of the final touch point on the screen, but that
2027 // ui::ET_GESTURE_END events corresponding to the removal of any other touch
2028 // point do not modify |gesture_handler_|.
2029 TEST_F(WidgetTest
, GestureEndEvents
) {
2030 Widget
* widget
= CreateTopLevelNativeWidget();
2031 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
2032 EventCountView
* view
= new EventCountView();
2033 view
->SetBounds(0, 0, 300, 300);
2034 internal::RootView
* root_view
=
2035 static_cast<internal::RootView
*>(widget
->GetRootView());
2036 root_view
->AddChildView(view
);
2039 // If no gesture handler is set, a ui::ET_GESTURE_END event should not set
2040 // the gesture handler.
2041 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2042 GestureEventForTest
end(ui::ET_GESTURE_END
, 15, 15);
2043 widget
->OnGestureEvent(&end
);
2044 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2046 // Change the handle mode of |view| to indicate that it would like
2047 // to handle all events, then send a GESTURE_TAP to set the gesture handler.
2048 view
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2049 GestureEventForTest
tap(ui::ET_GESTURE_TAP
, 15, 15);
2050 widget
->OnGestureEvent(&tap
);
2051 EXPECT_TRUE(tap
.handled());
2052 EXPECT_EQ(view
, GetGestureHandler(root_view
));
2054 // The gesture handler should remain unchanged on a ui::ET_GESTURE_END
2055 // corresponding to a second touch point, but should be reset to NULL by a
2056 // ui::ET_GESTURE_END corresponding to the final touch point.
2057 ui::GestureEventDetails
details(ui::ET_GESTURE_END
);
2058 details
.set_touch_points(2);
2059 GestureEventForTest
end_second_touch_point(details
, 15, 15);
2060 widget
->OnGestureEvent(&end_second_touch_point
);
2061 EXPECT_EQ(view
, GetGestureHandler(root_view
));
2063 end
= GestureEventForTest(ui::ET_GESTURE_END
, 15, 15);
2064 widget
->OnGestureEvent(&end
);
2065 EXPECT_TRUE(end
.handled());
2066 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2068 // Send a GESTURE_TAP to set the gesture handler, then change the handle
2069 // mode of |view| to indicate that it does not want to handle any
2071 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 15, 15);
2072 widget
->OnGestureEvent(&tap
);
2073 EXPECT_TRUE(tap
.handled());
2074 EXPECT_EQ(view
, GetGestureHandler(root_view
));
2075 view
->set_handle_mode(EventCountView::PROPAGATE_EVENTS
);
2077 // The gesture handler should remain unchanged on a ui::ET_GESTURE_END
2078 // corresponding to a second touch point, but should be reset to NULL by a
2079 // ui::ET_GESTURE_END corresponding to the final touch point.
2080 end_second_touch_point
= GestureEventForTest(details
, 15, 15);
2081 widget
->OnGestureEvent(&end_second_touch_point
);
2082 EXPECT_EQ(view
, GetGestureHandler(root_view
));
2084 end
= GestureEventForTest(ui::ET_GESTURE_END
, 15, 15);
2085 widget
->OnGestureEvent(&end
);
2086 EXPECT_FALSE(end
.handled());
2087 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2092 // Tests that gesture events which should not be processed (because
2093 // RootView::OnEventProcessingStarted() has marked them as handled) are not
2094 // dispatched to any views.
2095 TEST_F(WidgetTest
, GestureEventsNotProcessed
) {
2096 Widget
* widget
= CreateTopLevelNativeWidget();
2097 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
2099 // Define a hierarchy of four views (coordinates are in
2100 // their parent coordinate space).
2101 // v1 (0, 0, 300, 300)
2102 // v2 (0, 0, 100, 100)
2103 // v3 (0, 0, 50, 50)
2105 EventCountView
* v1
= new EventCountView();
2106 v1
->SetBounds(0, 0, 300, 300);
2107 EventCountView
* v2
= new EventCountView();
2108 v2
->SetBounds(0, 0, 100, 100);
2109 EventCountView
* v3
= new EventCountView();
2110 v3
->SetBounds(0, 0, 50, 50);
2111 EventCountView
* v4
= new EventCountView();
2112 v4
->SetBounds(0, 0, 10, 10);
2113 internal::RootView
* root_view
=
2114 static_cast<internal::RootView
*>(widget
->GetRootView());
2115 root_view
->AddChildView(v1
);
2116 v1
->AddChildView(v2
);
2117 v2
->AddChildView(v3
);
2118 v3
->AddChildView(v4
);
2122 // ui::ET_GESTURE_BEGIN events should never be seen by any view, but
2123 // they should be marked as handled by OnEventProcessingStarted().
2124 GestureEventForTest
begin(ui::ET_GESTURE_BEGIN
, 5, 5);
2125 widget
->OnGestureEvent(&begin
);
2126 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_BEGIN
));
2127 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_BEGIN
));
2128 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_BEGIN
));
2129 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_BEGIN
));
2130 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2131 EXPECT_TRUE(begin
.handled());
2137 // ui::ET_GESTURE_END events should not be seen by any view when there is
2138 // no default gesture handler set, but they should be marked as handled by
2139 // OnEventProcessingStarted().
2140 GestureEventForTest
end(ui::ET_GESTURE_END
, 5, 5);
2141 widget
->OnGestureEvent(&end
);
2142 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_END
));
2143 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_END
));
2144 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_END
));
2145 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_END
));
2146 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2147 EXPECT_TRUE(end
.handled());
2153 // ui::ET_GESTURE_END events not corresponding to the release of the
2154 // final touch point should never be seen by any view, but they should
2155 // be marked as handled by OnEventProcessingStarted().
2156 ui::GestureEventDetails
details(ui::ET_GESTURE_END
);
2157 details
.set_touch_points(2);
2158 GestureEventForTest
end_second_touch_point(details
, 5, 5);
2159 widget
->OnGestureEvent(&end_second_touch_point
);
2160 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_END
));
2161 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_END
));
2162 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_END
));
2163 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_END
));
2164 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2165 EXPECT_TRUE(end_second_touch_point
.handled());
2171 // ui::ET_GESTURE_SCROLL_UPDATE events should never be seen by any view when
2172 // there is no default gesture handler set, but they should be marked as
2173 // handled by OnEventProcessingStarted().
2174 GestureEventForTest
scroll_update(ui::ET_GESTURE_SCROLL_UPDATE
, 5, 5);
2175 widget
->OnGestureEvent(&scroll_update
);
2176 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2177 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2178 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2179 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2180 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2181 EXPECT_TRUE(scroll_update
.handled());
2187 // ui::ET_GESTURE_SCROLL_END events should never be seen by any view when
2188 // there is no default gesture handler set, but they should be marked as
2189 // handled by OnEventProcessingStarted().
2190 GestureEventForTest
scroll_end(ui::ET_GESTURE_SCROLL_END
, 5, 5);
2191 widget
->OnGestureEvent(&scroll_end
);
2192 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2193 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2194 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2195 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2196 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2197 EXPECT_TRUE(scroll_end
.handled());
2203 // ui::ET_SCROLL_FLING_START events should never be seen by any view when
2204 // there is no default gesture handler set, but they should be marked as
2205 // handled by OnEventProcessingStarted().
2206 GestureEventForTest
scroll_fling_start(ui::ET_SCROLL_FLING_START
, 5, 5);
2207 widget
->OnGestureEvent(&scroll_fling_start
);
2208 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_SCROLL_FLING_START
));
2209 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_SCROLL_FLING_START
));
2210 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_SCROLL_FLING_START
));
2211 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_SCROLL_FLING_START
));
2212 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2213 EXPECT_TRUE(scroll_fling_start
.handled());
2222 // Tests that a (non-scroll) gesture event is dispatched to the correct views
2223 // in a view hierarchy and that the default gesture handler in RootView is set
2225 TEST_F(WidgetTest
, GestureEventDispatch
) {
2226 Widget
* widget
= CreateTopLevelNativeWidget();
2227 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
2229 // Define a hierarchy of four views (coordinates are in
2230 // their parent coordinate space).
2231 // v1 (0, 0, 300, 300)
2232 // v2 (0, 0, 100, 100)
2233 // v3 (0, 0, 50, 50)
2235 EventCountView
* v1
= new EventCountView();
2236 v1
->SetBounds(0, 0, 300, 300);
2237 EventCountView
* v2
= new EventCountView();
2238 v2
->SetBounds(0, 0, 100, 100);
2239 EventCountView
* v3
= new EventCountView();
2240 v3
->SetBounds(0, 0, 50, 50);
2241 EventCountView
* v4
= new EventCountView();
2242 v4
->SetBounds(0, 0, 10, 10);
2243 internal::RootView
* root_view
=
2244 static_cast<internal::RootView
*>(widget
->GetRootView());
2245 root_view
->AddChildView(v1
);
2246 v1
->AddChildView(v2
);
2247 v2
->AddChildView(v3
);
2248 v3
->AddChildView(v4
);
2252 // No gesture handler is set in the root view and none of the views in the
2253 // view hierarchy handle a ui::ET_GESTURE_TAP event. In this case the tap
2254 // event should be dispatched to all views in the hierarchy, the gesture
2255 // handler should remain unset, and the event should remain unhandled.
2256 GestureEventForTest
tap(ui::ET_GESTURE_TAP
, 5, 5);
2257 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2258 widget
->OnGestureEvent(&tap
);
2259 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2260 EXPECT_EQ(1, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2261 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2262 EXPECT_EQ(1, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2263 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2264 EXPECT_FALSE(tap
.handled());
2266 // No gesture handler is set in the root view and |v1|, |v2|, and |v3| all
2267 // handle a ui::ET_GESTURE_TAP event. In this case the tap event should be
2268 // dispatched to |v4| and |v3|, the gesture handler should be set to |v3|,
2269 // and the event should be marked as handled.
2274 v1
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2275 v2
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2276 v3
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2277 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2278 widget
->OnGestureEvent(&tap
);
2279 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2280 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2281 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2282 EXPECT_EQ(1, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2283 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2284 EXPECT_TRUE(tap
.handled());
2286 // The gesture handler is set to |v3| and all views handle all gesture event
2287 // types. In this case subsequent gesture events should only be dispatched to
2288 // |v3| and marked as handled. The gesture handler should remain as |v3|.
2293 v4
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2294 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2295 widget
->OnGestureEvent(&tap
);
2296 EXPECT_TRUE(tap
.handled());
2297 GestureEventForTest
show_press(ui::ET_GESTURE_SHOW_PRESS
, 5, 5);
2298 widget
->OnGestureEvent(&show_press
);
2299 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2300 widget
->OnGestureEvent(&tap
);
2301 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2302 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2303 EXPECT_EQ(2, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2304 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2305 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_SHOW_PRESS
));
2306 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_SHOW_PRESS
));
2307 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_SHOW_PRESS
));
2308 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_SHOW_PRESS
));
2309 EXPECT_TRUE(tap
.handled());
2310 EXPECT_TRUE(show_press
.handled());
2311 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2313 // The gesture handler is set to |v3|, but |v3| does not handle
2314 // ui::ET_GESTURE_TAP events. In this case a tap gesture should be dispatched
2315 // only to |v3|, but the event should remain unhandled. The gesture handler
2316 // should remain as |v3|.
2321 v3
->set_handle_mode(EventCountView::PROPAGATE_EVENTS
);
2322 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2323 widget
->OnGestureEvent(&tap
);
2324 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2325 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2326 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2327 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2328 EXPECT_FALSE(tap
.handled());
2329 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2334 // Tests that gesture scroll events will change the default gesture handler in
2335 // RootView if the current handler to which they are dispatched does not handle
2336 // gesture scroll events.
2337 TEST_F(WidgetTest
, ScrollGestureEventDispatch
) {
2338 Widget
* widget
= CreateTopLevelNativeWidget();
2339 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
2341 // Define a hierarchy of four views (coordinates are in
2342 // their parent coordinate space).
2343 // v1 (0, 0, 300, 300)
2344 // v2 (0, 0, 100, 100)
2345 // v3 (0, 0, 50, 50)
2347 EventCountView
* v1
= new EventCountView();
2348 v1
->SetBounds(0, 0, 300, 300);
2349 EventCountView
* v2
= new EventCountView();
2350 v2
->SetBounds(0, 0, 100, 100);
2351 EventCountView
* v3
= new EventCountView();
2352 v3
->SetBounds(0, 0, 50, 50);
2353 EventCountView
* v4
= new EventCountView();
2354 v4
->SetBounds(0, 0, 10, 10);
2355 internal::RootView
* root_view
=
2356 static_cast<internal::RootView
*>(widget
->GetRootView());
2357 root_view
->AddChildView(v1
);
2358 v1
->AddChildView(v2
);
2359 v2
->AddChildView(v3
);
2360 v3
->AddChildView(v4
);
2364 // Change the handle mode of |v3| to indicate that it would like to handle
2366 v3
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2368 // When no gesture handler is set, dispatching a ui::ET_GESTURE_TAP_DOWN
2369 // should bubble up the views hierarchy until it reaches the first view
2370 // that will handle it (|v3|) and then sets the handler to |v3|.
2371 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2372 GestureEventForTest
tap_down(ui::ET_GESTURE_TAP_DOWN
, 5, 5);
2373 widget
->OnGestureEvent(&tap_down
);
2374 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
2375 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
2376 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
2377 EXPECT_EQ(1, v4
->GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
2378 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2379 EXPECT_TRUE(tap_down
.handled());
2385 // A ui::ET_GESTURE_TAP_CANCEL event should be dispatched to |v3| directly.
2386 GestureEventForTest
tap_cancel(ui::ET_GESTURE_TAP_CANCEL
, 5, 5);
2387 widget
->OnGestureEvent(&tap_cancel
);
2388 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
2389 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
2390 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
2391 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
2392 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2393 EXPECT_TRUE(tap_cancel
.handled());
2399 // Change the handle mode of |v3| to indicate that it would no longer like
2400 // to handle events, and change the mode of |v1| to indicate that it would
2401 // like to handle events.
2402 v3
->set_handle_mode(EventCountView::PROPAGATE_EVENTS
);
2403 v1
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2405 // Dispatch a ui::ET_GESTURE_SCROLL_BEGIN event. Because the current gesture
2406 // handler (|v3|) does not handle scroll events, the event should bubble up
2407 // the views hierarchy until it reaches the first view that will handle
2408 // it (|v1|) and then sets the handler to |v1|.
2409 GestureEventForTest
scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN
, 5, 5);
2410 widget
->OnGestureEvent(&scroll_begin
);
2411 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
2412 EXPECT_EQ(1, v2
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
2413 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
2414 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
2415 EXPECT_EQ(v1
, GetGestureHandler(root_view
));
2416 EXPECT_TRUE(scroll_begin
.handled());
2422 // A ui::ET_GESTURE_SCROLL_UPDATE event should be dispatched to |v1|
2424 GestureEventForTest
scroll_update(ui::ET_GESTURE_SCROLL_UPDATE
, 5, 5);
2425 widget
->OnGestureEvent(&scroll_update
);
2426 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2427 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2428 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2429 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2430 EXPECT_EQ(v1
, GetGestureHandler(root_view
));
2431 EXPECT_TRUE(scroll_update
.handled());
2437 // A ui::ET_GESTURE_SCROLL_END event should be dispatched to |v1|
2438 // directly and should not reset the gesture handler.
2439 GestureEventForTest
scroll_end(ui::ET_GESTURE_SCROLL_END
, 5, 5);
2440 widget
->OnGestureEvent(&scroll_end
);
2441 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2442 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2443 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2444 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2445 EXPECT_EQ(v1
, GetGestureHandler(root_view
));
2446 EXPECT_TRUE(scroll_end
.handled());
2452 // A ui::ET_GESTURE_PINCH_BEGIN event (which is a non-scroll event) should
2453 // still be dispatched to |v1| directly.
2454 GestureEventForTest
pinch_begin(ui::ET_GESTURE_PINCH_BEGIN
, 5, 5);
2455 widget
->OnGestureEvent(&pinch_begin
);
2456 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN
));
2457 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN
));
2458 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN
));
2459 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN
));
2460 EXPECT_EQ(v1
, GetGestureHandler(root_view
));
2461 EXPECT_TRUE(pinch_begin
.handled());
2467 // A ui::ET_GESTURE_END event should be dispatched to |v1| and should
2468 // set the gesture handler to NULL.
2469 GestureEventForTest
end(ui::ET_GESTURE_END
, 5, 5);
2470 widget
->OnGestureEvent(&end
);
2471 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_END
));
2472 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_END
));
2473 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_END
));
2474 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_END
));
2475 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2476 EXPECT_TRUE(end
.handled());
2481 // A class used in WidgetTest.GestureEventLocationWhileBubbling to verify
2482 // that when a gesture event bubbles up a View hierarchy, the location
2483 // of a gesture event seen by each View is in the local coordinate space
2485 class GestureLocationView
: public EventCountView
{
2487 GestureLocationView() {}
2488 ~GestureLocationView() override
{}
2490 void set_expected_location(gfx::Point expected_location
) {
2491 expected_location_
= expected_location
;
2495 void OnGestureEvent(ui::GestureEvent
* event
) override
{
2496 EventCountView::OnGestureEvent(event
);
2498 // Verify that the location of |event| is in the local coordinate
2500 EXPECT_EQ(expected_location_
, event
->location());
2504 // The expected location of a gesture event dispatched to |this|.
2505 gfx::Point expected_location_
;
2507 DISALLOW_COPY_AND_ASSIGN(GestureLocationView
);
2510 // Verifies that the location of a gesture event is always in the local
2511 // coordinate space of the View receiving the event while bubbling.
2512 TEST_F(WidgetTest
, GestureEventLocationWhileBubbling
) {
2513 Widget
* widget
= CreateTopLevelNativeWidget();
2514 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
2516 // Define a hierarchy of three views (coordinates shown below are in the
2517 // coordinate space of the root view, but the coordinates used for
2518 // SetBounds() are in their parent coordinate space).
2519 // v1 (50, 50, 150, 150)
2520 // v2 (100, 70, 50, 80)
2521 // v3 (120, 100, 10, 10)
2522 GestureLocationView
* v1
= new GestureLocationView();
2523 v1
->SetBounds(50, 50, 150, 150);
2524 GestureLocationView
* v2
= new GestureLocationView();
2525 v2
->SetBounds(50, 20, 50, 80);
2526 GestureLocationView
* v3
= new GestureLocationView();
2527 v3
->SetBounds(20, 30, 10, 10);
2528 internal::RootView
* root_view
=
2529 static_cast<internal::RootView
*>(widget
->GetRootView());
2530 root_view
->AddChildView(v1
);
2531 v1
->AddChildView(v2
);
2532 v2
->AddChildView(v3
);
2536 // Define a GESTURE_TAP event located at (125, 105) in root view coordinates.
2537 // This event is contained within all of |v1|, |v2|, and |v3|.
2538 gfx::Point
location_in_root(125, 105);
2539 GestureEventForTest
tap(
2540 ui::ET_GESTURE_TAP
, location_in_root
.x(), location_in_root
.y());
2542 // Calculate the location of the event in the local coordinate spaces
2543 // of each of the views.
2544 gfx::Point
location_in_v1(ConvertPointFromWidgetToView(v1
, location_in_root
));
2545 EXPECT_EQ(gfx::Point(75, 55), location_in_v1
);
2546 gfx::Point
location_in_v2(ConvertPointFromWidgetToView(v2
, location_in_root
));
2547 EXPECT_EQ(gfx::Point(25, 35), location_in_v2
);
2548 gfx::Point
location_in_v3(ConvertPointFromWidgetToView(v3
, location_in_root
));
2549 EXPECT_EQ(gfx::Point(5, 5), location_in_v3
);
2551 // Dispatch the event. When each view receives the event, its location should
2552 // be in the local coordinate space of that view (see the check made by
2553 // GestureLocationView). After dispatch is complete the event's location
2554 // should be in the root coordinate space.
2555 v1
->set_expected_location(location_in_v1
);
2556 v2
->set_expected_location(location_in_v2
);
2557 v3
->set_expected_location(location_in_v3
);
2558 widget
->OnGestureEvent(&tap
);
2559 EXPECT_EQ(location_in_root
, tap
.location());
2561 // Verify that each view did in fact see the event.
2562 EventCountView
* view1
= v1
;
2563 EventCountView
* view2
= v2
;
2564 EventCountView
* view3
= v3
;
2565 EXPECT_EQ(1, view1
->GetEventCount(ui::ET_GESTURE_TAP
));
2566 EXPECT_EQ(1, view2
->GetEventCount(ui::ET_GESTURE_TAP
));
2567 EXPECT_EQ(1, view3
->GetEventCount(ui::ET_GESTURE_TAP
));
2572 // Verifies that disabled views are permitted to be set as the default gesture
2573 // handler in RootView. Also verifies that gesture events targeted to a disabled
2574 // view are not actually dispatched to the view, but are still marked as
2576 TEST_F(WidgetTest
, DisabledGestureEventTarget
) {
2577 Widget
* widget
= CreateTopLevelNativeWidget();
2578 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
2580 // Define a hierarchy of four views (coordinates are in
2581 // their parent coordinate space).
2582 // v1 (0, 0, 300, 300)
2583 // v2 (0, 0, 100, 100)
2584 // v3 (0, 0, 50, 50)
2586 EventCountView
* v1
= new EventCountView();
2587 v1
->SetBounds(0, 0, 300, 300);
2588 EventCountView
* v2
= new EventCountView();
2589 v2
->SetBounds(0, 0, 100, 100);
2590 EventCountView
* v3
= new EventCountView();
2591 v3
->SetBounds(0, 0, 50, 50);
2592 EventCountView
* v4
= new EventCountView();
2593 v4
->SetBounds(0, 0, 10, 10);
2594 internal::RootView
* root_view
=
2595 static_cast<internal::RootView
*>(widget
->GetRootView());
2596 root_view
->AddChildView(v1
);
2597 v1
->AddChildView(v2
);
2598 v2
->AddChildView(v3
);
2599 v3
->AddChildView(v4
);
2603 // |v1|, |v2|, and |v3| all handle gesture events but |v3| is marked as
2605 v1
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2606 v2
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2607 v3
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2608 v3
->SetEnabled(false);
2610 // No gesture handler is set in the root view. In this case the tap event
2611 // should be dispatched only to |v4|, the gesture handler should be set to
2612 // |v3|, and the event should be marked as handled.
2613 GestureEventForTest
tap(ui::ET_GESTURE_TAP
, 5, 5);
2614 widget
->OnGestureEvent(&tap
);
2615 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2616 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2617 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2618 EXPECT_EQ(1, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2619 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2620 EXPECT_TRUE(tap
.handled());
2626 // A subsequent gesture event should be marked as handled but not dispatched.
2627 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2628 widget
->OnGestureEvent(&tap
);
2629 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2630 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2631 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2632 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2633 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2634 EXPECT_TRUE(tap
.handled());
2640 // A GESTURE_END should reset the default gesture handler to NULL. It should
2641 // also not be dispatched to |v3| but still marked as handled.
2642 GestureEventForTest
end(ui::ET_GESTURE_END
, 5, 5);
2643 widget
->OnGestureEvent(&end
);
2644 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_END
));
2645 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_END
));
2646 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_END
));
2647 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_END
));
2648 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2649 EXPECT_TRUE(end
.handled());
2655 // Change the handle mode of |v3| to indicate that it would no longer like
2656 // to handle events which are dispatched to it.
2657 v3
->set_handle_mode(EventCountView::PROPAGATE_EVENTS
);
2659 // No gesture handler is set in the root view. In this case the tap event
2660 // should be dispatched only to |v4| and the event should be marked as
2661 // handled. Furthermore, the gesture handler should be set to
2662 // |v3|; even though |v3| does not explicitly handle events, it is a
2663 // valid target for the tap event because it is disabled.
2664 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2665 widget
->OnGestureEvent(&tap
);
2666 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2667 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2668 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2669 EXPECT_EQ(1, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2670 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2671 EXPECT_TRUE(tap
.handled());
2677 // A GESTURE_END should reset the default gesture handler to NULL. It should
2678 // also not be dispatched to |v3| but still marked as handled.
2679 end
= GestureEventForTest(ui::ET_GESTURE_END
, 5, 5);
2680 widget
->OnGestureEvent(&end
);
2681 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_END
));
2682 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_END
));
2683 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_END
));
2684 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_END
));
2685 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2686 EXPECT_TRUE(end
.handled());
2691 // Test the result of Widget::GetAllChildWidgets().
2692 TEST_F(WidgetTest
, GetAllChildWidgets
) {
2693 // Create the following widget hierarchy:
2701 Widget
* toplevel
= CreateTopLevelPlatformWidget();
2702 Widget
* w1
= CreateChildPlatformWidget(toplevel
->GetNativeView());
2703 Widget
* w11
= CreateChildPlatformWidget(w1
->GetNativeView());
2704 Widget
* w2
= CreateChildPlatformWidget(toplevel
->GetNativeView());
2705 Widget
* w21
= CreateChildPlatformWidget(w2
->GetNativeView());
2706 Widget
* w22
= CreateChildPlatformWidget(w2
->GetNativeView());
2708 std::set
<Widget
*> expected
;
2709 expected
.insert(toplevel
);
2710 expected
.insert(w1
);
2711 expected
.insert(w11
);
2712 expected
.insert(w2
);
2713 expected
.insert(w21
);
2714 expected
.insert(w22
);
2716 std::set
<Widget
*> widgets
;
2717 Widget::GetAllChildWidgets(toplevel
->GetNativeView(), &widgets
);
2719 EXPECT_EQ(expected
.size(), widgets
.size());
2720 EXPECT_TRUE(std::equal(expected
.begin(), expected
.end(), widgets
.begin()));
2723 // Used by DestroyChildWidgetsInOrder. On destruction adds the supplied name to
2725 class DestroyedTrackingView
: public View
{
2727 DestroyedTrackingView(const std::string
& name
,
2728 std::vector
<std::string
>* add_to
)
2733 ~DestroyedTrackingView() override
{ add_to_
->push_back(name_
); }
2736 const std::string name_
;
2737 std::vector
<std::string
>* add_to_
;
2739 DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingView
);
2742 class WidgetChildDestructionTest
: public WidgetTest
{
2744 WidgetChildDestructionTest() {}
2746 // Creates a top level and a child, destroys the child and verifies the views
2747 // of the child are destroyed before the views of the parent.
2748 void RunDestroyChildWidgetsTest(bool top_level_has_desktop_native_widget_aura
,
2749 bool child_has_desktop_native_widget_aura
) {
2750 // When a View is destroyed its name is added here.
2751 std::vector
<std::string
> destroyed
;
2753 Widget
* top_level
= new Widget
;
2754 Widget::InitParams params
=
2755 CreateParams(views::Widget::InitParams::TYPE_WINDOW
);
2756 #if !defined(OS_CHROMEOS)
2757 if (top_level_has_desktop_native_widget_aura
)
2758 params
.native_widget
= new PlatformDesktopNativeWidget(top_level
);
2760 top_level
->Init(params
);
2761 top_level
->GetRootView()->AddChildView(
2762 new DestroyedTrackingView("parent", &destroyed
));
2765 Widget
* child
= new Widget
;
2766 Widget::InitParams child_params
=
2767 CreateParams(views::Widget::InitParams::TYPE_POPUP
);
2768 child_params
.parent
= top_level
->GetNativeView();
2769 #if !defined(OS_CHROMEOS)
2770 if (child_has_desktop_native_widget_aura
)
2771 child_params
.native_widget
= new PlatformDesktopNativeWidget(child
);
2773 child
->Init(child_params
);
2774 child
->GetRootView()->AddChildView(
2775 new DestroyedTrackingView("child", &destroyed
));
2778 // Should trigger destruction of the child too.
2779 top_level
->native_widget_private()->CloseNow();
2781 // Child should be destroyed first.
2782 ASSERT_EQ(2u, destroyed
.size());
2783 EXPECT_EQ("child", destroyed
[0]);
2784 EXPECT_EQ("parent", destroyed
[1]);
2788 DISALLOW_COPY_AND_ASSIGN(WidgetChildDestructionTest
);
2791 #if !defined(OS_CHROMEOS)
2792 // See description of RunDestroyChildWidgetsTest(). Parent uses
2793 // DesktopNativeWidgetAura.
2794 TEST_F(WidgetChildDestructionTest
,
2795 DestroyChildWidgetsInOrderWithDesktopNativeWidget
) {
2796 RunDestroyChildWidgetsTest(true, false);
2799 // See description of RunDestroyChildWidgetsTest(). Both parent and child use
2800 // DesktopNativeWidgetAura.
2801 TEST_F(WidgetChildDestructionTest
,
2802 DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth
) {
2803 RunDestroyChildWidgetsTest(true, true);
2805 #endif // !defined(OS_CHROMEOS)
2807 // See description of RunDestroyChildWidgetsTest().
2808 TEST_F(WidgetChildDestructionTest
, DestroyChildWidgetsInOrder
) {
2809 RunDestroyChildWidgetsTest(false, false);
2812 #if !defined(OS_CHROMEOS)
2813 // Provides functionality to create a window modal dialog.
2814 class ModalDialogDelegate
: public DialogDelegateView
{
2816 ModalDialogDelegate() {}
2817 ~ModalDialogDelegate() override
{}
2819 // WidgetDelegate overrides.
2820 ui::ModalType
GetModalType() const override
{ return ui::MODAL_TYPE_WINDOW
; }
2823 DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate
);
2826 // This test verifies that whether mouse events when a modal dialog is
2827 // displayed are eaten or recieved by the dialog.
2828 TEST_F(WidgetTest
, WindowMouseModalityTest
) {
2829 // Create a top level widget.
2830 Widget top_level_widget
;
2831 Widget::InitParams init_params
=
2832 CreateParams(Widget::InitParams::TYPE_WINDOW
);
2833 init_params
.show_state
= ui::SHOW_STATE_NORMAL
;
2834 gfx::Rect
initial_bounds(0, 0, 500, 500);
2835 init_params
.bounds
= initial_bounds
;
2836 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
2837 init_params
.native_widget
=
2838 new PlatformDesktopNativeWidget(&top_level_widget
);
2839 top_level_widget
.Init(init_params
);
2840 top_level_widget
.Show();
2841 EXPECT_TRUE(top_level_widget
.IsVisible());
2843 // Create a view and validate that a mouse moves makes it to the view.
2844 EventCountView
* widget_view
= new EventCountView();
2845 widget_view
->SetBounds(0, 0, 10, 10);
2846 top_level_widget
.GetRootView()->AddChildView(widget_view
);
2848 gfx::Point
cursor_location_main(5, 5);
2849 ui::MouseEvent
move_main(ui::ET_MOUSE_MOVED
,
2850 cursor_location_main
,
2851 cursor_location_main
,
2854 ui::EventDispatchDetails details
=
2855 GetEventProcessor(&top_level_widget
)->OnEventFromSource(&move_main
);
2856 ASSERT_FALSE(details
.dispatcher_destroyed
);
2858 EXPECT_EQ(1, widget_view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
2859 widget_view
->ResetCounts();
2861 // Create a modal dialog and validate that a mouse down message makes it to
2862 // the main view within the dialog.
2864 // This instance will be destroyed when the dialog is destroyed.
2865 ModalDialogDelegate
* dialog_delegate
= new ModalDialogDelegate
;
2867 Widget
* modal_dialog_widget
= views::DialogDelegate::CreateDialogWidget(
2868 dialog_delegate
, NULL
, top_level_widget
.GetNativeView());
2869 modal_dialog_widget
->SetBounds(gfx::Rect(100, 100, 200, 200));
2870 EventCountView
* dialog_widget_view
= new EventCountView();
2871 dialog_widget_view
->SetBounds(0, 0, 50, 50);
2872 modal_dialog_widget
->GetRootView()->AddChildView(dialog_widget_view
);
2873 modal_dialog_widget
->Show();
2874 EXPECT_TRUE(modal_dialog_widget
->IsVisible());
2876 gfx::Point
cursor_location_dialog(100, 100);
2877 ui::MouseEvent
mouse_down_dialog(ui::ET_MOUSE_PRESSED
,
2878 cursor_location_dialog
,
2879 cursor_location_dialog
,
2882 details
= GetEventProcessor(&top_level_widget
)->OnEventFromSource(
2883 &mouse_down_dialog
);
2884 ASSERT_FALSE(details
.dispatcher_destroyed
);
2885 EXPECT_EQ(1, dialog_widget_view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
2887 // Send a mouse move message to the main window. It should not be received by
2888 // the main window as the modal dialog is still active.
2889 gfx::Point
cursor_location_main2(6, 6);
2890 ui::MouseEvent
mouse_down_main(ui::ET_MOUSE_MOVED
,
2891 cursor_location_main2
,
2892 cursor_location_main2
,
2895 details
= GetEventProcessor(&top_level_widget
)->OnEventFromSource(
2897 ASSERT_FALSE(details
.dispatcher_destroyed
);
2898 EXPECT_EQ(0, widget_view
->GetEventCount(ui::ET_MOUSE_MOVED
));
2900 modal_dialog_widget
->CloseNow();
2901 top_level_widget
.CloseNow();
2904 // Verifies nativeview visbility matches that of Widget visibility when
2905 // SetFullscreen is invoked.
2906 TEST_F(WidgetTest
, FullscreenStatePropagated
) {
2907 Widget::InitParams init_params
=
2908 CreateParams(Widget::InitParams::TYPE_WINDOW
);
2909 init_params
.show_state
= ui::SHOW_STATE_NORMAL
;
2910 init_params
.bounds
= gfx::Rect(0, 0, 500, 500);
2911 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
2914 Widget top_level_widget
;
2915 top_level_widget
.Init(init_params
);
2916 top_level_widget
.SetFullscreen(true);
2917 EXPECT_EQ(top_level_widget
.IsVisible(),
2918 IsNativeWindowVisible(top_level_widget
.GetNativeWindow()));
2919 top_level_widget
.CloseNow();
2921 #if !defined(OS_CHROMEOS)
2923 Widget top_level_widget
;
2924 init_params
.native_widget
=
2925 new PlatformDesktopNativeWidget(&top_level_widget
);
2926 top_level_widget
.Init(init_params
);
2927 top_level_widget
.SetFullscreen(true);
2928 EXPECT_EQ(top_level_widget
.IsVisible(),
2929 IsNativeWindowVisible(top_level_widget
.GetNativeWindow()));
2930 top_level_widget
.CloseNow();
2936 // Provides functionality to test widget activation via an activation flag
2937 // which can be set by an accessor.
2938 class ModalWindowTestWidgetDelegate
: public WidgetDelegate
{
2940 ModalWindowTestWidgetDelegate()
2942 can_activate_(true) {}
2944 virtual ~ModalWindowTestWidgetDelegate() {}
2946 // Overridden from WidgetDelegate:
2947 virtual void DeleteDelegate() override
{
2950 virtual Widget
* GetWidget() override
{
2953 virtual const Widget
* GetWidget() const override
{
2956 virtual bool CanActivate() const override
{
2957 return can_activate_
;
2959 virtual bool ShouldAdvanceFocusToTopLevelWidget() const override
{
2963 void set_can_activate(bool can_activate
) {
2964 can_activate_
= can_activate
;
2967 void set_widget(Widget
* widget
) {
2975 DISALLOW_COPY_AND_ASSIGN(ModalWindowTestWidgetDelegate
);
2978 // Tests whether we can activate the top level widget when a modal dialog is
2980 TEST_F(WidgetTest
, WindowModalityActivationTest
) {
2981 // Destroyed when the top level widget created below is destroyed.
2982 ModalWindowTestWidgetDelegate
* widget_delegate
=
2983 new ModalWindowTestWidgetDelegate
;
2984 // Create a top level widget.
2985 Widget top_level_widget
;
2986 Widget::InitParams init_params
=
2987 CreateParams(Widget::InitParams::TYPE_WINDOW
);
2988 init_params
.show_state
= ui::SHOW_STATE_NORMAL
;
2989 gfx::Rect
initial_bounds(0, 0, 500, 500);
2990 init_params
.bounds
= initial_bounds
;
2991 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
2992 init_params
.native_widget
= new DesktopNativeWidgetAura(&top_level_widget
);
2993 init_params
.delegate
= widget_delegate
;
2994 top_level_widget
.Init(init_params
);
2995 widget_delegate
->set_widget(&top_level_widget
);
2996 top_level_widget
.Show();
2997 EXPECT_TRUE(top_level_widget
.IsVisible());
2999 HWND win32_window
= views::HWNDForWidget(&top_level_widget
);
3000 EXPECT_TRUE(::IsWindow(win32_window
));
3002 // This instance will be destroyed when the dialog is destroyed.
3003 ModalDialogDelegate
* dialog_delegate
= new ModalDialogDelegate
;
3005 // We should be able to activate the window even if the WidgetDelegate
3006 // says no, when a modal dialog is active.
3007 widget_delegate
->set_can_activate(false);
3009 Widget
* modal_dialog_widget
= views::DialogDelegate::CreateDialogWidget(
3010 dialog_delegate
, NULL
, top_level_widget
.GetNativeWindow());
3011 modal_dialog_widget
->SetBounds(gfx::Rect(100, 100, 200, 200));
3012 modal_dialog_widget
->Show();
3013 EXPECT_TRUE(modal_dialog_widget
->IsVisible());
3015 LRESULT activate_result
= ::SendMessage(
3018 reinterpret_cast<WPARAM
>(win32_window
),
3019 MAKELPARAM(WM_LBUTTONDOWN
, HTCLIENT
));
3020 EXPECT_EQ(activate_result
, MA_ACTIVATE
);
3022 modal_dialog_widget
->CloseNow();
3023 top_level_widget
.CloseNow();
3025 #endif // defined(OS_WIN)
3026 #endif // !defined(OS_CHROMEOS)
3028 TEST_F(WidgetTest
, ShowCreatesActiveWindow
) {
3029 Widget
* widget
= CreateTopLevelPlatformWidget();
3032 EXPECT_EQ(GetWidgetShowState(widget
), ui::SHOW_STATE_NORMAL
);
3037 // OSX does not have a per-application "active" window such as provided by
3038 // ::GetActiveWindow() on Windows. There is only a system-wide "keyWindow" which
3039 // is updated asynchronously.
3040 #if defined(OS_MACOSX)
3041 #define MAYBE_ShowInactive DISABLED_ShowInactive
3043 #define MAYBE_ShowInactive ShowInactive
3045 TEST_F(WidgetTest
, MAYBE_ShowInactive
) {
3046 Widget
* widget
= CreateTopLevelPlatformWidget();
3048 widget
->ShowInactive();
3049 EXPECT_EQ(GetWidgetShowState(widget
), ui::SHOW_STATE_INACTIVE
);
3054 TEST_F(WidgetTest
, InactiveBeforeShow
) {
3055 Widget
* widget
= CreateTopLevelPlatformWidget();
3057 EXPECT_FALSE(widget
->IsActive());
3058 EXPECT_FALSE(widget
->IsVisible());
3062 EXPECT_TRUE(widget
->IsActive());
3063 EXPECT_TRUE(widget
->IsVisible());
3068 TEST_F(WidgetTest
, ShowInactiveAfterShow
) {
3069 // Create 2 widgets to ensure window layering does not change.
3070 Widget
* widget
= CreateTopLevelPlatformWidget();
3071 Widget
* widget2
= CreateTopLevelPlatformWidget();
3074 EXPECT_FALSE(widget
->IsActive());
3075 EXPECT_TRUE(widget2
->IsVisible());
3076 EXPECT_TRUE(widget2
->IsActive());
3079 EXPECT_TRUE(widget
->IsActive());
3080 EXPECT_FALSE(widget2
->IsActive());
3081 widget
->ShowInactive();
3082 EXPECT_TRUE(widget
->IsActive());
3083 EXPECT_FALSE(widget2
->IsActive());
3084 EXPECT_EQ(GetWidgetShowState(widget
), ui::SHOW_STATE_NORMAL
);
3086 widget2
->CloseNow();
3090 TEST_F(WidgetTest
, ShowAfterShowInactive
) {
3091 Widget
* widget
= CreateTopLevelPlatformWidget();
3093 widget
->ShowInactive();
3095 EXPECT_EQ(GetWidgetShowState(widget
), ui::SHOW_STATE_NORMAL
);
3100 #if !defined(OS_CHROMEOS)
3101 TEST_F(WidgetTest
, InactiveWidgetDoesNotGrabActivation
) {
3102 Widget
* widget
= CreateTopLevelPlatformWidget();
3104 EXPECT_EQ(GetWidgetShowState(widget
), ui::SHOW_STATE_NORMAL
);
3107 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
3108 params
.native_widget
= new PlatformDesktopNativeWidget(&widget2
);
3109 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
3110 widget2
.Init(params
);
3113 EXPECT_EQ(GetWidgetShowState(&widget2
), ui::SHOW_STATE_INACTIVE
);
3114 EXPECT_EQ(GetWidgetShowState(widget
), ui::SHOW_STATE_NORMAL
);
3119 #endif // !defined(OS_CHROMEOS)
3123 class FullscreenAwareFrame
: public views::NonClientFrameView
{
3125 explicit FullscreenAwareFrame(views::Widget
* widget
)
3126 : widget_(widget
), fullscreen_layout_called_(false) {}
3127 ~FullscreenAwareFrame() override
{}
3129 // views::NonClientFrameView overrides:
3130 gfx::Rect
GetBoundsForClientView() const override
{ return gfx::Rect(); }
3131 gfx::Rect
GetWindowBoundsForClientBounds(
3132 const gfx::Rect
& client_bounds
) const override
{
3135 int NonClientHitTest(const gfx::Point
& point
) override
{ return HTNOWHERE
; }
3136 void GetWindowMask(const gfx::Size
& size
, gfx::Path
* window_mask
) override
{}
3137 void ResetWindowControls() override
{}
3138 void UpdateWindowIcon() override
{}
3139 void UpdateWindowTitle() override
{}
3140 void SizeConstraintsChanged() override
{}
3142 // views::View overrides:
3143 void Layout() override
{
3144 if (widget_
->IsFullscreen())
3145 fullscreen_layout_called_
= true;
3148 bool fullscreen_layout_called() const { return fullscreen_layout_called_
; }
3151 views::Widget
* widget_
;
3152 bool fullscreen_layout_called_
;
3154 DISALLOW_COPY_AND_ASSIGN(FullscreenAwareFrame
);
3159 // Tests that frame Layout is called when a widget goes fullscreen without
3160 // changing its size or title.
3161 TEST_F(WidgetTest
, FullscreenFrameLayout
) {
3162 Widget
* widget
= CreateTopLevelPlatformWidget();
3163 FullscreenAwareFrame
* frame
= new FullscreenAwareFrame(widget
);
3164 widget
->non_client_view()->SetFrameView(frame
); // Owns |frame|.
3167 RunPendingMessages();
3169 EXPECT_FALSE(frame
->fullscreen_layout_called());
3170 widget
->SetFullscreen(true);
3172 RunPendingMessages();
3173 EXPECT_TRUE(frame
->fullscreen_layout_called());
3178 #if !defined(OS_CHROMEOS)
3181 // Trivial WidgetObserverTest that invokes Widget::IsActive() from
3182 // OnWindowDestroying.
3183 class IsActiveFromDestroyObserver
: public WidgetObserver
{
3185 IsActiveFromDestroyObserver() {}
3186 ~IsActiveFromDestroyObserver() override
{}
3187 void OnWidgetDestroying(Widget
* widget
) override
{ widget
->IsActive(); }
3190 DISALLOW_COPY_AND_ASSIGN(IsActiveFromDestroyObserver
);
3195 // Verifies Widget::IsActive() invoked from
3196 // WidgetObserver::OnWidgetDestroying() in a child widget doesn't crash.
3197 TEST_F(WidgetTest
, IsActiveFromDestroy
) {
3198 // Create two widgets, one a child of the other.
3199 IsActiveFromDestroyObserver observer
;
3200 Widget parent_widget
;
3201 Widget::InitParams parent_params
=
3202 CreateParams(Widget::InitParams::TYPE_POPUP
);
3203 parent_params
.native_widget
= new PlatformDesktopNativeWidget(&parent_widget
);
3204 parent_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
3205 parent_widget
.Init(parent_params
);
3206 parent_widget
.Show();
3208 Widget child_widget
;
3209 Widget::InitParams child_params
=
3210 CreateParams(Widget::InitParams::TYPE_POPUP
);
3211 child_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
3212 child_params
.context
= parent_widget
.GetNativeWindow();
3213 child_widget
.Init(child_params
);
3214 child_widget
.AddObserver(&observer
);
3215 child_widget
.Show();
3217 parent_widget
.CloseNow();
3219 #endif // !defined(OS_CHROMEOS)
3221 // Tests that events propagate through from the dispatcher with the correct
3222 // event type, and that the different platforms behave the same.
3223 TEST_F(WidgetTest
, MouseEventTypesViaGenerator
) {
3224 EventCountView
* view
= new EventCountView
;
3225 view
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
3226 view
->SetBounds(10, 10, 50, 40);
3228 Widget
* widget
= CreateTopLevelFramelessPlatformWidget();
3229 widget
->GetRootView()->AddChildView(view
);
3231 widget
->SetBounds(gfx::Rect(0, 0, 100, 80));
3234 ui::test::EventGenerator
generator(GetContext(), widget
->GetNativeWindow());
3235 generator
.set_current_location(gfx::Point(20, 20));
3237 generator
.ClickLeftButton();
3238 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
3239 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_RELEASED
));
3240 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON
, view
->last_flags());
3242 generator
.PressRightButton();
3243 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
3244 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_RELEASED
));
3245 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON
, view
->last_flags());
3247 generator
.ReleaseRightButton();
3248 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
3249 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_RELEASED
));
3250 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON
, view
->last_flags());
3252 // Test mouse move events.
3253 EXPECT_EQ(0, view
->GetEventCount(ui::ET_MOUSE_MOVED
));
3254 EXPECT_EQ(0, view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
3256 // Move the mouse within the view (20, 20) -> (30, 30).
3257 generator
.MoveMouseTo(gfx::Point(30, 30));
3258 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_MOVED
));
3259 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
3260 EXPECT_EQ(ui::EF_NONE
, view
->last_flags());
3262 // Move it again - entered count shouldn't change.
3263 generator
.MoveMouseTo(gfx::Point(31, 31));
3264 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_MOVED
));
3265 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
3266 EXPECT_EQ(0, view
->GetEventCount(ui::ET_MOUSE_EXITED
));
3268 // Move it off the view.
3269 generator
.MoveMouseTo(gfx::Point(5, 5));
3270 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_MOVED
));
3271 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
3272 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_EXITED
));
3275 generator
.MoveMouseTo(gfx::Point(20, 20));
3276 EXPECT_EQ(3, view
->GetEventCount(ui::ET_MOUSE_MOVED
));
3277 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
3278 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_EXITED
));
3280 // Drargging. Cover HasCapture() and NativeWidgetPrivate::IsMouseButtonDown().
3281 generator
.DragMouseTo(gfx::Point(40, 40));
3282 EXPECT_EQ(3, view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
3283 EXPECT_EQ(3, view
->GetEventCount(ui::ET_MOUSE_RELEASED
));
3284 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_DRAGGED
));
3285 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON
, view
->last_flags());
3290 // Tests that the root view is correctly set up for Widget types that do not
3291 // require a non-client view, before any other views are added to the widget.
3292 // That is, before Widget::ReorderNativeViews() is called which, if called with
3293 // a root view not set, could cause the root view to get resized to the widget.
3294 TEST_F(WidgetTest
, NonClientWindowValidAfterInit
) {
3295 Widget
* widget
= CreateTopLevelFramelessPlatformWidget();
3296 View
* root_view
= widget
->GetRootView();
3298 // Size the root view to exceed the widget bounds.
3299 const gfx::Rect
test_rect(0, 0, 500, 500);
3300 root_view
->SetBoundsRect(test_rect
);
3302 EXPECT_NE(test_rect
.size(), widget
->GetWindowBoundsInScreen().size());
3304 EXPECT_EQ(test_rect
, root_view
->bounds());
3305 widget
->ReorderNativeViews();
3306 EXPECT_EQ(test_rect
, root_view
->bounds());
3312 } // namespace views