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"
42 // A view that keeps track of the events it receives, optionally consuming them.
43 class EventCountView
: public View
{
45 // Whether to call SetHandled() on events as they are received. For some event
46 // types, this will allow EventCountView to receives future events in the
47 // event sequence, such as a drag.
55 handle_mode_(PROPAGATE_EVENTS
) {}
57 virtual ~EventCountView() {}
59 int GetEventCount(ui::EventType type
) {
60 return event_count_
[type
];
67 int last_flags() const {
71 void set_handle_mode(HandleMode handle_mode
) {
72 handle_mode_
= handle_mode
;
76 // Overridden from View:
77 virtual void OnMouseMoved(const ui::MouseEvent
& event
) OVERRIDE
{
78 // MouseMove events are not re-dispatched from the RootView.
79 ++event_count_
[ui::ET_MOUSE_MOVED
];
83 // Overridden from ui::EventHandler:
84 virtual void OnKeyEvent(ui::KeyEvent
* event
) OVERRIDE
{
87 virtual void OnMouseEvent(ui::MouseEvent
* event
) OVERRIDE
{
90 virtual void OnScrollEvent(ui::ScrollEvent
* event
) OVERRIDE
{
93 virtual void OnGestureEvent(ui::GestureEvent
* event
) OVERRIDE
{
98 void RecordEvent(ui::Event
* event
) {
99 ++event_count_
[event
->type()];
100 last_flags_
= event
->flags();
101 if (handle_mode_
== CONSUME_EVENTS
)
105 std::map
<ui::EventType
, int> event_count_
;
107 HandleMode handle_mode_
;
109 DISALLOW_COPY_AND_ASSIGN(EventCountView
);
112 // A view that keeps track of the events it receives, and consumes all scroll
113 // gesture events and ui::ET_SCROLL events.
114 class ScrollableEventCountView
: public EventCountView
{
116 ScrollableEventCountView() {}
117 virtual ~ScrollableEventCountView() {}
120 // Overridden from ui::EventHandler:
121 virtual void OnGestureEvent(ui::GestureEvent
* event
) OVERRIDE
{
122 EventCountView::OnGestureEvent(event
);
123 switch (event
->type()) {
124 case ui::ET_GESTURE_SCROLL_BEGIN
:
125 case ui::ET_GESTURE_SCROLL_UPDATE
:
126 case ui::ET_GESTURE_SCROLL_END
:
127 case ui::ET_SCROLL_FLING_START
:
135 virtual void OnScrollEvent(ui::ScrollEvent
* event
) OVERRIDE
{
136 EventCountView::OnScrollEvent(event
);
137 if (event
->type() == ui::ET_SCROLL
)
141 DISALLOW_COPY_AND_ASSIGN(ScrollableEventCountView
);
144 // A view that implements GetMinimumSize.
145 class MinimumSizeFrameView
: public NativeFrameView
{
147 explicit MinimumSizeFrameView(Widget
* frame
): NativeFrameView(frame
) {}
148 virtual ~MinimumSizeFrameView() {}
151 // Overridden from View:
152 virtual gfx::Size
GetMinimumSize() const OVERRIDE
{
153 return gfx::Size(300, 400);
156 DISALLOW_COPY_AND_ASSIGN(MinimumSizeFrameView
);
159 // An event handler that simply keeps a count of the different types of events
161 class EventCountHandler
: public ui::EventHandler
{
163 EventCountHandler() {}
164 virtual ~EventCountHandler() {}
166 int GetEventCount(ui::EventType type
) {
167 return event_count_
[type
];
171 event_count_
.clear();
175 // Overridden from ui::EventHandler:
176 virtual void OnEvent(ui::Event
* event
) OVERRIDE
{
178 ui::EventHandler::OnEvent(event
);
182 void RecordEvent(const ui::Event
& event
) {
183 ++event_count_
[event
.type()];
186 std::map
<ui::EventType
, int> event_count_
;
188 DISALLOW_COPY_AND_ASSIGN(EventCountHandler
);
191 // Class that closes the widget (which ends up deleting it immediately) when the
192 // appropriate event is received.
193 class CloseWidgetView
: public View
{
195 explicit CloseWidgetView(ui::EventType event_type
)
196 : event_type_(event_type
) {
199 // ui::EventHandler override:
200 virtual void OnEvent(ui::Event
* event
) OVERRIDE
{
201 if (event
->type() == event_type_
) {
202 // Go through NativeWidgetPrivate to simulate what happens if the OS
203 // deletes the NativeWindow out from under us.
204 GetWidget()->native_widget_private()->CloseNow();
206 View::OnEvent(event
);
207 if (!event
->IsTouchEvent())
213 const ui::EventType event_type_
;
215 DISALLOW_COPY_AND_ASSIGN(CloseWidgetView
);
218 ui::WindowShowState
GetWidgetShowState(const Widget
* widget
) {
219 // Use IsMaximized/IsMinimized/IsFullScreen instead of GetWindowPlacement
220 // because the former is implemented on all platforms but the latter is not.
221 return widget
->IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN
:
222 widget
->IsMaximized() ? ui::SHOW_STATE_MAXIMIZED
:
223 widget
->IsMinimized() ? ui::SHOW_STATE_MINIMIZED
:
224 widget
->IsActive() ? ui::SHOW_STATE_NORMAL
:
225 ui::SHOW_STATE_INACTIVE
;
228 TEST_F(WidgetTest
, WidgetInitParams
) {
229 // Widgets are not transparent by default.
230 Widget::InitParams init1
;
231 EXPECT_EQ(Widget::InitParams::INFER_OPACITY
, init1
.opacity
);
234 ////////////////////////////////////////////////////////////////////////////////
235 // Widget::GetTopLevelWidget tests.
237 TEST_F(WidgetTest
, GetTopLevelWidget_Native
) {
238 // Create a hierarchy of native widgets.
239 Widget
* toplevel
= CreateTopLevelPlatformWidget();
240 gfx::NativeView parent
= toplevel
->GetNativeView();
241 Widget
* child
= CreateChildPlatformWidget(parent
);
243 EXPECT_EQ(toplevel
, toplevel
->GetTopLevelWidget());
244 EXPECT_EQ(toplevel
, child
->GetTopLevelWidget());
246 toplevel
->CloseNow();
247 // |child| should be automatically destroyed with |toplevel|.
250 // Test if a focus manager and an inputmethod work without CHECK failure
251 // when window activation changes.
252 TEST_F(WidgetTest
, ChangeActivation
) {
253 Widget
* top1
= CreateTopLevelPlatformWidget();
254 // CreateInputMethod before activated
255 top1
->GetInputMethod();
257 RunPendingMessages();
259 Widget
* top2
= CreateTopLevelPlatformWidget();
261 RunPendingMessages();
264 RunPendingMessages();
266 // Create InputMethod after deactivated.
267 top2
->GetInputMethod();
269 RunPendingMessages();
272 RunPendingMessages();
278 // Tests visibility of child widgets.
279 TEST_F(WidgetTest
, Visibility
) {
280 Widget
* toplevel
= CreateTopLevelPlatformWidget();
281 gfx::NativeView parent
= toplevel
->GetNativeView();
282 Widget
* child
= CreateChildPlatformWidget(parent
);
284 EXPECT_FALSE(toplevel
->IsVisible());
285 EXPECT_FALSE(child
->IsVisible());
289 EXPECT_FALSE(toplevel
->IsVisible());
290 EXPECT_FALSE(child
->IsVisible());
294 EXPECT_TRUE(toplevel
->IsVisible());
295 EXPECT_TRUE(child
->IsVisible());
297 toplevel
->CloseNow();
298 // |child| should be automatically destroyed with |toplevel|.
301 ////////////////////////////////////////////////////////////////////////////////
302 // Widget ownership tests.
304 // Tests various permutations of Widget ownership specified in the
305 // InitParams::Ownership param.
307 // A WidgetTest that supplies a toplevel widget for NativeWidget to parent to.
308 class WidgetOwnershipTest
: public WidgetTest
{
310 WidgetOwnershipTest() {}
311 virtual ~WidgetOwnershipTest() {}
313 virtual void SetUp() {
315 desktop_widget_
= CreateTopLevelPlatformWidget();
318 virtual void TearDown() {
319 desktop_widget_
->CloseNow();
320 WidgetTest::TearDown();
324 Widget
* desktop_widget_
;
326 DISALLOW_COPY_AND_ASSIGN(WidgetOwnershipTest
);
329 // A bag of state to monitor destructions.
330 struct OwnershipTestState
{
331 OwnershipTestState() : widget_deleted(false), native_widget_deleted(false) {}
334 bool native_widget_deleted
;
337 // A platform NativeWidget subclass that updates a bag of state when it is
339 class OwnershipTestNativeWidget
: public PlatformNativeWidget
{
341 OwnershipTestNativeWidget(internal::NativeWidgetDelegate
* delegate
,
342 OwnershipTestState
* state
)
343 : PlatformNativeWidget(delegate
),
346 virtual ~OwnershipTestNativeWidget() {
347 state_
->native_widget_deleted
= true;
351 OwnershipTestState
* state_
;
353 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidget
);
356 // A views NativeWidget subclass that updates a bag of state when it is
358 class OwnershipTestNativeWidgetAura
: public NativeWidgetCapture
{
360 OwnershipTestNativeWidgetAura(internal::NativeWidgetDelegate
* delegate
,
361 OwnershipTestState
* state
)
362 : NativeWidgetCapture(delegate
),
365 virtual ~OwnershipTestNativeWidgetAura() {
366 state_
->native_widget_deleted
= true;
370 OwnershipTestState
* state_
;
372 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetAura
);
375 // A Widget subclass that updates a bag of state when it is destroyed.
376 class OwnershipTestWidget
: public Widget
{
378 explicit OwnershipTestWidget(OwnershipTestState
* state
) : state_(state
) {}
379 virtual ~OwnershipTestWidget() {
380 state_
->widget_deleted
= true;
384 OwnershipTestState
* state_
;
386 DISALLOW_COPY_AND_ASSIGN(OwnershipTestWidget
);
389 // Widget owns its NativeWidget, part 1: NativeWidget is a platform-native
391 TEST_F(WidgetOwnershipTest
, Ownership_WidgetOwnsPlatformNativeWidget
) {
392 OwnershipTestState state
;
394 scoped_ptr
<Widget
> widget(new OwnershipTestWidget(&state
));
395 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
396 params
.native_widget
=
397 new OwnershipTestNativeWidgetAura(widget
.get(), &state
);
398 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
399 widget
->Init(params
);
401 // Now delete the Widget, which should delete the NativeWidget.
404 EXPECT_TRUE(state
.widget_deleted
);
405 EXPECT_TRUE(state
.native_widget_deleted
);
407 // TODO(beng): write test for this ownership scenario and the NativeWidget
408 // being deleted out from under the Widget.
411 // Widget owns its NativeWidget, part 2: NativeWidget is a NativeWidget.
412 TEST_F(WidgetOwnershipTest
, Ownership_WidgetOwnsViewsNativeWidget
) {
413 OwnershipTestState state
;
415 scoped_ptr
<Widget
> widget(new OwnershipTestWidget(&state
));
416 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
417 params
.native_widget
=
418 new OwnershipTestNativeWidgetAura(widget
.get(), &state
);
419 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
420 widget
->Init(params
);
422 // Now delete the Widget, which should delete the NativeWidget.
425 EXPECT_TRUE(state
.widget_deleted
);
426 EXPECT_TRUE(state
.native_widget_deleted
);
428 // TODO(beng): write test for this ownership scenario and the NativeWidget
429 // being deleted out from under the Widget.
432 // Widget owns its NativeWidget, part 3: NativeWidget is a NativeWidget,
433 // destroy the parent view.
434 TEST_F(WidgetOwnershipTest
,
435 Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView
) {
436 OwnershipTestState state
;
438 Widget
* toplevel
= CreateTopLevelPlatformWidget();
440 scoped_ptr
<Widget
> widget(new OwnershipTestWidget(&state
));
441 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
442 params
.native_widget
=
443 new OwnershipTestNativeWidgetAura(widget
.get(), &state
);
444 params
.parent
= toplevel
->GetNativeView();
445 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
446 widget
->Init(params
);
448 // Now close the toplevel, which deletes the view hierarchy.
449 toplevel
->CloseNow();
451 RunPendingMessages();
453 // This shouldn't delete the widget because it shouldn't be deleted
454 // from the native side.
455 EXPECT_FALSE(state
.widget_deleted
);
456 EXPECT_FALSE(state
.native_widget_deleted
);
458 // Now delete it explicitly.
461 EXPECT_TRUE(state
.widget_deleted
);
462 EXPECT_TRUE(state
.native_widget_deleted
);
465 // NativeWidget owns its Widget, part 1: NativeWidget is a platform-native
467 TEST_F(WidgetOwnershipTest
, Ownership_PlatformNativeWidgetOwnsWidget
) {
468 OwnershipTestState state
;
470 Widget
* widget
= new OwnershipTestWidget(&state
);
471 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
472 params
.native_widget
=
473 new OwnershipTestNativeWidgetAura(widget
, &state
);
474 widget
->Init(params
);
476 // Now destroy the native widget.
479 EXPECT_TRUE(state
.widget_deleted
);
480 EXPECT_TRUE(state
.native_widget_deleted
);
483 // NativeWidget owns its Widget, part 2: NativeWidget is a NativeWidget.
484 TEST_F(WidgetOwnershipTest
, Ownership_ViewsNativeWidgetOwnsWidget
) {
485 OwnershipTestState state
;
487 Widget
* toplevel
= CreateTopLevelPlatformWidget();
489 Widget
* widget
= new OwnershipTestWidget(&state
);
490 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
491 params
.native_widget
=
492 new OwnershipTestNativeWidgetAura(widget
, &state
);
493 params
.parent
= toplevel
->GetNativeView();
494 widget
->Init(params
);
496 // Now destroy the native widget. This is achieved by closing the toplevel.
497 toplevel
->CloseNow();
499 // The NativeWidget won't be deleted until after a return to the message loop
500 // so we have to run pending messages before testing the destruction status.
501 RunPendingMessages();
503 EXPECT_TRUE(state
.widget_deleted
);
504 EXPECT_TRUE(state
.native_widget_deleted
);
507 // NativeWidget owns its Widget, part 3: NativeWidget is a platform-native
508 // widget, destroyed out from under it by the OS.
509 TEST_F(WidgetOwnershipTest
,
510 Ownership_PlatformNativeWidgetOwnsWidget_NativeDestroy
) {
511 OwnershipTestState state
;
513 Widget
* widget
= new OwnershipTestWidget(&state
);
514 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
515 params
.native_widget
=
516 new OwnershipTestNativeWidgetAura(widget
, &state
);
517 widget
->Init(params
);
519 // Now simulate a destroy of the platform native widget from the OS:
520 SimulateNativeDestroy(widget
);
522 EXPECT_TRUE(state
.widget_deleted
);
523 EXPECT_TRUE(state
.native_widget_deleted
);
526 // NativeWidget owns its Widget, part 4: NativeWidget is a NativeWidget,
527 // destroyed by the view hierarchy that contains it.
528 TEST_F(WidgetOwnershipTest
,
529 Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy
) {
530 OwnershipTestState state
;
532 Widget
* toplevel
= CreateTopLevelPlatformWidget();
534 Widget
* widget
= new OwnershipTestWidget(&state
);
535 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
536 params
.native_widget
=
537 new OwnershipTestNativeWidgetAura(widget
, &state
);
538 params
.parent
= toplevel
->GetNativeView();
539 widget
->Init(params
);
541 // Destroy the widget (achieved by closing the toplevel).
542 toplevel
->CloseNow();
544 // The NativeWidget won't be deleted until after a return to the message loop
545 // so we have to run pending messages before testing the destruction status.
546 RunPendingMessages();
548 EXPECT_TRUE(state
.widget_deleted
);
549 EXPECT_TRUE(state
.native_widget_deleted
);
552 // NativeWidget owns its Widget, part 5: NativeWidget is a NativeWidget,
553 // we close it directly.
554 TEST_F(WidgetOwnershipTest
,
555 Ownership_ViewsNativeWidgetOwnsWidget_Close
) {
556 OwnershipTestState state
;
558 Widget
* toplevel
= CreateTopLevelPlatformWidget();
560 Widget
* widget
= new OwnershipTestWidget(&state
);
561 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
562 params
.native_widget
=
563 new OwnershipTestNativeWidgetAura(widget
, &state
);
564 params
.parent
= toplevel
->GetNativeView();
565 widget
->Init(params
);
567 // Destroy the widget.
569 toplevel
->CloseNow();
571 // The NativeWidget won't be deleted until after a return to the message loop
572 // so we have to run pending messages before testing the destruction status.
573 RunPendingMessages();
575 EXPECT_TRUE(state
.widget_deleted
);
576 EXPECT_TRUE(state
.native_widget_deleted
);
579 // Widget owns its NativeWidget and has a WidgetDelegateView as its contents.
580 TEST_F(WidgetOwnershipTest
,
581 Ownership_WidgetOwnsNativeWidgetWithWithWidgetDelegateView
) {
582 OwnershipTestState state
;
584 WidgetDelegateView
* delegate_view
= new WidgetDelegateView
;
586 scoped_ptr
<Widget
> widget(new OwnershipTestWidget(&state
));
587 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
588 params
.native_widget
=
589 new OwnershipTestNativeWidgetAura(widget
.get(), &state
);
590 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
591 params
.delegate
= delegate_view
;
592 widget
->Init(params
);
593 widget
->SetContentsView(delegate_view
);
595 // Now delete the Widget. There should be no crash or use-after-free.
598 EXPECT_TRUE(state
.widget_deleted
);
599 EXPECT_TRUE(state
.native_widget_deleted
);
602 ////////////////////////////////////////////////////////////////////////////////
603 // Test to verify using various Widget methods doesn't crash when the underlying
604 // NativeView is destroyed.
606 class WidgetWithDestroyedNativeViewTest
: public ViewsTestBase
{
608 WidgetWithDestroyedNativeViewTest() {}
609 virtual ~WidgetWithDestroyedNativeViewTest() {}
611 void InvokeWidgetMethods(Widget
* widget
) {
612 widget
->GetNativeView();
613 widget
->GetNativeWindow();
614 ui::Accelerator accelerator
;
615 widget
->GetAccelerator(0, &accelerator
);
616 widget
->GetTopLevelWidget();
617 widget
->GetWindowBoundsInScreen();
618 widget
->GetClientAreaBoundsInScreen();
619 widget
->SetBounds(gfx::Rect(0, 0, 100, 80));
620 widget
->SetSize(gfx::Size(10, 11));
621 widget
->SetBoundsConstrained(gfx::Rect(0, 0, 120, 140));
622 widget
->SetVisibilityChangedAnimationsEnabled(false);
623 widget
->StackAtTop();
628 widget
->Deactivate();
630 widget
->DisableInactiveRendering();
631 widget
->SetAlwaysOnTop(true);
632 widget
->IsAlwaysOnTop();
636 widget
->IsMaximized();
637 widget
->IsFullscreen();
638 widget
->SetOpacity(0);
639 widget
->SetUseDragFrame(true);
640 widget
->FlashFrame(true);
642 widget
->GetThemeProvider();
643 widget
->GetNativeTheme();
644 widget
->GetFocusManager();
645 widget
->GetInputMethod();
646 widget
->SchedulePaintInRect(gfx::Rect(0, 0, 1, 2));
647 widget
->IsMouseEventsEnabled();
648 widget
->SetNativeWindowProperty("xx", widget
);
649 widget
->GetNativeWindowProperty("xx");
650 widget
->GetFocusTraversable();
652 widget
->ReorderNativeViews();
653 widget
->SetCapture(widget
->GetRootView());
654 widget
->ReleaseCapture();
655 widget
->HasCapture();
656 widget
->GetWorkAreaBoundsInScreen();
657 widget
->IsTranslucentWindowOpacitySupported();
661 DISALLOW_COPY_AND_ASSIGN(WidgetWithDestroyedNativeViewTest
);
664 TEST_F(WidgetWithDestroyedNativeViewTest
, Test
) {
667 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
668 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
672 widget
.native_widget_private()->CloseNow();
673 InvokeWidgetMethods(&widget
);
675 #if !defined(OS_CHROMEOS)
678 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
679 params
.native_widget
= new PlatformDesktopNativeWidget(&widget
);
680 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
684 widget
.native_widget_private()->CloseNow();
685 InvokeWidgetMethods(&widget
);
690 ////////////////////////////////////////////////////////////////////////////////
691 // Widget observer tests.
694 class WidgetObserverTest
: public WidgetTest
, public WidgetObserver
{
698 widget_closed_(NULL
),
699 widget_activated_(NULL
),
701 widget_hidden_(NULL
),
702 widget_bounds_changed_(NULL
) {
705 virtual ~WidgetObserverTest() {}
707 // Overridden from WidgetObserver:
708 virtual void OnWidgetDestroying(Widget
* widget
) OVERRIDE
{
709 if (active_
== widget
)
711 widget_closed_
= widget
;
714 virtual void OnWidgetActivationChanged(Widget
* widget
,
715 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 virtual void OnWidgetVisibilityChanged(Widget
* widget
,
729 bool visible
) OVERRIDE
{
731 widget_shown_
= widget
;
733 widget_hidden_
= widget
;
736 virtual void OnWidgetBoundsChanged(Widget
* widget
,
737 const gfx::Rect
& new_bounds
) OVERRIDE
{
738 widget_bounds_changed_
= widget
;
743 widget_closed_
= NULL
;
744 widget_activated_
= NULL
;
745 widget_deactivated_
= NULL
;
746 widget_shown_
= NULL
;
747 widget_hidden_
= NULL
;
748 widget_bounds_changed_
= NULL
;
751 Widget
* NewWidget() {
752 Widget
* widget
= CreateTopLevelNativeWidget();
753 widget
->AddObserver(this);
757 const Widget
* active() const { return active_
; }
758 const Widget
* widget_closed() const { return widget_closed_
; }
759 const Widget
* widget_activated() const { return widget_activated_
; }
760 const Widget
* widget_deactivated() const { return widget_deactivated_
; }
761 const Widget
* widget_shown() const { return widget_shown_
; }
762 const Widget
* widget_hidden() const { return widget_hidden_
; }
763 const Widget
* widget_bounds_changed() const { return widget_bounds_changed_
; }
768 Widget
* widget_closed_
;
769 Widget
* widget_activated_
;
770 Widget
* widget_deactivated_
;
771 Widget
* widget_shown_
;
772 Widget
* widget_hidden_
;
773 Widget
* widget_bounds_changed_
;
776 TEST_F(WidgetObserverTest
, DISABLED_ActivationChange
) {
777 Widget
* toplevel
= CreateTopLevelPlatformWidget();
779 Widget
* toplevel1
= NewWidget();
780 Widget
* toplevel2
= NewWidget();
787 toplevel1
->Activate();
789 RunPendingMessages();
790 EXPECT_EQ(toplevel1
, widget_activated());
792 toplevel2
->Activate();
793 RunPendingMessages();
794 EXPECT_EQ(toplevel1
, widget_deactivated());
795 EXPECT_EQ(toplevel2
, widget_activated());
796 EXPECT_EQ(toplevel2
, active());
798 toplevel
->CloseNow();
801 TEST_F(WidgetObserverTest
, DISABLED_VisibilityChange
) {
802 Widget
* toplevel
= CreateTopLevelPlatformWidget();
804 Widget
* child1
= NewWidget();
805 Widget
* child2
= NewWidget();
814 EXPECT_EQ(child1
, widget_hidden());
817 EXPECT_EQ(child2
, widget_hidden());
820 EXPECT_EQ(child1
, widget_shown());
823 EXPECT_EQ(child2
, widget_shown());
825 toplevel
->CloseNow();
828 TEST_F(WidgetObserverTest
, DestroyBubble
) {
829 Widget
* anchor
= CreateTopLevelPlatformWidget();
832 BubbleDelegateView
* bubble_delegate
=
833 new BubbleDelegateView(anchor
->client_view(), BubbleBorder::NONE
);
834 Widget
* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate
));
835 bubble_widget
->Show();
836 bubble_widget
->CloseNow();
842 TEST_F(WidgetObserverTest
, WidgetBoundsChanged
) {
843 Widget
* child1
= NewWidget();
844 Widget
* child2
= NewWidget();
846 child1
->OnNativeWidgetMove();
847 EXPECT_EQ(child1
, widget_bounds_changed());
849 child2
->OnNativeWidgetMove();
850 EXPECT_EQ(child2
, widget_bounds_changed());
852 child1
->OnNativeWidgetSizeChanged(gfx::Size());
853 EXPECT_EQ(child1
, widget_bounds_changed());
855 child2
->OnNativeWidgetSizeChanged(gfx::Size());
856 EXPECT_EQ(child2
, widget_bounds_changed());
859 // Tests that SetBounds() and GetWindowBoundsInScreen() is symmetric when the
860 // widget is visible and not maximized or fullscreen.
861 TEST_F(WidgetTest
, GetWindowBoundsInScreen
) {
862 // Choose test coordinates away from edges and dimensions that are "small"
863 // (but not too small) to ensure the OS doesn't try to adjust them.
864 const gfx::Rect
kTestBounds(150, 150, 400, 300);
865 const gfx::Size
kTestSize(200, 180);
867 // First test a toplevel widget.
868 Widget
* widget
= CreateTopLevelPlatformWidget();
871 EXPECT_NE(kTestSize
.ToString(),
872 widget
->GetWindowBoundsInScreen().size().ToString());
873 widget
->SetSize(kTestSize
);
874 EXPECT_EQ(kTestSize
.ToString(),
875 widget
->GetWindowBoundsInScreen().size().ToString());
877 EXPECT_NE(kTestBounds
.ToString(),
878 widget
->GetWindowBoundsInScreen().ToString());
879 widget
->SetBounds(kTestBounds
);
880 EXPECT_EQ(kTestBounds
.ToString(),
881 widget
->GetWindowBoundsInScreen().ToString());
883 // Changing just the size should not change the origin.
884 widget
->SetSize(kTestSize
);
885 EXPECT_EQ(kTestBounds
.origin().ToString(),
886 widget
->GetWindowBoundsInScreen().origin().ToString());
890 // Same tests with a frameless window.
891 widget
= CreateTopLevelFramelessPlatformWidget();
894 EXPECT_NE(kTestSize
.ToString(),
895 widget
->GetWindowBoundsInScreen().size().ToString());
896 widget
->SetSize(kTestSize
);
897 EXPECT_EQ(kTestSize
.ToString(),
898 widget
->GetWindowBoundsInScreen().size().ToString());
900 EXPECT_NE(kTestBounds
.ToString(),
901 widget
->GetWindowBoundsInScreen().ToString());
902 widget
->SetBounds(kTestBounds
);
903 EXPECT_EQ(kTestBounds
.ToString(),
904 widget
->GetWindowBoundsInScreen().ToString());
906 // For a frameless widget, the client bounds should also match.
907 EXPECT_EQ(kTestBounds
.ToString(),
908 widget
->GetClientAreaBoundsInScreen().ToString());
910 // Verify origin is stable for a frameless window as well.
911 widget
->SetSize(kTestSize
);
912 EXPECT_EQ(kTestBounds
.origin().ToString(),
913 widget
->GetWindowBoundsInScreen().origin().ToString());
919 // Aura needs shell to maximize/fullscreen window.
920 // NativeWidgetGtk doesn't implement GetRestoredBounds.
921 TEST_F(WidgetTest
, GetRestoredBounds
) {
922 Widget
* toplevel
= CreateTopLevelPlatformWidget();
923 EXPECT_EQ(toplevel
->GetWindowBoundsInScreen().ToString(),
924 toplevel
->GetRestoredBounds().ToString());
926 toplevel
->Maximize();
927 RunPendingMessages();
928 EXPECT_NE(toplevel
->GetWindowBoundsInScreen().ToString(),
929 toplevel
->GetRestoredBounds().ToString());
930 EXPECT_GT(toplevel
->GetRestoredBounds().width(), 0);
931 EXPECT_GT(toplevel
->GetRestoredBounds().height(), 0);
934 RunPendingMessages();
935 EXPECT_EQ(toplevel
->GetWindowBoundsInScreen().ToString(),
936 toplevel
->GetRestoredBounds().ToString());
938 toplevel
->SetFullscreen(true);
939 RunPendingMessages();
940 EXPECT_NE(toplevel
->GetWindowBoundsInScreen().ToString(),
941 toplevel
->GetRestoredBounds().ToString());
942 EXPECT_GT(toplevel
->GetRestoredBounds().width(), 0);
943 EXPECT_GT(toplevel
->GetRestoredBounds().height(), 0);
947 // Test that window state is not changed after getting out of full screen.
948 TEST_F(WidgetTest
, ExitFullscreenRestoreState
) {
949 Widget
* toplevel
= CreateTopLevelPlatformWidget();
952 RunPendingMessages();
954 // This should be a normal state window.
955 EXPECT_EQ(ui::SHOW_STATE_NORMAL
, GetWidgetShowState(toplevel
));
957 toplevel
->SetFullscreen(true);
958 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN
, GetWidgetShowState(toplevel
));
959 toplevel
->SetFullscreen(false);
960 EXPECT_NE(ui::SHOW_STATE_FULLSCREEN
, GetWidgetShowState(toplevel
));
962 // And it should still be in normal state after getting out of full screen.
963 EXPECT_EQ(ui::SHOW_STATE_NORMAL
, GetWidgetShowState(toplevel
));
965 // Now, make it maximized.
966 toplevel
->Maximize();
967 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED
, GetWidgetShowState(toplevel
));
969 toplevel
->SetFullscreen(true);
970 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN
, GetWidgetShowState(toplevel
));
971 toplevel
->SetFullscreen(false);
972 EXPECT_NE(ui::SHOW_STATE_FULLSCREEN
, GetWidgetShowState(toplevel
));
974 // And it stays maximized after getting out of full screen.
975 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED
, GetWidgetShowState(toplevel
));
979 RunPendingMessages();
982 // The key-event propagation from Widget happens differently on aura and
983 // non-aura systems because of the difference in IME. So this test works only on
985 TEST_F(WidgetTest
, KeyboardInputEvent
) {
986 Widget
* toplevel
= CreateTopLevelPlatformWidget();
987 View
* container
= toplevel
->client_view();
989 Textfield
* textfield
= new Textfield();
990 textfield
->SetText(base::ASCIIToUTF16("some text"));
991 container
->AddChildView(textfield
);
993 textfield
->RequestFocus();
995 // The press gets handled. The release doesn't have an effect.
996 ui::KeyEvent
backspace_p(ui::ET_KEY_PRESSED
, ui::VKEY_DELETE
, ui::EF_NONE
);
997 toplevel
->OnKeyEvent(&backspace_p
);
998 EXPECT_TRUE(backspace_p
.stopped_propagation());
999 ui::KeyEvent
backspace_r(ui::ET_KEY_RELEASED
, ui::VKEY_DELETE
, ui::EF_NONE
);
1000 toplevel
->OnKeyEvent(&backspace_r
);
1001 EXPECT_FALSE(backspace_r
.handled());
1006 // Verifies bubbles result in a focus lost when shown.
1007 // TODO(msw): this tests relies on focus, it needs to be in
1008 // interactive_ui_tests.
1009 TEST_F(WidgetTest
, DISABLED_FocusChangesOnBubble
) {
1010 // Create a widget, show and activate it and focus the contents view.
1011 View
* contents_view
= new View
;
1012 contents_view
->SetFocusable(true);
1014 Widget::InitParams init_params
=
1015 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS
);
1016 init_params
.bounds
= gfx::Rect(0, 0, 200, 200);
1017 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1018 #if !defined(OS_CHROMEOS)
1019 init_params
.native_widget
= new PlatformDesktopNativeWidget(&widget
);
1021 widget
.Init(init_params
);
1022 widget
.SetContentsView(contents_view
);
1025 contents_view
->RequestFocus();
1026 EXPECT_TRUE(contents_view
->HasFocus());
1029 BubbleDelegateView
* bubble_delegate_view
=
1030 new BubbleDelegateView(contents_view
, BubbleBorder::TOP_LEFT
);
1031 bubble_delegate_view
->SetFocusable(true);
1032 BubbleDelegateView::CreateBubble(bubble_delegate_view
)->Show();
1033 bubble_delegate_view
->RequestFocus();
1035 // |contents_view_| should no longer have focus.
1036 EXPECT_FALSE(contents_view
->HasFocus());
1037 EXPECT_TRUE(bubble_delegate_view
->HasFocus());
1039 bubble_delegate_view
->GetWidget()->CloseNow();
1041 // Closing the bubble should result in focus going back to the contents view.
1042 EXPECT_TRUE(contents_view
->HasFocus());
1045 class TestBubbleDelegateView
: public BubbleDelegateView
{
1047 TestBubbleDelegateView(View
* anchor
)
1048 : BubbleDelegateView(anchor
, BubbleBorder::NONE
),
1049 reset_controls_called_(false) {}
1050 virtual ~TestBubbleDelegateView() {}
1052 virtual bool ShouldShowCloseButton() const OVERRIDE
{
1053 reset_controls_called_
= true;
1057 mutable bool reset_controls_called_
;
1060 TEST_F(WidgetTest
, BubbleControlsResetOnInit
) {
1061 Widget
* anchor
= CreateTopLevelPlatformWidget();
1064 TestBubbleDelegateView
* bubble_delegate
=
1065 new TestBubbleDelegateView(anchor
->client_view());
1066 Widget
* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate
));
1067 EXPECT_TRUE(bubble_delegate
->reset_controls_called_
);
1068 bubble_widget
->Show();
1069 bubble_widget
->CloseNow();
1075 // Desktop native widget Aura tests are for non Chrome OS platforms.
1076 #if !defined(OS_CHROMEOS)
1077 // Test to ensure that after minimize, view width is set to zero.
1078 TEST_F(WidgetTest
, TestViewWidthAfterMinimizingWidget
) {
1081 Widget::InitParams init_params
=
1082 CreateParams(Widget::InitParams::TYPE_WINDOW
);
1083 init_params
.show_state
= ui::SHOW_STATE_NORMAL
;
1084 gfx::Rect
initial_bounds(0, 0, 300, 400);
1085 init_params
.bounds
= initial_bounds
;
1086 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1087 init_params
.native_widget
= new PlatformDesktopNativeWidget(&widget
);
1088 widget
.Init(init_params
);
1089 NonClientView
* non_client_view
= widget
.non_client_view();
1090 NonClientFrameView
* frame_view
= new MinimumSizeFrameView(&widget
);
1091 non_client_view
->SetFrameView(frame_view
);
1094 EXPECT_EQ(0, frame_view
->width());
1097 // This class validates whether paints are received for a visible Widget.
1098 // To achieve this it overrides the Show and Close methods on the Widget class
1099 // and sets state whether subsequent paints are expected.
1100 class DesktopAuraTestValidPaintWidget
: public views::Widget
{
1102 DesktopAuraTestValidPaintWidget()
1103 : expect_paint_(true),
1104 received_paint_while_hidden_(false) {
1107 virtual ~DesktopAuraTestValidPaintWidget() {
1110 virtual void Show() OVERRIDE
{
1111 expect_paint_
= true;
1112 views::Widget::Show();
1115 virtual void Close() OVERRIDE
{
1116 expect_paint_
= false;
1117 views::Widget::Close();
1121 expect_paint_
= false;
1122 views::Widget::Hide();
1125 virtual void OnNativeWidgetPaint(gfx::Canvas
* canvas
) OVERRIDE
{
1126 EXPECT_TRUE(expect_paint_
);
1128 received_paint_while_hidden_
= true;
1129 views::Widget::OnNativeWidgetPaint(canvas
);
1132 bool received_paint_while_hidden() const {
1133 return received_paint_while_hidden_
;
1138 bool received_paint_while_hidden_
;
1141 TEST_F(WidgetTest
, DesktopNativeWidgetNoPaintAfterCloseTest
) {
1142 View
* contents_view
= new View
;
1143 contents_view
->SetFocusable(true);
1144 DesktopAuraTestValidPaintWidget widget
;
1145 Widget::InitParams init_params
=
1146 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS
);
1147 init_params
.bounds
= gfx::Rect(0, 0, 200, 200);
1148 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1149 init_params
.native_widget
= new PlatformDesktopNativeWidget(&widget
);
1150 widget
.Init(init_params
);
1151 widget
.SetContentsView(contents_view
);
1154 RunPendingMessages();
1155 widget
.SchedulePaintInRect(init_params
.bounds
);
1157 RunPendingMessages();
1158 EXPECT_FALSE(widget
.received_paint_while_hidden());
1161 TEST_F(WidgetTest
, DesktopNativeWidgetNoPaintAfterHideTest
) {
1162 View
* contents_view
= new View
;
1163 contents_view
->SetFocusable(true);
1164 DesktopAuraTestValidPaintWidget widget
;
1165 Widget::InitParams init_params
=
1166 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS
);
1167 init_params
.bounds
= gfx::Rect(0, 0, 200, 200);
1168 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1169 init_params
.native_widget
= new PlatformDesktopNativeWidget(&widget
);
1170 widget
.Init(init_params
);
1171 widget
.SetContentsView(contents_view
);
1174 RunPendingMessages();
1175 widget
.SchedulePaintInRect(init_params
.bounds
);
1177 RunPendingMessages();
1178 EXPECT_FALSE(widget
.received_paint_while_hidden());
1182 // Test to ensure that the aura Window's visiblity state is set to visible if
1183 // the underlying widget is hidden and then shown.
1184 TEST_F(WidgetTest
, TestWindowVisibilityAfterHide
) {
1187 Widget::InitParams init_params
=
1188 CreateParams(Widget::InitParams::TYPE_WINDOW
);
1189 init_params
.show_state
= ui::SHOW_STATE_NORMAL
;
1190 gfx::Rect
initial_bounds(0, 0, 300, 400);
1191 init_params
.bounds
= initial_bounds
;
1192 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1193 init_params
.native_widget
= new PlatformDesktopNativeWidget(&widget
);
1194 widget
.Init(init_params
);
1195 NonClientView
* non_client_view
= widget
.non_client_view();
1196 NonClientFrameView
* frame_view
= new MinimumSizeFrameView(&widget
);
1197 non_client_view
->SetFrameView(frame_view
);
1200 EXPECT_FALSE(IsNativeWindowVisible(widget
.GetNativeWindow()));
1202 EXPECT_TRUE(IsNativeWindowVisible(widget
.GetNativeWindow()));
1205 // The following code verifies we can correctly destroy a Widget from a mouse
1206 // enter/exit. We could test move/drag/enter/exit but in general we don't run
1207 // nested message loops from such events, nor has the code ever really dealt
1208 // with this situation.
1210 // Generates two moves (first generates enter, second real move), a press, drag
1211 // and release stopping at |last_event_type|.
1212 void GenerateMouseEvents(Widget
* widget
, ui::EventType last_event_type
) {
1213 const gfx::Rect
screen_bounds(widget
->GetWindowBoundsInScreen());
1214 ui::MouseEvent
move_event(ui::ET_MOUSE_MOVED
, screen_bounds
.CenterPoint(),
1215 screen_bounds
.CenterPoint(), 0, 0);
1216 ui::EventProcessor
* dispatcher
= WidgetTest::GetEventProcessor(widget
);
1217 ui::EventDispatchDetails details
= dispatcher
->OnEventFromSource(&move_event
);
1218 if (last_event_type
== ui::ET_MOUSE_ENTERED
|| details
.dispatcher_destroyed
)
1220 details
= dispatcher
->OnEventFromSource(&move_event
);
1221 if (last_event_type
== ui::ET_MOUSE_MOVED
|| details
.dispatcher_destroyed
)
1224 ui::MouseEvent
press_event(ui::ET_MOUSE_PRESSED
, screen_bounds
.CenterPoint(),
1225 screen_bounds
.CenterPoint(), 0, 0);
1226 details
= dispatcher
->OnEventFromSource(&press_event
);
1227 if (last_event_type
== ui::ET_MOUSE_PRESSED
|| details
.dispatcher_destroyed
)
1230 gfx::Point
end_point(screen_bounds
.CenterPoint());
1231 end_point
.Offset(1, 1);
1232 ui::MouseEvent
drag_event(ui::ET_MOUSE_DRAGGED
, end_point
, end_point
, 0, 0);
1233 details
= dispatcher
->OnEventFromSource(&drag_event
);
1234 if (last_event_type
== ui::ET_MOUSE_DRAGGED
|| details
.dispatcher_destroyed
)
1237 ui::MouseEvent
release_event(ui::ET_MOUSE_RELEASED
, end_point
, end_point
, 0,
1239 details
= dispatcher
->OnEventFromSource(&release_event
);
1240 if (details
.dispatcher_destroyed
)
1244 // Creates a widget and invokes GenerateMouseEvents() with |last_event_type|.
1245 void RunCloseWidgetDuringDispatchTest(WidgetTest
* test
,
1246 ui::EventType last_event_type
) {
1247 // |widget| is deleted by CloseWidgetView.
1248 Widget
* widget
= new Widget
;
1249 Widget::InitParams params
=
1250 test
->CreateParams(Widget::InitParams::TYPE_POPUP
);
1251 params
.native_widget
= new PlatformDesktopNativeWidget(widget
);
1252 params
.bounds
= gfx::Rect(0, 0, 50, 100);
1253 widget
->Init(params
);
1254 widget
->SetContentsView(new CloseWidgetView(last_event_type
));
1256 GenerateMouseEvents(widget
, last_event_type
);
1259 // Verifies deleting the widget from a mouse pressed event doesn't crash.
1260 TEST_F(WidgetTest
, CloseWidgetDuringMousePress
) {
1261 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_PRESSED
);
1264 // Verifies deleting the widget from a mouse released event doesn't crash.
1265 TEST_F(WidgetTest
, CloseWidgetDuringMouseReleased
) {
1266 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_RELEASED
);
1269 #endif // !defined(OS_CHROMEOS)
1271 // Tests that wheel events generated from scroll events are targetted to the
1272 // views under the cursor when the focused view does not processed them.
1273 TEST_F(WidgetTest
, WheelEventsFromScrollEventTarget
) {
1274 EventCountView
* cursor_view
= new EventCountView
;
1275 cursor_view
->SetBounds(60, 0, 50, 40);
1277 Widget
* widget
= CreateTopLevelPlatformWidget();
1278 widget
->GetRootView()->AddChildView(cursor_view
);
1280 // Generate a scroll event on the cursor view.
1281 ui::ScrollEvent
scroll(ui::ET_SCROLL
,
1283 ui::EventTimeForNow(),
1288 widget
->OnScrollEvent(&scroll
);
1290 EXPECT_EQ(1, cursor_view
->GetEventCount(ui::ET_SCROLL
));
1291 EXPECT_EQ(1, cursor_view
->GetEventCount(ui::ET_MOUSEWHEEL
));
1293 cursor_view
->ResetCounts();
1295 ui::ScrollEvent
scroll2(ui::ET_SCROLL
,
1297 ui::EventTimeForNow(),
1302 widget
->OnScrollEvent(&scroll2
);
1304 EXPECT_EQ(0, cursor_view
->GetEventCount(ui::ET_SCROLL
));
1305 EXPECT_EQ(0, cursor_view
->GetEventCount(ui::ET_MOUSEWHEEL
));
1310 // Tests that if a scroll-begin gesture is not handled, then subsequent scroll
1311 // events are not dispatched to any view.
1312 TEST_F(WidgetTest
, GestureScrollEventDispatching
) {
1313 EventCountView
* noscroll_view
= new EventCountView
;
1314 EventCountView
* scroll_view
= new ScrollableEventCountView
;
1316 noscroll_view
->SetBounds(0, 0, 50, 40);
1317 scroll_view
->SetBounds(60, 0, 40, 40);
1319 Widget
* widget
= CreateTopLevelPlatformWidget();
1320 widget
->GetRootView()->AddChildView(noscroll_view
);
1321 widget
->GetRootView()->AddChildView(scroll_view
);
1324 ui::GestureEvent
begin(
1329 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN
, 0, 0));
1330 widget
->OnGestureEvent(&begin
);
1331 ui::GestureEvent
update(
1336 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE
, 20, 10));
1337 widget
->OnGestureEvent(&update
);
1338 ui::GestureEvent
end(
1343 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END
, 0, 0));
1344 widget
->OnGestureEvent(&end
);
1346 EXPECT_EQ(1, noscroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
1347 EXPECT_EQ(0, noscroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
1348 EXPECT_EQ(0, noscroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
1352 ui::GestureEvent
begin(
1357 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN
, 0, 0));
1358 widget
->OnGestureEvent(&begin
);
1359 ui::GestureEvent
update(
1364 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE
, 20, 10));
1365 widget
->OnGestureEvent(&update
);
1366 ui::GestureEvent
end(
1371 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END
, 0, 0));
1372 widget
->OnGestureEvent(&end
);
1374 EXPECT_EQ(1, scroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
1375 EXPECT_EQ(1, scroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
1376 EXPECT_EQ(1, scroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
1382 // Tests that event-handlers installed on the RootView get triggered correctly.
1383 // TODO(tdanderson): Clean up this test as part of crbug.com/355680.
1384 TEST_F(WidgetTest
, EventHandlersOnRootView
) {
1385 Widget
* widget
= CreateTopLevelNativeWidget();
1386 View
* root_view
= widget
->GetRootView();
1388 scoped_ptr
<EventCountView
> view(new EventCountView());
1389 view
->set_owned_by_client();
1390 view
->SetBounds(0, 0, 20, 20);
1391 root_view
->AddChildView(view
.get());
1393 EventCountHandler h1
;
1394 root_view
->AddPreTargetHandler(&h1
);
1396 EventCountHandler h2
;
1397 root_view
->AddPostTargetHandler(&h2
);
1399 widget
->SetBounds(gfx::Rect(0, 0, 100, 100));
1402 // Dispatch a ui::ET_SCROLL event. The event remains unhandled and should
1403 // bubble up the views hierarchy to be re-dispatched on the root view.
1404 ui::ScrollEvent
scroll(ui::ET_SCROLL
,
1406 ui::EventTimeForNow(),
1411 widget
->OnScrollEvent(&scroll
);
1412 EXPECT_EQ(2, h1
.GetEventCount(ui::ET_SCROLL
));
1413 EXPECT_EQ(1, view
->GetEventCount(ui::ET_SCROLL
));
1414 EXPECT_EQ(2, h2
.GetEventCount(ui::ET_SCROLL
));
1416 // Unhandled scroll events are turned into wheel events and re-dispatched.
1417 EXPECT_EQ(1, h1
.GetEventCount(ui::ET_MOUSEWHEEL
));
1418 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSEWHEEL
));
1419 EXPECT_EQ(1, h2
.GetEventCount(ui::ET_MOUSEWHEEL
));
1422 view
->ResetCounts();
1425 // Dispatch a ui::ET_SCROLL_FLING_START event. The event remains unhandled and
1426 // should bubble up the views hierarchy to be re-dispatched on the root view.
1427 ui::ScrollEvent
fling(ui::ET_SCROLL_FLING_START
,
1429 ui::EventTimeForNow(),
1434 widget
->OnScrollEvent(&fling
);
1435 EXPECT_EQ(2, h1
.GetEventCount(ui::ET_SCROLL_FLING_START
));
1436 EXPECT_EQ(1, view
->GetEventCount(ui::ET_SCROLL_FLING_START
));
1437 EXPECT_EQ(2, h2
.GetEventCount(ui::ET_SCROLL_FLING_START
));
1439 // Unhandled scroll events which are not of type ui::ET_SCROLL should not
1440 // be turned into wheel events and re-dispatched.
1441 EXPECT_EQ(0, h1
.GetEventCount(ui::ET_MOUSEWHEEL
));
1442 EXPECT_EQ(0, view
->GetEventCount(ui::ET_MOUSEWHEEL
));
1443 EXPECT_EQ(0, h2
.GetEventCount(ui::ET_MOUSEWHEEL
));
1446 view
->ResetCounts();
1449 // Change the handle mode of |view| so that events are marked as handled at
1450 // the target phase.
1451 view
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
1453 // Dispatch a ui::ET_GESTURE_TAP_DOWN and a ui::ET_GESTURE_TAP_CANCEL event.
1454 // The events are handled at the target phase and should not reach the
1455 // post-target handler.
1456 ui::GestureEvent
tap_down(5,
1459 ui::EventTimeForNow(),
1460 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN
,
1463 widget
->OnGestureEvent(&tap_down
);
1464 EXPECT_EQ(1, h1
.GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
1465 EXPECT_EQ(1, view
->GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
1466 EXPECT_EQ(0, h2
.GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
1468 ui::GestureEvent
tap_cancel(5,
1471 ui::EventTimeForNow(),
1472 ui::GestureEventDetails(ui::ET_GESTURE_TAP_CANCEL
,
1475 widget
->OnGestureEvent(&tap_cancel
);
1476 EXPECT_EQ(1, h1
.GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
1477 EXPECT_EQ(1, view
->GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
1478 EXPECT_EQ(0, h2
.GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
1481 view
->ResetCounts();
1484 // Dispatch a ui::ET_SCROLL event. The event is handled at the target phase
1485 // and should not reach the post-target handler.
1486 ui::ScrollEvent
consumed_scroll(ui::ET_SCROLL
,
1488 ui::EventTimeForNow(),
1493 widget
->OnScrollEvent(&consumed_scroll
);
1494 EXPECT_EQ(1, h1
.GetEventCount(ui::ET_SCROLL
));
1495 EXPECT_EQ(1, view
->GetEventCount(ui::ET_SCROLL
));
1496 EXPECT_EQ(0, h2
.GetEventCount(ui::ET_SCROLL
));
1498 // Handled scroll events are not turned into wheel events and re-dispatched.
1499 EXPECT_EQ(0, h1
.GetEventCount(ui::ET_MOUSEWHEEL
));
1500 EXPECT_EQ(0, view
->GetEventCount(ui::ET_MOUSEWHEEL
));
1501 EXPECT_EQ(0, h2
.GetEventCount(ui::ET_MOUSEWHEEL
));
1506 TEST_F(WidgetTest
, SynthesizeMouseMoveEvent
) {
1507 Widget
* widget
= CreateTopLevelNativeWidget();
1508 View
* root_view
= widget
->GetRootView();
1510 EventCountView
* v1
= new EventCountView();
1511 v1
->SetBounds(0, 0, 10, 10);
1512 root_view
->AddChildView(v1
);
1513 EventCountView
* v2
= new EventCountView();
1514 v2
->SetBounds(0, 10, 10, 10);
1515 root_view
->AddChildView(v2
);
1517 gfx::Point
cursor_location(5, 5);
1518 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
, cursor_location
, cursor_location
,
1519 ui::EF_NONE
, ui::EF_NONE
);
1520 widget
->OnMouseEvent(&move
);
1522 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_MOUSE_ENTERED
));
1523 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_MOUSE_ENTERED
));
1526 v2
->SetBounds(0, 0, 10, 10);
1527 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_MOUSE_ENTERED
));
1529 widget
->SynthesizeMouseMoveEvent();
1530 EXPECT_EQ(1, v2
->GetEventCount(ui::ET_MOUSE_ENTERED
));
1535 // ui::EventHandler which handles all mouse press events.
1536 class MousePressEventConsumer
: public ui::EventHandler
{
1538 explicit MousePressEventConsumer() {
1541 virtual ~MousePressEventConsumer() {
1545 // ui::EventHandler:
1546 virtual void OnMouseEvent(ui::MouseEvent
* event
) OVERRIDE
{
1547 if (event
->type() == ui::ET_MOUSE_PRESSED
)
1548 event
->SetHandled();
1551 DISALLOW_COPY_AND_ASSIGN(MousePressEventConsumer
);
1556 // Test that mouse presses and mouse releases are dispatched normally when a
1558 TEST_F(WidgetTest
, MouseEventDispatchWhileTouchIsDown
) {
1559 Widget
* widget
= CreateTopLevelNativeWidget();
1561 widget
->SetSize(gfx::Size(300, 300));
1563 EventCountView
* event_count_view
= new EventCountView();
1564 event_count_view
->SetBounds(0, 0, 300, 300);
1565 widget
->GetRootView()->AddChildView(event_count_view
);
1567 MousePressEventConsumer consumer
;
1568 event_count_view
->AddPostTargetHandler(&consumer
);
1570 ui::test::EventGenerator
generator(GetContext(), widget
->GetNativeWindow());
1571 generator
.PressTouch();
1572 generator
.ClickLeftButton();
1574 EXPECT_EQ(1, event_count_view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
1575 EXPECT_EQ(1, event_count_view
->GetEventCount(ui::ET_MOUSE_RELEASED
));
1580 // Used by SingleWindowClosing to count number of times WindowClosing() has
1582 class ClosingDelegate
: public WidgetDelegate
{
1584 ClosingDelegate() : count_(0), widget_(NULL
) {}
1586 int count() const { return count_
; }
1588 void set_widget(views::Widget
* widget
) { widget_
= widget
; }
1590 // WidgetDelegate overrides:
1591 virtual Widget
* GetWidget() OVERRIDE
{ return widget_
; }
1592 virtual const Widget
* GetWidget() const OVERRIDE
{ return widget_
; }
1593 virtual void WindowClosing() OVERRIDE
{
1599 views::Widget
* widget_
;
1601 DISALLOW_COPY_AND_ASSIGN(ClosingDelegate
);
1604 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget
1606 TEST_F(WidgetTest
, SingleWindowClosing
) {
1607 scoped_ptr
<ClosingDelegate
> delegate(new ClosingDelegate());
1608 Widget
* widget
= new Widget(); // Destroyed by CloseNow() below.
1609 Widget::InitParams init_params
=
1610 CreateParams(Widget::InitParams::TYPE_WINDOW
);
1611 init_params
.bounds
= gfx::Rect(0, 0, 200, 200);
1612 init_params
.delegate
= delegate
.get();
1613 #if !defined(OS_CHROMEOS)
1614 init_params
.native_widget
= new PlatformDesktopNativeWidget(widget
);
1616 widget
->Init(init_params
);
1617 EXPECT_EQ(0, delegate
->count());
1619 EXPECT_EQ(1, delegate
->count());
1622 class WidgetWindowTitleTest
: public WidgetTest
{
1624 void RunTest(bool desktop_native_widget
) {
1625 Widget
* widget
= new Widget(); // Destroyed by CloseNow() below.
1626 Widget::InitParams init_params
=
1627 CreateParams(Widget::InitParams::TYPE_WINDOW
);
1628 widget
->Init(init_params
);
1630 #if !defined(OS_CHROMEOS)
1631 if (desktop_native_widget
)
1632 init_params
.native_widget
= new PlatformDesktopNativeWidget(widget
);
1634 DCHECK(!desktop_native_widget
)
1635 << "DesktopNativeWidget does not exist on non-Aura or on ChromeOS.";
1638 internal::NativeWidgetPrivate
* native_widget
=
1639 widget
->native_widget_private();
1641 base::string16 empty
;
1642 base::string16
s1(base::UTF8ToUTF16("Title1"));
1643 base::string16
s2(base::UTF8ToUTF16("Title2"));
1644 base::string16
s3(base::UTF8ToUTF16("TitleLong"));
1646 // The widget starts with no title, setting empty should not change
1648 EXPECT_FALSE(native_widget
->SetWindowTitle(empty
));
1649 // Setting the title to something non-empty should cause a change.
1650 EXPECT_TRUE(native_widget
->SetWindowTitle(s1
));
1651 // Setting the title to something else with the same length should cause a
1653 EXPECT_TRUE(native_widget
->SetWindowTitle(s2
));
1654 // Setting the title to something else with a different length should cause
1656 EXPECT_TRUE(native_widget
->SetWindowTitle(s3
));
1657 // Setting the title to the same thing twice should not cause a change.
1658 EXPECT_FALSE(native_widget
->SetWindowTitle(s3
));
1664 TEST_F(WidgetWindowTitleTest
, SetWindowTitleChanged_NativeWidget
) {
1665 // Use the default NativeWidget.
1666 bool desktop_native_widget
= false;
1667 RunTest(desktop_native_widget
);
1670 // DesktopNativeWidget does not exist on non-Aura or on ChromeOS.
1671 #if !defined(OS_CHROMEOS)
1672 TEST_F(WidgetWindowTitleTest
, SetWindowTitleChanged_DesktopNativeWidget
) {
1673 // Override to use a DesktopNativeWidget.
1674 bool desktop_native_widget
= true;
1675 RunTest(desktop_native_widget
);
1677 #endif // !OS_CHROMEOS
1679 TEST_F(WidgetTest
, WidgetDeleted_InOnMousePressed
) {
1680 Widget
* widget
= new Widget
;
1681 Widget::InitParams params
=
1682 CreateParams(views::Widget::InitParams::TYPE_POPUP
);
1683 widget
->Init(params
);
1685 widget
->SetContentsView(new CloseWidgetView(ui::ET_MOUSE_PRESSED
));
1687 widget
->SetSize(gfx::Size(100, 100));
1690 ui::test::EventGenerator
generator(GetContext(), widget
->GetNativeWindow());
1692 WidgetDeletionObserver
deletion_observer(widget
);
1693 generator
.ClickLeftButton();
1694 EXPECT_FALSE(deletion_observer
.IsWidgetAlive());
1696 // Yay we did not crash!
1699 TEST_F(WidgetTest
, WidgetDeleted_InDispatchGestureEvent
) {
1700 Widget
* widget
= new Widget
;
1701 Widget::InitParams params
=
1702 CreateParams(views::Widget::InitParams::TYPE_POPUP
);
1703 widget
->Init(params
);
1705 widget
->SetContentsView(new CloseWidgetView(ui::ET_GESTURE_TAP_DOWN
));
1707 widget
->SetSize(gfx::Size(100, 100));
1710 ui::test::EventGenerator
generator(GetContext(), widget
->GetNativeWindow());
1712 WidgetDeletionObserver
deletion_observer(widget
);
1713 generator
.GestureTapAt(widget
->GetWindowBoundsInScreen().CenterPoint());
1714 EXPECT_FALSE(deletion_observer
.IsWidgetAlive());
1716 // Yay we did not crash!
1719 // See description of RunGetNativeThemeFromDestructor() for details.
1720 class GetNativeThemeFromDestructorView
: public WidgetDelegateView
{
1722 GetNativeThemeFromDestructorView() {}
1723 virtual ~GetNativeThemeFromDestructorView() {
1724 VerifyNativeTheme();
1727 virtual View
* GetContentsView() OVERRIDE
{
1732 void VerifyNativeTheme() {
1733 ASSERT_TRUE(GetNativeTheme() != NULL
);
1736 DISALLOW_COPY_AND_ASSIGN(GetNativeThemeFromDestructorView
);
1739 // Verifies GetNativeTheme() from the destructor of a WidgetDelegateView doesn't
1740 // crash. |is_first_run| is true if this is the first call. A return value of
1741 // true indicates this should be run again with a value of false.
1742 // First run uses DesktopNativeWidgetAura (if possible). Second run doesn't.
1743 bool RunGetNativeThemeFromDestructor(const Widget::InitParams
& in_params
,
1744 bool is_first_run
) {
1745 bool needs_second_run
= false;
1746 // Destroyed by CloseNow() below.
1747 Widget
* widget
= new Widget
;
1748 Widget::InitParams
params(in_params
);
1749 // Deletes itself when the Widget is destroyed.
1750 params
.delegate
= new GetNativeThemeFromDestructorView
;
1751 #if !defined(OS_CHROMEOS)
1753 params
.native_widget
= new PlatformDesktopNativeWidget(widget
);
1754 needs_second_run
= true;
1757 widget
->Init(params
);
1759 return needs_second_run
;
1762 // See description of RunGetNativeThemeFromDestructor() for details.
1763 TEST_F(WidgetTest
, GetNativeThemeFromDestructor
) {
1764 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
1765 if (RunGetNativeThemeFromDestructor(params
, true))
1766 RunGetNativeThemeFromDestructor(params
, false);
1769 // Used by HideCloseDestroy. Allows setting a boolean when the widget is
1771 class CloseDestroysWidget
: public Widget
{
1773 explicit CloseDestroysWidget(bool* destroyed
)
1774 : destroyed_(destroyed
) {
1777 virtual ~CloseDestroysWidget() {
1780 base::MessageLoop::current()->QuitNow();
1784 void Detach() { destroyed_
= NULL
; }
1787 // If non-null set to true from destructor.
1790 DISALLOW_COPY_AND_ASSIGN(CloseDestroysWidget
);
1793 // An observer that registers that an animation has ended.
1794 class AnimationEndObserver
: public ui::ImplicitAnimationObserver
{
1796 AnimationEndObserver() : animation_completed_(false) {}
1797 virtual ~AnimationEndObserver() {}
1799 bool animation_completed() const { return animation_completed_
; }
1801 // ui::ImplicitAnimationObserver:
1802 virtual void OnImplicitAnimationsCompleted() OVERRIDE
{
1803 animation_completed_
= true;
1807 bool animation_completed_
;
1809 DISALLOW_COPY_AND_ASSIGN(AnimationEndObserver
);
1812 // An observer that registers the bounds of a widget on destruction.
1813 class WidgetBoundsObserver
: public WidgetObserver
{
1815 WidgetBoundsObserver() {}
1816 virtual ~WidgetBoundsObserver() {}
1818 gfx::Rect
bounds() { return bounds_
; }
1821 virtual void OnWidgetDestroying(Widget
* widget
) OVERRIDE
{
1822 bounds_
= widget
->GetWindowBoundsInScreen();
1828 DISALLOW_COPY_AND_ASSIGN(WidgetBoundsObserver
);
1831 // Verifies Close() results in destroying.
1832 TEST_F(WidgetTest
, CloseDestroys
) {
1833 bool destroyed
= false;
1834 CloseDestroysWidget
* widget
= new CloseDestroysWidget(&destroyed
);
1835 Widget::InitParams params
=
1836 CreateParams(views::Widget::InitParams::TYPE_MENU
);
1837 params
.opacity
= Widget::InitParams::OPAQUE_WINDOW
;
1838 #if !defined(OS_CHROMEOS)
1839 params
.native_widget
= new PlatformDesktopNativeWidget(widget
);
1841 widget
->Init(params
);
1845 EXPECT_FALSE(destroyed
);
1846 // Run the message loop as Close() asynchronously deletes.
1847 base::RunLoop().Run();
1848 EXPECT_TRUE(destroyed
);
1849 // Close() should destroy the widget. If not we'll cleanup to avoid leaks.
1856 // Tests that killing a widget while animating it does not crash.
1857 TEST_F(WidgetTest
, CloseWidgetWhileAnimating
) {
1858 scoped_ptr
<Widget
> widget(new Widget
);
1859 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
1860 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1861 params
.bounds
= gfx::Rect(50, 50, 250, 250);
1862 widget
->Init(params
);
1863 AnimationEndObserver animation_observer
;
1864 WidgetBoundsObserver widget_observer
;
1865 gfx::Rect
bounds(0, 0, 50, 50);
1867 // Normal animations for tests have ZERO_DURATION, make sure we are actually
1868 // animating the movement.
1869 ui::ScopedAnimationDurationScaleMode
animation_scale_mode(
1870 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION
);
1871 ui::ScopedLayerAnimationSettings
animation_settings(
1872 widget
->GetLayer()->GetAnimator());
1873 animation_settings
.AddObserver(&animation_observer
);
1874 widget
->AddObserver(&widget_observer
);
1877 // Animate the bounds change.
1878 widget
->SetBounds(bounds
);
1880 EXPECT_FALSE(animation_observer
.animation_completed());
1882 EXPECT_TRUE(animation_observer
.animation_completed());
1883 EXPECT_EQ(widget_observer
.bounds(), bounds
);
1886 // A view that consumes mouse-pressed event and gesture-tap-down events.
1887 class RootViewTestView
: public View
{
1889 RootViewTestView(): View() {}
1892 virtual bool OnMousePressed(const ui::MouseEvent
& event
) OVERRIDE
{
1896 virtual void OnGestureEvent(ui::GestureEvent
* event
) OVERRIDE
{
1897 if (event
->type() == ui::ET_GESTURE_TAP_DOWN
)
1898 event
->SetHandled();
1902 // Checks if RootView::*_handler_ fields are unset when widget is hidden.
1903 // Fails on chromium.webkit Windows bot, see crbug.com/264872.
1905 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1906 DISABLED_TestRootViewHandlersWhenHidden
1908 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1909 TestRootViewHandlersWhenHidden
1911 TEST_F(WidgetTest
, MAYBE_DisableTestRootViewHandlersWhenHidden
) {
1912 Widget
* widget
= CreateTopLevelNativeWidget();
1913 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
1914 View
* view
= new RootViewTestView();
1915 view
->SetBounds(0, 0, 300, 300);
1916 internal::RootView
* root_view
=
1917 static_cast<internal::RootView
*>(widget
->GetRootView());
1918 root_view
->AddChildView(view
);
1920 // Check RootView::mouse_pressed_handler_.
1922 EXPECT_EQ(NULL
, GetMousePressedHandler(root_view
));
1923 gfx::Point
click_location(45, 15);
1924 ui::MouseEvent
press(ui::ET_MOUSE_PRESSED
, click_location
, click_location
,
1925 ui::EF_LEFT_MOUSE_BUTTON
, ui::EF_LEFT_MOUSE_BUTTON
);
1926 widget
->OnMouseEvent(&press
);
1927 EXPECT_EQ(view
, GetMousePressedHandler(root_view
));
1929 EXPECT_EQ(NULL
, GetMousePressedHandler(root_view
));
1931 // Check RootView::mouse_move_handler_.
1933 EXPECT_EQ(NULL
, GetMouseMoveHandler(root_view
));
1934 gfx::Point
move_location(45, 15);
1935 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
, move_location
, move_location
, 0, 0);
1936 widget
->OnMouseEvent(&move
);
1937 EXPECT_EQ(view
, GetMouseMoveHandler(root_view
));
1939 EXPECT_EQ(NULL
, GetMouseMoveHandler(root_view
));
1941 // Check RootView::gesture_handler_.
1943 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
1944 ui::GestureEvent
tap_down(
1949 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN
, 0, 0));
1950 widget
->OnGestureEvent(&tap_down
);
1951 EXPECT_EQ(view
, GetGestureHandler(root_view
));
1953 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
1958 // Convenience to make constructing a GestureEvent simpler.
1959 class GestureEventForTest
: public ui::GestureEvent
{
1961 GestureEventForTest(ui::EventType type
, int x
, int y
)
1966 ui::GestureEventDetails(type
, 0.0f
, 0.0f
)) {}
1968 GestureEventForTest(ui::GestureEventDetails details
, int x
, int y
)
1969 : GestureEvent(x
, y
, 0, base::TimeDelta(), details
) {}
1972 // Tests that the |gesture_handler_| member in RootView is always NULL
1973 // after the dispatch of a ui::ET_GESTURE_END event corresponding to
1974 // the release of the final touch point on the screen and that
1975 // ui::ET_GESTURE_END events corresponding to the removal of any other touch
1976 // point are never dispatched to a view. Also verifies that
1977 // ui::ET_GESTURE_BEGIN is never dispatched to a view and does not change the
1978 // value of |gesture_handler_|.
1979 TEST_F(WidgetTest
, GestureBeginAndEndEvents
) {
1980 Widget
* widget
= CreateTopLevelNativeWidget();
1981 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
1982 EventCountView
* view
= new EventCountView();
1983 view
->SetBounds(0, 0, 300, 300);
1984 internal::RootView
* root_view
=
1985 static_cast<internal::RootView
*>(widget
->GetRootView());
1986 root_view
->AddChildView(view
);
1989 // If no gesture handler is set, dispatching a ui::ET_GESTURE_END or
1990 // ui::ET_GESTURE_BEGIN event should not set the gesture handler and
1991 // the events should remain unhandled because the handle mode of |view|
1992 // indicates that events should not be consumed.
1993 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
1994 GestureEventForTest
end(ui::ET_GESTURE_END
, 15, 15);
1995 widget
->OnGestureEvent(&end
);
1996 EXPECT_FALSE(end
.handled());
1997 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
1999 GestureEventForTest
begin(ui::ET_GESTURE_BEGIN
, 15, 15);
2000 widget
->OnGestureEvent(&begin
);
2001 EXPECT_FALSE(begin
.handled());
2002 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2004 // Change the handle mode of |view| to indicate that it would like
2005 // to handle all events.
2006 view
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2008 // If no gesture handler is set, dispatching only a ui::ET_GESTURE_BEGIN
2009 // should not set the gesture handler and should not be marked as handled
2010 // because it is never dispatched.
2011 begin
= GestureEventForTest(ui::ET_GESTURE_BEGIN
, 15, 15);
2012 widget
->OnGestureEvent(&begin
);
2013 EXPECT_FALSE(begin
.handled());
2014 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2016 // If no gesture handler is set, dispatching only a ui::ET_GESTURE_BEGIN
2017 // corresponding to a second touch point should not set the gesture handler
2018 // and should not be marked as handled because it is never dispatched.
2019 ui::GestureEventDetails
details(ui::ET_GESTURE_END
, 15, 15);
2020 details
.set_touch_points(2);
2021 GestureEventForTest
end_second_touch_point(details
, 15, 15);
2022 widget
->OnGestureEvent(&end_second_touch_point
);
2023 EXPECT_FALSE(end_second_touch_point
.handled());
2024 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2026 // If no gesture handler is set, dispatching only a ui::ET_GESTURE_END
2027 // event corresponding to the final touch point should not set the gesture
2028 // handler, but it should be marked as handled because it was dispatched to
2029 // the view targeted by the event's location.
2030 end
= GestureEventForTest(ui::ET_GESTURE_END
, 15, 15);
2031 widget
->OnGestureEvent(&end
);
2032 EXPECT_TRUE(end
.handled());
2033 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2035 // If the gesture handler has been set by a previous gesture, then it should
2036 // remain unchanged on a ui::ET_GESTURE_BEGIN or a ui::ET_GESTURE_END
2037 // corresponding to a second touch point. It should be reset to NULL by a
2038 // ui::ET_GESTURE_END corresponding to the final touch point.
2039 GestureEventForTest
tap(ui::ET_GESTURE_TAP
, 15, 15);
2040 widget
->OnGestureEvent(&tap
);
2041 EXPECT_TRUE(tap
.handled());
2042 EXPECT_EQ(view
, GetGestureHandler(root_view
));
2044 begin
= GestureEventForTest(ui::ET_GESTURE_BEGIN
, 15, 15);
2045 widget
->OnGestureEvent(&begin
);
2046 EXPECT_FALSE(begin
.handled());
2047 EXPECT_EQ(view
, GetGestureHandler(root_view
));
2049 end_second_touch_point
= GestureEventForTest(details
, 15, 15);
2050 widget
->OnGestureEvent(&end_second_touch_point
);
2051 EXPECT_FALSE(end_second_touch_point
.handled());
2052 EXPECT_EQ(view
, GetGestureHandler(root_view
));
2054 end
= GestureEventForTest(ui::ET_GESTURE_END
, 15, 15);
2055 widget
->OnGestureEvent(&end
);
2056 EXPECT_TRUE(end
.handled());
2057 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2059 // If the gesture handler has been set by a previous gesture, then
2060 // it should remain unchanged on a ui::ET_GESTURE_BEGIN or a
2061 // ui::ET_GESTURE_END corresponding to a second touch point and be reset
2062 // to NULL by a ui::ET_GESTURE_END corresponding to the final touch point,
2063 // even when the gesture handler has indicated that it would not like to
2064 // handle any further events.
2065 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 15, 15);
2066 widget
->OnGestureEvent(&tap
);
2067 EXPECT_TRUE(tap
.handled());
2068 EXPECT_EQ(view
, GetGestureHandler(root_view
));
2070 // Change the handle mode of |view| to indicate that it does not want
2071 // to handle any further events.
2072 view
->set_handle_mode(EventCountView::PROPAGATE_EVENTS
);
2074 begin
= GestureEventForTest(ui::ET_GESTURE_BEGIN
, 15, 15);
2075 widget
->OnGestureEvent(&begin
);
2076 EXPECT_FALSE(begin
.handled());
2077 EXPECT_EQ(view
, GetGestureHandler(root_view
));
2079 end_second_touch_point
= GestureEventForTest(details
, 15, 15);
2080 widget
->OnGestureEvent(&end_second_touch_point
);
2081 EXPECT_FALSE(end_second_touch_point
.handled());
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 a (non-scroll) gesture event is dispatched to the correct views
2093 // in a view hierarchy and that the default gesture handler in RootView is set
2095 TEST_F(WidgetTest
, GestureEventDispatch
) {
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 // No gesture handler is set in the root view and none of the views in the
2123 // view hierarchy handle a ui::ET_GESTURE_TAP event. In this case the tap
2124 // event should be dispatched to all views in the hierarchy, the gesture
2125 // handler should remain unset, and the event should remain unhandled.
2126 GestureEventForTest
tap(ui::ET_GESTURE_TAP
, 5, 5);
2127 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2128 widget
->OnGestureEvent(&tap
);
2129 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2130 EXPECT_EQ(1, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2131 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2132 EXPECT_EQ(1, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2133 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2134 EXPECT_FALSE(tap
.handled());
2136 // No gesture handler is set in the root view and |v1|, |v2|, and |v3| all
2137 // handle a ui::ET_GESTURE_TAP event. In this case the tap event should be
2138 // dispatched to |v4| and |v3|, the gesture handler should be set to |v3|,
2139 // and the event should be marked as handled.
2144 v1
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2145 v2
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2146 v3
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2147 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2148 widget
->OnGestureEvent(&tap
);
2149 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2150 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2151 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2152 EXPECT_EQ(1, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2153 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2154 EXPECT_TRUE(tap
.handled());
2156 // The gesture handler is set to |v3| and all views handle all gesture event
2157 // types. In this case subsequent gesture events should only be dispatched to
2158 // |v3| and marked as handled. The gesture handler should remain as |v3|.
2163 v4
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2164 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2165 widget
->OnGestureEvent(&tap
);
2166 EXPECT_TRUE(tap
.handled());
2167 GestureEventForTest
show_press(ui::ET_GESTURE_SHOW_PRESS
, 5, 5);
2168 widget
->OnGestureEvent(&show_press
);
2169 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2170 widget
->OnGestureEvent(&tap
);
2171 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2172 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2173 EXPECT_EQ(2, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2174 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2175 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_SHOW_PRESS
));
2176 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_SHOW_PRESS
));
2177 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_SHOW_PRESS
));
2178 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_SHOW_PRESS
));
2179 EXPECT_TRUE(tap
.handled());
2180 EXPECT_TRUE(show_press
.handled());
2181 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2183 // The gesture handler is set to |v3|, but |v3| does not handle
2184 // ui::ET_GESTURE_TAP events. In this case a tap gesture should be dispatched
2185 // only to |v3|, but the event should remain unhandled. The gesture handler
2186 // should remain as |v3|.
2191 v3
->set_handle_mode(EventCountView::PROPAGATE_EVENTS
);
2192 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2193 widget
->OnGestureEvent(&tap
);
2194 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2195 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2196 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2197 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2198 EXPECT_FALSE(tap
.handled());
2199 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2204 // Tests that gesture scroll events will change the default gesture handler in
2205 // RootView if the current handler to which they are dispatched does not handle
2206 // gesture scroll events.
2207 TEST_F(WidgetTest
, ScrollGestureEventDispatch
) {
2208 Widget
* widget
= CreateTopLevelNativeWidget();
2209 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
2211 // Define a hierarchy of four views (coordinates are in
2212 // their parent coordinate space).
2213 // v1 (0, 0, 300, 300)
2214 // v2 (0, 0, 100, 100)
2215 // v3 (0, 0, 50, 50)
2217 EventCountView
* v1
= new EventCountView();
2218 v1
->SetBounds(0, 0, 300, 300);
2219 EventCountView
* v2
= new EventCountView();
2220 v2
->SetBounds(0, 0, 100, 100);
2221 EventCountView
* v3
= new EventCountView();
2222 v3
->SetBounds(0, 0, 50, 50);
2223 EventCountView
* v4
= new EventCountView();
2224 v4
->SetBounds(0, 0, 10, 10);
2225 internal::RootView
* root_view
=
2226 static_cast<internal::RootView
*>(widget
->GetRootView());
2227 root_view
->AddChildView(v1
);
2228 v1
->AddChildView(v2
);
2229 v2
->AddChildView(v3
);
2230 v3
->AddChildView(v4
);
2234 // Change the handle mode of |v3| to indicate that it would like to handle
2236 v3
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2238 // When no gesture handler is set, dispatching a ui::ET_GESTURE_TAP_DOWN
2239 // should bubble up the views hierarchy until it reaches the first view
2240 // that will handle it (|v3|) and then sets the handler to |v3|.
2241 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2242 GestureEventForTest
tap_down(ui::ET_GESTURE_TAP_DOWN
, 5, 5);
2243 widget
->OnGestureEvent(&tap_down
);
2244 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
2245 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
2246 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
2247 EXPECT_EQ(1, v4
->GetEventCount(ui::ET_GESTURE_TAP_DOWN
));
2248 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2249 EXPECT_TRUE(tap_down
.handled());
2255 // A ui::ET_GESTURE_TAP_CANCEL event should be dispatched to |v3| directly.
2256 GestureEventForTest
tap_cancel(ui::ET_GESTURE_TAP_CANCEL
, 5, 5);
2257 widget
->OnGestureEvent(&tap_cancel
);
2258 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
2259 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
2260 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
2261 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_TAP_CANCEL
));
2262 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2263 EXPECT_TRUE(tap_cancel
.handled());
2269 // Change the handle mode of |v3| to indicate that it would no longer like
2270 // to handle events, and change the mode of |v1| to indicate that it would
2271 // like to handle events.
2272 v3
->set_handle_mode(EventCountView::PROPAGATE_EVENTS
);
2273 v1
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2275 // Dispatch a ui::ET_GESTURE_SCROLL_BEGIN event. Because the current gesture
2276 // handler (|v3|) does not handle scroll events, the event should bubble up
2277 // the views hierarchy until it reaches the first view that will handle
2278 // it (|v1|) and then sets the handler to |v1|.
2279 GestureEventForTest
scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN
, 5, 5);
2280 widget
->OnGestureEvent(&scroll_begin
);
2281 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
2282 EXPECT_EQ(1, v2
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
2283 EXPECT_EQ(1, v3
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
2284 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
2285 EXPECT_EQ(v1
, GetGestureHandler(root_view
));
2286 EXPECT_TRUE(scroll_begin
.handled());
2292 // A ui::ET_GESTURE_SCROLL_UPDATE event should be dispatched to |v1|
2294 GestureEventForTest
scroll_update(ui::ET_GESTURE_SCROLL_UPDATE
, 5, 5);
2295 widget
->OnGestureEvent(&scroll_update
);
2296 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2297 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2298 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2299 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
2300 EXPECT_EQ(v1
, GetGestureHandler(root_view
));
2301 EXPECT_TRUE(scroll_update
.handled());
2307 // A ui::ET_GESTURE_SCROLL_END event should be dispatched to |v1|
2308 // directly and should not reset the gesture handler.
2309 GestureEventForTest
scroll_end(ui::ET_GESTURE_SCROLL_END
, 5, 5);
2310 widget
->OnGestureEvent(&scroll_end
);
2311 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2312 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2313 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2314 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
2315 EXPECT_EQ(v1
, GetGestureHandler(root_view
));
2316 EXPECT_TRUE(scroll_end
.handled());
2322 // A ui::ET_GESTURE_PINCH_BEGIN event (which is a non-scroll event) should
2323 // still be dispatched to |v1| directly.
2324 GestureEventForTest
pinch_begin(ui::ET_GESTURE_PINCH_BEGIN
, 5, 5);
2325 widget
->OnGestureEvent(&pinch_begin
);
2326 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN
));
2327 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN
));
2328 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN
));
2329 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN
));
2330 EXPECT_EQ(v1
, GetGestureHandler(root_view
));
2331 EXPECT_TRUE(pinch_begin
.handled());
2337 // A ui::ET_GESTURE_END event should be dispatched to |v1| and should
2338 // set the gesture handler to NULL.
2339 GestureEventForTest
end(ui::ET_GESTURE_END
, 5, 5);
2340 widget
->OnGestureEvent(&end
);
2341 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_GESTURE_END
));
2342 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_END
));
2343 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_END
));
2344 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_END
));
2345 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2346 EXPECT_TRUE(end
.handled());
2351 // Verifies that disabled views are permitted to be set as the default gesture
2352 // handler in RootView. Also verifies that gesture events targeted to a disabled
2353 // view are not actually dispatched to the view, but are still marked as
2355 TEST_F(WidgetTest
, DisabledGestureEventTarget
) {
2356 Widget
* widget
= CreateTopLevelNativeWidget();
2357 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
2359 // Define a hierarchy of four views (coordinates are in
2360 // their parent coordinate space).
2361 // v1 (0, 0, 300, 300)
2362 // v2 (0, 0, 100, 100)
2363 // v3 (0, 0, 50, 50)
2365 EventCountView
* v1
= new EventCountView();
2366 v1
->SetBounds(0, 0, 300, 300);
2367 EventCountView
* v2
= new EventCountView();
2368 v2
->SetBounds(0, 0, 100, 100);
2369 EventCountView
* v3
= new EventCountView();
2370 v3
->SetBounds(0, 0, 50, 50);
2371 EventCountView
* v4
= new EventCountView();
2372 v4
->SetBounds(0, 0, 10, 10);
2373 internal::RootView
* root_view
=
2374 static_cast<internal::RootView
*>(widget
->GetRootView());
2375 root_view
->AddChildView(v1
);
2376 v1
->AddChildView(v2
);
2377 v2
->AddChildView(v3
);
2378 v3
->AddChildView(v4
);
2382 // |v1|, |v2|, and |v3| all handle gesture events but |v3| is marked as
2384 v1
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2385 v2
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2386 v3
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
2387 v3
->SetEnabled(false);
2389 // No gesture handler is set in the root view, so it should remain unset
2390 // after a GESTURE_END. The event is first dispatched to |v4| (which does
2391 // not want to handle the event) and is then targeted at |v3|. Since |v3|
2392 // is disabled, the event is not dispatched but is still marked as handled.
2393 GestureEventForTest
end(ui::ET_GESTURE_END
, 5, 5);
2394 widget
->OnGestureEvent(&end
);
2395 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_END
));
2396 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_END
));
2397 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_END
));
2398 EXPECT_EQ(1, v4
->GetEventCount(ui::ET_GESTURE_END
));
2399 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2400 EXPECT_TRUE(end
.handled());
2406 // No gesture handler is set in the root view. In this case the tap event
2407 // should be dispatched only to |v4|, the gesture handler should be set to
2408 // |v3|, and the event should be marked as handled.
2409 GestureEventForTest
tap(ui::ET_GESTURE_TAP
, 5, 5);
2410 widget
->OnGestureEvent(&tap
);
2411 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2412 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2413 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2414 EXPECT_EQ(1, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2415 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2416 EXPECT_TRUE(tap
.handled());
2422 // A subsequent gesture event should be marked as handled but not dispatched.
2423 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2424 widget
->OnGestureEvent(&tap
);
2425 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2426 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2427 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2428 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2429 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2430 EXPECT_TRUE(tap
.handled());
2436 // A GESTURE_END should reset the default gesture handler to NULL. It should
2437 // also not be dispatched to |v3| but still marked as handled.
2438 end
= GestureEventForTest(ui::ET_GESTURE_END
, 5, 5);
2439 widget
->OnGestureEvent(&end
);
2440 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_END
));
2441 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_END
));
2442 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_END
));
2443 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_END
));
2444 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2445 EXPECT_TRUE(end
.handled());
2451 // Change the handle mode of |v3| to indicate that it would no longer like
2452 // to handle events which are dispatched to it.
2453 v3
->set_handle_mode(EventCountView::PROPAGATE_EVENTS
);
2455 // No gesture handler is set in the root view. In this case the tap event
2456 // should be dispatched only to |v4| and the event should be marked as
2457 // handled. Furthermore, the gesture handler should be set to
2458 // |v3|; even though |v3| does not explicitly handle events, it is a
2459 // valid target for the tap event because it is disabled.
2460 tap
= GestureEventForTest(ui::ET_GESTURE_TAP
, 5, 5);
2461 widget
->OnGestureEvent(&tap
);
2462 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_TAP
));
2463 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_TAP
));
2464 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_TAP
));
2465 EXPECT_EQ(1, v4
->GetEventCount(ui::ET_GESTURE_TAP
));
2466 EXPECT_EQ(v3
, GetGestureHandler(root_view
));
2467 EXPECT_TRUE(tap
.handled());
2473 // A GESTURE_END should reset the default gesture handler to NULL. It should
2474 // also not be dispatched to |v3| but still marked as handled.
2475 end
= GestureEventForTest(ui::ET_GESTURE_END
, 5, 5);
2476 widget
->OnGestureEvent(&end
);
2477 EXPECT_EQ(0, v1
->GetEventCount(ui::ET_GESTURE_END
));
2478 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_GESTURE_END
));
2479 EXPECT_EQ(0, v3
->GetEventCount(ui::ET_GESTURE_END
));
2480 EXPECT_EQ(0, v4
->GetEventCount(ui::ET_GESTURE_END
));
2481 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
2482 EXPECT_TRUE(end
.handled());
2487 // Test the result of Widget::GetAllChildWidgets().
2488 TEST_F(WidgetTest
, GetAllChildWidgets
) {
2489 // Create the following widget hierarchy:
2497 Widget
* toplevel
= CreateTopLevelPlatformWidget();
2498 Widget
* w1
= CreateChildPlatformWidget(toplevel
->GetNativeView());
2499 Widget
* w11
= CreateChildPlatformWidget(w1
->GetNativeView());
2500 Widget
* w2
= CreateChildPlatformWidget(toplevel
->GetNativeView());
2501 Widget
* w21
= CreateChildPlatformWidget(w2
->GetNativeView());
2502 Widget
* w22
= CreateChildPlatformWidget(w2
->GetNativeView());
2504 std::set
<Widget
*> expected
;
2505 expected
.insert(toplevel
);
2506 expected
.insert(w1
);
2507 expected
.insert(w11
);
2508 expected
.insert(w2
);
2509 expected
.insert(w21
);
2510 expected
.insert(w22
);
2512 std::set
<Widget
*> widgets
;
2513 Widget::GetAllChildWidgets(toplevel
->GetNativeView(), &widgets
);
2515 EXPECT_EQ(expected
.size(), widgets
.size());
2516 EXPECT_TRUE(std::equal(expected
.begin(), expected
.end(), widgets
.begin()));
2519 // Used by DestroyChildWidgetsInOrder. On destruction adds the supplied name to
2521 class DestroyedTrackingView
: public View
{
2523 DestroyedTrackingView(const std::string
& name
,
2524 std::vector
<std::string
>* add_to
)
2529 virtual ~DestroyedTrackingView() {
2530 add_to_
->push_back(name_
);
2534 const std::string name_
;
2535 std::vector
<std::string
>* add_to_
;
2537 DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingView
);
2540 class WidgetChildDestructionTest
: public WidgetTest
{
2542 WidgetChildDestructionTest() {}
2544 // Creates a top level and a child, destroys the child and verifies the views
2545 // of the child are destroyed before the views of the parent.
2546 void RunDestroyChildWidgetsTest(bool top_level_has_desktop_native_widget_aura
,
2547 bool child_has_desktop_native_widget_aura
) {
2548 // When a View is destroyed its name is added here.
2549 std::vector
<std::string
> destroyed
;
2551 Widget
* top_level
= new Widget
;
2552 Widget::InitParams params
=
2553 CreateParams(views::Widget::InitParams::TYPE_WINDOW
);
2554 #if !defined(OS_CHROMEOS)
2555 if (top_level_has_desktop_native_widget_aura
)
2556 params
.native_widget
= new PlatformDesktopNativeWidget(top_level
);
2558 top_level
->Init(params
);
2559 top_level
->GetRootView()->AddChildView(
2560 new DestroyedTrackingView("parent", &destroyed
));
2563 Widget
* child
= new Widget
;
2564 Widget::InitParams child_params
=
2565 CreateParams(views::Widget::InitParams::TYPE_POPUP
);
2566 child_params
.parent
= top_level
->GetNativeView();
2567 #if !defined(OS_CHROMEOS)
2568 if (child_has_desktop_native_widget_aura
)
2569 child_params
.native_widget
= new PlatformDesktopNativeWidget(child
);
2571 child
->Init(child_params
);
2572 child
->GetRootView()->AddChildView(
2573 new DestroyedTrackingView("child", &destroyed
));
2576 // Should trigger destruction of the child too.
2577 top_level
->native_widget_private()->CloseNow();
2579 // Child should be destroyed first.
2580 ASSERT_EQ(2u, destroyed
.size());
2581 EXPECT_EQ("child", destroyed
[0]);
2582 EXPECT_EQ("parent", destroyed
[1]);
2586 DISALLOW_COPY_AND_ASSIGN(WidgetChildDestructionTest
);
2589 #if !defined(OS_CHROMEOS)
2590 // See description of RunDestroyChildWidgetsTest(). Parent uses
2591 // DesktopNativeWidgetAura.
2592 TEST_F(WidgetChildDestructionTest
,
2593 DestroyChildWidgetsInOrderWithDesktopNativeWidget
) {
2594 RunDestroyChildWidgetsTest(true, false);
2597 // See description of RunDestroyChildWidgetsTest(). Both parent and child use
2598 // DesktopNativeWidgetAura.
2599 TEST_F(WidgetChildDestructionTest
,
2600 DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth
) {
2601 RunDestroyChildWidgetsTest(true, true);
2603 #endif // !defined(OS_CHROMEOS)
2605 // See description of RunDestroyChildWidgetsTest().
2606 TEST_F(WidgetChildDestructionTest
, DestroyChildWidgetsInOrder
) {
2607 RunDestroyChildWidgetsTest(false, false);
2610 #if !defined(OS_CHROMEOS)
2611 // Provides functionality to create a window modal dialog.
2612 class ModalDialogDelegate
: public DialogDelegateView
{
2614 ModalDialogDelegate() {}
2615 virtual ~ModalDialogDelegate() {}
2617 // WidgetDelegate overrides.
2618 virtual ui::ModalType
GetModalType() const OVERRIDE
{
2619 return ui::MODAL_TYPE_WINDOW
;
2623 DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate
);
2626 // This test verifies that whether mouse events when a modal dialog is
2627 // displayed are eaten or recieved by the dialog.
2628 TEST_F(WidgetTest
, WindowMouseModalityTest
) {
2629 // Create a top level widget.
2630 Widget top_level_widget
;
2631 Widget::InitParams init_params
=
2632 CreateParams(Widget::InitParams::TYPE_WINDOW
);
2633 init_params
.show_state
= ui::SHOW_STATE_NORMAL
;
2634 gfx::Rect
initial_bounds(0, 0, 500, 500);
2635 init_params
.bounds
= initial_bounds
;
2636 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
2637 init_params
.native_widget
=
2638 new PlatformDesktopNativeWidget(&top_level_widget
);
2639 top_level_widget
.Init(init_params
);
2640 top_level_widget
.Show();
2641 EXPECT_TRUE(top_level_widget
.IsVisible());
2643 // Create a view and validate that a mouse moves makes it to the view.
2644 EventCountView
* widget_view
= new EventCountView();
2645 widget_view
->SetBounds(0, 0, 10, 10);
2646 top_level_widget
.GetRootView()->AddChildView(widget_view
);
2648 gfx::Point
cursor_location_main(5, 5);
2649 ui::MouseEvent
move_main(ui::ET_MOUSE_MOVED
,
2650 cursor_location_main
,
2651 cursor_location_main
,
2654 ui::EventDispatchDetails details
=
2655 GetEventProcessor(&top_level_widget
)->OnEventFromSource(&move_main
);
2656 ASSERT_FALSE(details
.dispatcher_destroyed
);
2658 EXPECT_EQ(1, widget_view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
2659 widget_view
->ResetCounts();
2661 // Create a modal dialog and validate that a mouse down message makes it to
2662 // the main view within the dialog.
2664 // This instance will be destroyed when the dialog is destroyed.
2665 ModalDialogDelegate
* dialog_delegate
= new ModalDialogDelegate
;
2667 Widget
* modal_dialog_widget
= views::DialogDelegate::CreateDialogWidget(
2668 dialog_delegate
, NULL
, top_level_widget
.GetNativeView());
2669 modal_dialog_widget
->SetBounds(gfx::Rect(100, 100, 200, 200));
2670 EventCountView
* dialog_widget_view
= new EventCountView();
2671 dialog_widget_view
->SetBounds(0, 0, 50, 50);
2672 modal_dialog_widget
->GetRootView()->AddChildView(dialog_widget_view
);
2673 modal_dialog_widget
->Show();
2674 EXPECT_TRUE(modal_dialog_widget
->IsVisible());
2676 gfx::Point
cursor_location_dialog(100, 100);
2677 ui::MouseEvent
mouse_down_dialog(ui::ET_MOUSE_PRESSED
,
2678 cursor_location_dialog
,
2679 cursor_location_dialog
,
2682 details
= GetEventProcessor(&top_level_widget
)->OnEventFromSource(
2683 &mouse_down_dialog
);
2684 ASSERT_FALSE(details
.dispatcher_destroyed
);
2685 EXPECT_EQ(1, dialog_widget_view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
2687 // Send a mouse move message to the main window. It should not be received by
2688 // the main window as the modal dialog is still active.
2689 gfx::Point
cursor_location_main2(6, 6);
2690 ui::MouseEvent
mouse_down_main(ui::ET_MOUSE_MOVED
,
2691 cursor_location_main2
,
2692 cursor_location_main2
,
2695 details
= GetEventProcessor(&top_level_widget
)->OnEventFromSource(
2697 ASSERT_FALSE(details
.dispatcher_destroyed
);
2698 EXPECT_EQ(0, widget_view
->GetEventCount(ui::ET_MOUSE_MOVED
));
2700 modal_dialog_widget
->CloseNow();
2701 top_level_widget
.CloseNow();
2704 // Verifies nativeview visbility matches that of Widget visibility when
2705 // SetFullscreen is invoked.
2706 TEST_F(WidgetTest
, FullscreenStatePropagated
) {
2707 Widget::InitParams init_params
=
2708 CreateParams(Widget::InitParams::TYPE_WINDOW
);
2709 init_params
.show_state
= ui::SHOW_STATE_NORMAL
;
2710 init_params
.bounds
= gfx::Rect(0, 0, 500, 500);
2711 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
2714 Widget top_level_widget
;
2715 top_level_widget
.Init(init_params
);
2716 top_level_widget
.SetFullscreen(true);
2717 EXPECT_EQ(top_level_widget
.IsVisible(),
2718 IsNativeWindowVisible(top_level_widget
.GetNativeWindow()));
2719 top_level_widget
.CloseNow();
2721 #if !defined(OS_CHROMEOS)
2723 Widget top_level_widget
;
2724 init_params
.native_widget
=
2725 new PlatformDesktopNativeWidget(&top_level_widget
);
2726 top_level_widget
.Init(init_params
);
2727 top_level_widget
.SetFullscreen(true);
2728 EXPECT_EQ(top_level_widget
.IsVisible(),
2729 IsNativeWindowVisible(top_level_widget
.GetNativeWindow()));
2730 top_level_widget
.CloseNow();
2736 // Provides functionality to test widget activation via an activation flag
2737 // which can be set by an accessor.
2738 class ModalWindowTestWidgetDelegate
: public WidgetDelegate
{
2740 ModalWindowTestWidgetDelegate()
2742 can_activate_(true) {}
2744 virtual ~ModalWindowTestWidgetDelegate() {}
2746 // Overridden from WidgetDelegate:
2747 virtual void DeleteDelegate() OVERRIDE
{
2750 virtual Widget
* GetWidget() OVERRIDE
{
2753 virtual const Widget
* GetWidget() const OVERRIDE
{
2756 virtual bool CanActivate() const OVERRIDE
{
2757 return can_activate_
;
2759 virtual bool ShouldAdvanceFocusToTopLevelWidget() const OVERRIDE
{
2763 void set_can_activate(bool can_activate
) {
2764 can_activate_
= can_activate
;
2767 void set_widget(Widget
* widget
) {
2775 DISALLOW_COPY_AND_ASSIGN(ModalWindowTestWidgetDelegate
);
2778 // Tests whether we can activate the top level widget when a modal dialog is
2780 TEST_F(WidgetTest
, WindowModalityActivationTest
) {
2781 // Destroyed when the top level widget created below is destroyed.
2782 ModalWindowTestWidgetDelegate
* widget_delegate
=
2783 new ModalWindowTestWidgetDelegate
;
2784 // Create a top level widget.
2785 Widget top_level_widget
;
2786 Widget::InitParams init_params
=
2787 CreateParams(Widget::InitParams::TYPE_WINDOW
);
2788 init_params
.show_state
= ui::SHOW_STATE_NORMAL
;
2789 gfx::Rect
initial_bounds(0, 0, 500, 500);
2790 init_params
.bounds
= initial_bounds
;
2791 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
2792 init_params
.native_widget
= new DesktopNativeWidgetAura(&top_level_widget
);
2793 init_params
.delegate
= widget_delegate
;
2794 top_level_widget
.Init(init_params
);
2795 widget_delegate
->set_widget(&top_level_widget
);
2796 top_level_widget
.Show();
2797 EXPECT_TRUE(top_level_widget
.IsVisible());
2799 HWND win32_window
= views::HWNDForWidget(&top_level_widget
);
2800 EXPECT_TRUE(::IsWindow(win32_window
));
2802 // This instance will be destroyed when the dialog is destroyed.
2803 ModalDialogDelegate
* dialog_delegate
= new ModalDialogDelegate
;
2805 // We should be able to activate the window even if the WidgetDelegate
2806 // says no, when a modal dialog is active.
2807 widget_delegate
->set_can_activate(false);
2809 Widget
* modal_dialog_widget
= views::DialogDelegate::CreateDialogWidget(
2810 dialog_delegate
, NULL
, top_level_widget
.GetNativeWindow());
2811 modal_dialog_widget
->SetBounds(gfx::Rect(100, 100, 200, 200));
2812 modal_dialog_widget
->Show();
2813 EXPECT_TRUE(modal_dialog_widget
->IsVisible());
2815 LRESULT activate_result
= ::SendMessage(
2818 reinterpret_cast<WPARAM
>(win32_window
),
2819 MAKELPARAM(WM_LBUTTONDOWN
, HTCLIENT
));
2820 EXPECT_EQ(activate_result
, MA_ACTIVATE
);
2822 modal_dialog_widget
->CloseNow();
2823 top_level_widget
.CloseNow();
2825 #endif // defined(OS_WIN)
2826 #endif // !defined(OS_CHROMEOS)
2828 TEST_F(WidgetTest
, ShowCreatesActiveWindow
) {
2829 Widget
* widget
= CreateTopLevelPlatformWidget();
2832 EXPECT_EQ(GetWidgetShowState(widget
), ui::SHOW_STATE_NORMAL
);
2837 // OSX does not have a per-application "active" window such as provided by
2838 // ::GetActiveWindow() on Windows. There is only a system-wide "keyWindow" which
2839 // is updated asynchronously.
2840 #if defined(OS_MACOSX)
2841 #define MAYBE_ShowInactive DISABLED_ShowInactive
2843 #define MAYBE_ShowInactive ShowInactive
2845 TEST_F(WidgetTest
, MAYBE_ShowInactive
) {
2846 Widget
* widget
= CreateTopLevelPlatformWidget();
2848 widget
->ShowInactive();
2849 EXPECT_EQ(GetWidgetShowState(widget
), ui::SHOW_STATE_INACTIVE
);
2854 TEST_F(WidgetTest
, InactiveBeforeShow
) {
2855 Widget
* widget
= CreateTopLevelPlatformWidget();
2857 EXPECT_FALSE(widget
->IsActive());
2858 EXPECT_FALSE(widget
->IsVisible());
2862 EXPECT_TRUE(widget
->IsActive());
2863 EXPECT_TRUE(widget
->IsVisible());
2868 TEST_F(WidgetTest
, ShowInactiveAfterShow
) {
2869 // Create 2 widgets to ensure window layering does not change.
2870 Widget
* widget
= CreateTopLevelPlatformWidget();
2871 Widget
* widget2
= CreateTopLevelPlatformWidget();
2874 EXPECT_FALSE(widget
->IsActive());
2875 EXPECT_TRUE(widget2
->IsVisible());
2876 EXPECT_TRUE(widget2
->IsActive());
2879 EXPECT_TRUE(widget
->IsActive());
2880 EXPECT_FALSE(widget2
->IsActive());
2881 widget
->ShowInactive();
2882 EXPECT_TRUE(widget
->IsActive());
2883 EXPECT_FALSE(widget2
->IsActive());
2884 EXPECT_EQ(GetWidgetShowState(widget
), ui::SHOW_STATE_NORMAL
);
2886 widget2
->CloseNow();
2890 TEST_F(WidgetTest
, ShowAfterShowInactive
) {
2891 Widget
* widget
= CreateTopLevelPlatformWidget();
2893 widget
->ShowInactive();
2895 EXPECT_EQ(GetWidgetShowState(widget
), ui::SHOW_STATE_NORMAL
);
2900 #if !defined(OS_CHROMEOS)
2901 TEST_F(WidgetTest
, InactiveWidgetDoesNotGrabActivation
) {
2902 Widget
* widget
= CreateTopLevelPlatformWidget();
2904 EXPECT_EQ(GetWidgetShowState(widget
), ui::SHOW_STATE_NORMAL
);
2907 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
2908 params
.native_widget
= new PlatformDesktopNativeWidget(&widget2
);
2909 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
2910 widget2
.Init(params
);
2913 EXPECT_EQ(GetWidgetShowState(&widget2
), ui::SHOW_STATE_INACTIVE
);
2914 EXPECT_EQ(GetWidgetShowState(widget
), ui::SHOW_STATE_NORMAL
);
2919 #endif // !defined(OS_CHROMEOS)
2923 class FullscreenAwareFrame
: public views::NonClientFrameView
{
2925 explicit FullscreenAwareFrame(views::Widget
* widget
)
2926 : widget_(widget
), fullscreen_layout_called_(false) {}
2927 virtual ~FullscreenAwareFrame() {}
2929 // views::NonClientFrameView overrides:
2930 virtual gfx::Rect
GetBoundsForClientView() const OVERRIDE
{
2933 virtual gfx::Rect
GetWindowBoundsForClientBounds(
2934 const gfx::Rect
& client_bounds
) const OVERRIDE
{
2937 virtual int NonClientHitTest(const gfx::Point
& point
) OVERRIDE
{
2940 virtual void GetWindowMask(const gfx::Size
& size
,
2941 gfx::Path
* window_mask
) OVERRIDE
{}
2942 virtual void ResetWindowControls() OVERRIDE
{}
2943 virtual void UpdateWindowIcon() OVERRIDE
{}
2944 virtual void UpdateWindowTitle() OVERRIDE
{}
2946 // views::View overrides:
2947 virtual void Layout() OVERRIDE
{
2948 if (widget_
->IsFullscreen())
2949 fullscreen_layout_called_
= true;
2952 bool fullscreen_layout_called() const { return fullscreen_layout_called_
; }
2955 views::Widget
* widget_
;
2956 bool fullscreen_layout_called_
;
2958 DISALLOW_COPY_AND_ASSIGN(FullscreenAwareFrame
);
2963 // Tests that frame Layout is called when a widget goes fullscreen without
2964 // changing its size or title.
2965 TEST_F(WidgetTest
, FullscreenFrameLayout
) {
2966 Widget
* widget
= CreateTopLevelPlatformWidget();
2967 FullscreenAwareFrame
* frame
= new FullscreenAwareFrame(widget
);
2968 widget
->non_client_view()->SetFrameView(frame
); // Owns |frame|.
2971 RunPendingMessages();
2973 EXPECT_FALSE(frame
->fullscreen_layout_called());
2974 widget
->SetFullscreen(true);
2976 RunPendingMessages();
2977 EXPECT_TRUE(frame
->fullscreen_layout_called());
2982 #if !defined(OS_CHROMEOS)
2985 // Trivial WidgetObserverTest that invokes Widget::IsActive() from
2986 // OnWindowDestroying.
2987 class IsActiveFromDestroyObserver
: public WidgetObserver
{
2989 IsActiveFromDestroyObserver() {}
2990 virtual ~IsActiveFromDestroyObserver() {}
2991 virtual void OnWidgetDestroying(Widget
* widget
) OVERRIDE
{
2996 DISALLOW_COPY_AND_ASSIGN(IsActiveFromDestroyObserver
);
3001 // Verifies Widget::IsActive() invoked from
3002 // WidgetObserver::OnWidgetDestroying() in a child widget doesn't crash.
3003 TEST_F(WidgetTest
, IsActiveFromDestroy
) {
3004 // Create two widgets, one a child of the other.
3005 IsActiveFromDestroyObserver observer
;
3006 Widget parent_widget
;
3007 Widget::InitParams parent_params
=
3008 CreateParams(Widget::InitParams::TYPE_POPUP
);
3009 parent_params
.native_widget
= new PlatformDesktopNativeWidget(&parent_widget
);
3010 parent_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
3011 parent_widget
.Init(parent_params
);
3012 parent_widget
.Show();
3014 Widget child_widget
;
3015 Widget::InitParams child_params
=
3016 CreateParams(Widget::InitParams::TYPE_POPUP
);
3017 child_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
3018 child_params
.context
= parent_widget
.GetNativeWindow();
3019 child_widget
.Init(child_params
);
3020 child_widget
.AddObserver(&observer
);
3021 child_widget
.Show();
3023 parent_widget
.CloseNow();
3025 #endif // !defined(OS_CHROMEOS)
3027 // Tests that events propagate through from the dispatcher with the correct
3028 // event type, and that the different platforms behave the same.
3029 TEST_F(WidgetTest
, MouseEventTypesViaGenerator
) {
3030 EventCountView
* view
= new EventCountView
;
3031 view
->set_handle_mode(EventCountView::CONSUME_EVENTS
);
3032 view
->SetBounds(10, 10, 50, 40);
3034 Widget
* widget
= CreateTopLevelFramelessPlatformWidget();
3035 widget
->GetRootView()->AddChildView(view
);
3037 widget
->SetBounds(gfx::Rect(0, 0, 100, 80));
3040 ui::test::EventGenerator
generator(GetContext(), widget
->GetNativeWindow());
3041 generator
.set_current_location(gfx::Point(20, 20));
3043 generator
.ClickLeftButton();
3044 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
3045 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_RELEASED
));
3046 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON
, view
->last_flags());
3048 generator
.PressRightButton();
3049 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
3050 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_RELEASED
));
3051 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON
, view
->last_flags());
3053 generator
.ReleaseRightButton();
3054 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
3055 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_RELEASED
));
3056 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON
, view
->last_flags());
3058 // Test mouse move events.
3059 EXPECT_EQ(0, view
->GetEventCount(ui::ET_MOUSE_MOVED
));
3060 EXPECT_EQ(0, view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
3062 // Move the mouse within the view (20, 20) -> (30, 30).
3063 generator
.MoveMouseTo(gfx::Point(30, 30));
3064 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_MOVED
));
3065 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
3066 EXPECT_EQ(ui::EF_NONE
, view
->last_flags());
3068 // Move it again - entered count shouldn't change.
3069 generator
.MoveMouseTo(gfx::Point(31, 31));
3070 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_MOVED
));
3071 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
3072 EXPECT_EQ(0, view
->GetEventCount(ui::ET_MOUSE_EXITED
));
3074 // Move it off the view.
3075 generator
.MoveMouseTo(gfx::Point(5, 5));
3076 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_MOVED
));
3077 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
3078 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_EXITED
));
3081 generator
.MoveMouseTo(gfx::Point(20, 20));
3082 EXPECT_EQ(3, view
->GetEventCount(ui::ET_MOUSE_MOVED
));
3083 EXPECT_EQ(2, view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
3084 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_EXITED
));
3086 // Drargging. Cover HasCapture() and NativeWidgetPrivate::IsMouseButtonDown().
3087 generator
.DragMouseTo(gfx::Point(40, 40));
3088 EXPECT_EQ(3, view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
3089 EXPECT_EQ(3, view
->GetEventCount(ui::ET_MOUSE_RELEASED
));
3090 EXPECT_EQ(1, view
->GetEventCount(ui::ET_MOUSE_DRAGGED
));
3091 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON
, view
->last_flags());
3097 } // namespace views