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/events/event_utils.h"
16 #include "ui/gfx/native_widget_types.h"
17 #include "ui/gfx/point.h"
18 #include "ui/views/bubble/bubble_delegate.h"
19 #include "ui/views/controls/textfield/textfield.h"
20 #include "ui/views/test/test_views_delegate.h"
21 #include "ui/views/test/widget_test.h"
22 #include "ui/views/views_delegate.h"
23 #include "ui/views/widget/native_widget_delegate.h"
24 #include "ui/views/widget/root_view.h"
25 #include "ui/views/window/dialog_delegate.h"
26 #include "ui/views/window/native_frame_view.h"
29 #include "ui/aura/client/aura_constants.h"
30 #include "ui/aura/client/window_tree_client.h"
31 #include "ui/aura/root_window.h"
32 #include "ui/aura/test/test_window_delegate.h"
33 #include "ui/aura/window.h"
34 #include "ui/views/widget/native_widget_aura.h"
35 #if !defined(OS_CHROMEOS)
36 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
39 #include "ui/views/widget/native_widget_win.h"
43 #include "ui/views/win/hwnd_util.h"
49 // A view that keeps track of the events it receives, but consumes no events.
50 class EventCountView
: public View
{
53 virtual ~EventCountView() {}
55 int GetEventCount(ui::EventType type
) {
56 return event_count_
[type
];
64 // Overridden from ui::EventHandler:
65 virtual void OnKeyEvent(ui::KeyEvent
* event
) OVERRIDE
{
68 virtual void OnMouseEvent(ui::MouseEvent
* event
) OVERRIDE
{
71 virtual void OnScrollEvent(ui::ScrollEvent
* event
) OVERRIDE
{
74 virtual void OnTouchEvent(ui::TouchEvent
* event
) OVERRIDE
{
77 virtual void OnGestureEvent(ui::GestureEvent
* event
) OVERRIDE
{
82 void RecordEvent(const ui::Event
& event
) {
83 ++event_count_
[event
.type()];
86 std::map
<ui::EventType
, int> event_count_
;
88 DISALLOW_COPY_AND_ASSIGN(EventCountView
);
91 // A view that keeps track of the events it receives, and consumes all scroll
93 class ScrollableEventCountView
: public EventCountView
{
95 ScrollableEventCountView() {}
96 virtual ~ScrollableEventCountView() {}
99 // Overridden from ui::EventHandler:
100 virtual void OnGestureEvent(ui::GestureEvent
* event
) OVERRIDE
{
101 EventCountView::OnGestureEvent(event
);
102 switch (event
->type()) {
103 case ui::ET_GESTURE_SCROLL_BEGIN
:
104 case ui::ET_GESTURE_SCROLL_UPDATE
:
105 case ui::ET_GESTURE_SCROLL_END
:
106 case ui::ET_SCROLL_FLING_START
:
114 DISALLOW_COPY_AND_ASSIGN(ScrollableEventCountView
);
117 // A view that implements GetMinimumSize.
118 class MinimumSizeFrameView
: public NativeFrameView
{
120 explicit MinimumSizeFrameView(Widget
* frame
): NativeFrameView(frame
) {}
121 virtual ~MinimumSizeFrameView() {}
124 // Overridden from View:
125 virtual gfx::Size
GetMinimumSize() OVERRIDE
{
126 return gfx::Size(300, 400);
129 DISALLOW_COPY_AND_ASSIGN(MinimumSizeFrameView
);
132 // An event handler that simply keeps a count of the different types of events
134 class EventCountHandler
: public ui::EventHandler
{
136 EventCountHandler() {}
137 virtual ~EventCountHandler() {}
139 int GetEventCount(ui::EventType type
) {
140 return event_count_
[type
];
144 event_count_
.clear();
148 // Overridden from ui::EventHandler:
149 virtual void OnEvent(ui::Event
* event
) OVERRIDE
{
151 ui::EventHandler::OnEvent(event
);
155 void RecordEvent(const ui::Event
& event
) {
156 ++event_count_
[event
.type()];
159 std::map
<ui::EventType
, int> event_count_
;
161 DISALLOW_COPY_AND_ASSIGN(EventCountHandler
);
164 ui::WindowShowState
GetWidgetShowState(const Widget
* widget
) {
165 // Use IsMaximized/IsMinimized/IsFullScreen instead of GetWindowPlacement
166 // because the former is implemented on all platforms but the latter is not.
167 return widget
->IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN
:
168 widget
->IsMaximized() ? ui::SHOW_STATE_MAXIMIZED
:
169 widget
->IsMinimized() ? ui::SHOW_STATE_MINIMIZED
:
170 ui::SHOW_STATE_NORMAL
;
173 TEST_F(WidgetTest
, WidgetInitParams
) {
174 ASSERT_FALSE(views_delegate().UseTransparentWindows());
176 // Widgets are not transparent by default.
177 Widget::InitParams init1
;
178 EXPECT_EQ(Widget::InitParams::INFER_OPACITY
, init1
.opacity
);
180 // Non-window widgets are not transparent either.
181 Widget::InitParams
init2(Widget::InitParams::TYPE_MENU
);
182 EXPECT_EQ(Widget::InitParams::INFER_OPACITY
, init2
.opacity
);
184 // A ViewsDelegate can set windows transparent by default.
185 views_delegate().SetUseTransparentWindows(true);
186 Widget::InitParams init3
;
187 EXPECT_EQ(Widget::InitParams::TRANSLUCENT_WINDOW
, init3
.opacity
);
189 // Non-window widgets stay opaque.
190 Widget::InitParams
init4(Widget::InitParams::TYPE_MENU
);
191 EXPECT_EQ(Widget::InitParams::INFER_OPACITY
, init4
.opacity
);
194 ////////////////////////////////////////////////////////////////////////////////
195 // Widget::GetTopLevelWidget tests.
197 TEST_F(WidgetTest
, GetTopLevelWidget_Native
) {
198 // Create a hierarchy of native widgets.
199 Widget
* toplevel
= CreateTopLevelPlatformWidget();
200 gfx::NativeView parent
= toplevel
->GetNativeView();
201 Widget
* child
= CreateChildPlatformWidget(parent
);
203 EXPECT_EQ(toplevel
, toplevel
->GetTopLevelWidget());
204 EXPECT_EQ(toplevel
, child
->GetTopLevelWidget());
206 toplevel
->CloseNow();
207 // |child| should be automatically destroyed with |toplevel|.
210 // Test if a focus manager and an inputmethod work without CHECK failure
211 // when window activation changes.
212 TEST_F(WidgetTest
, ChangeActivation
) {
213 Widget
* top1
= CreateTopLevelPlatformWidget();
214 // CreateInputMethod before activated
215 top1
->GetInputMethod();
217 RunPendingMessages();
219 Widget
* top2
= CreateTopLevelPlatformWidget();
221 RunPendingMessages();
224 RunPendingMessages();
226 // Create InputMethod after deactivated.
227 top2
->GetInputMethod();
229 RunPendingMessages();
232 RunPendingMessages();
238 // Tests visibility of child widgets.
239 TEST_F(WidgetTest
, Visibility
) {
240 Widget
* toplevel
= CreateTopLevelPlatformWidget();
241 gfx::NativeView parent
= toplevel
->GetNativeView();
242 Widget
* child
= CreateChildPlatformWidget(parent
);
244 EXPECT_FALSE(toplevel
->IsVisible());
245 EXPECT_FALSE(child
->IsVisible());
249 EXPECT_FALSE(toplevel
->IsVisible());
250 EXPECT_FALSE(child
->IsVisible());
254 EXPECT_TRUE(toplevel
->IsVisible());
255 EXPECT_TRUE(child
->IsVisible());
257 toplevel
->CloseNow();
258 // |child| should be automatically destroyed with |toplevel|.
261 #if defined(OS_WIN) && !defined(USE_AURA)
262 // On Windows, it is possible to have child window that are TYPE_POPUP. Unlike
263 // regular child windows, these should be created as hidden and must be shown
265 TEST_F(WidgetTest
, Visibility_ChildPopup
) {
266 Widget
* toplevel
= CreateTopLevelPlatformWidget();
267 Widget
* child_popup
= CreateChildPopupPlatformWidget(
268 toplevel
->GetNativeView());
270 EXPECT_FALSE(toplevel
->IsVisible());
271 EXPECT_FALSE(child_popup
->IsVisible());
275 EXPECT_TRUE(toplevel
->IsVisible());
276 EXPECT_FALSE(child_popup
->IsVisible());
280 EXPECT_TRUE(child_popup
->IsVisible());
282 toplevel
->CloseNow();
283 // |child_popup| should be automatically destroyed with |toplevel|.
287 ////////////////////////////////////////////////////////////////////////////////
288 // Widget ownership tests.
290 // Tests various permutations of Widget ownership specified in the
291 // InitParams::Ownership param.
293 // A WidgetTest that supplies a toplevel widget for NativeWidget to parent to.
294 class WidgetOwnershipTest
: public WidgetTest
{
296 WidgetOwnershipTest() {}
297 virtual ~WidgetOwnershipTest() {}
299 virtual void SetUp() {
301 desktop_widget_
= CreateTopLevelPlatformWidget();
304 virtual void TearDown() {
305 desktop_widget_
->CloseNow();
306 WidgetTest::TearDown();
310 Widget
* desktop_widget_
;
312 DISALLOW_COPY_AND_ASSIGN(WidgetOwnershipTest
);
315 // A bag of state to monitor destructions.
316 struct OwnershipTestState
{
317 OwnershipTestState() : widget_deleted(false), native_widget_deleted(false) {}
320 bool native_widget_deleted
;
323 // A platform NativeWidget subclass that updates a bag of state when it is
325 class OwnershipTestNativeWidget
: public NativeWidgetPlatform
{
327 OwnershipTestNativeWidget(internal::NativeWidgetDelegate
* delegate
,
328 OwnershipTestState
* state
)
329 : NativeWidgetPlatform(delegate
),
332 virtual ~OwnershipTestNativeWidget() {
333 state_
->native_widget_deleted
= true;
337 OwnershipTestState
* state_
;
339 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidget
);
342 // A views NativeWidget subclass that updates a bag of state when it is
344 class OwnershipTestNativeWidgetPlatform
: public NativeWidgetPlatformForTest
{
346 OwnershipTestNativeWidgetPlatform(internal::NativeWidgetDelegate
* delegate
,
347 OwnershipTestState
* state
)
348 : NativeWidgetPlatformForTest(delegate
),
351 virtual ~OwnershipTestNativeWidgetPlatform() {
352 state_
->native_widget_deleted
= true;
356 OwnershipTestState
* state_
;
358 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetPlatform
);
361 // A Widget subclass that updates a bag of state when it is destroyed.
362 class OwnershipTestWidget
: public Widget
{
364 explicit OwnershipTestWidget(OwnershipTestState
* state
) : state_(state
) {}
365 virtual ~OwnershipTestWidget() {
366 state_
->widget_deleted
= true;
370 OwnershipTestState
* state_
;
372 DISALLOW_COPY_AND_ASSIGN(OwnershipTestWidget
);
375 // Widget owns its NativeWidget, part 1: NativeWidget is a platform-native
377 TEST_F(WidgetOwnershipTest
, Ownership_WidgetOwnsPlatformNativeWidget
) {
378 OwnershipTestState state
;
380 scoped_ptr
<Widget
> widget(new OwnershipTestWidget(&state
));
381 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
382 params
.native_widget
=
383 new OwnershipTestNativeWidgetPlatform(widget
.get(), &state
);
384 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
385 widget
->Init(params
);
387 // Now delete the Widget, which should delete the NativeWidget.
390 EXPECT_TRUE(state
.widget_deleted
);
391 EXPECT_TRUE(state
.native_widget_deleted
);
393 // TODO(beng): write test for this ownership scenario and the NativeWidget
394 // being deleted out from under the Widget.
397 // Widget owns its NativeWidget, part 2: NativeWidget is a NativeWidget.
398 TEST_F(WidgetOwnershipTest
, Ownership_WidgetOwnsViewsNativeWidget
) {
399 OwnershipTestState state
;
401 scoped_ptr
<Widget
> widget(new OwnershipTestWidget(&state
));
402 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
403 params
.native_widget
=
404 new OwnershipTestNativeWidgetPlatform(widget
.get(), &state
);
405 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
406 widget
->Init(params
);
408 // Now delete the Widget, which should delete the NativeWidget.
411 EXPECT_TRUE(state
.widget_deleted
);
412 EXPECT_TRUE(state
.native_widget_deleted
);
414 // TODO(beng): write test for this ownership scenario and the NativeWidget
415 // being deleted out from under the Widget.
418 // Widget owns its NativeWidget, part 3: NativeWidget is a NativeWidget,
419 // destroy the parent view.
420 TEST_F(WidgetOwnershipTest
,
421 Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView
) {
422 OwnershipTestState state
;
424 Widget
* toplevel
= CreateTopLevelPlatformWidget();
426 scoped_ptr
<Widget
> widget(new OwnershipTestWidget(&state
));
427 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
428 params
.native_widget
=
429 new OwnershipTestNativeWidgetPlatform(widget
.get(), &state
);
430 params
.parent
= toplevel
->GetNativeView();
431 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
432 widget
->Init(params
);
434 // Now close the toplevel, which deletes the view hierarchy.
435 toplevel
->CloseNow();
437 RunPendingMessages();
439 // This shouldn't delete the widget because it shouldn't be deleted
440 // from the native side.
441 EXPECT_FALSE(state
.widget_deleted
);
442 EXPECT_FALSE(state
.native_widget_deleted
);
444 // Now delete it explicitly.
447 EXPECT_TRUE(state
.widget_deleted
);
448 EXPECT_TRUE(state
.native_widget_deleted
);
451 // NativeWidget owns its Widget, part 1: NativeWidget is a platform-native
453 TEST_F(WidgetOwnershipTest
, Ownership_PlatformNativeWidgetOwnsWidget
) {
454 OwnershipTestState state
;
456 Widget
* widget
= new OwnershipTestWidget(&state
);
457 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
458 params
.native_widget
=
459 new OwnershipTestNativeWidgetPlatform(widget
, &state
);
460 widget
->Init(params
);
462 // Now destroy the native widget.
465 EXPECT_TRUE(state
.widget_deleted
);
466 EXPECT_TRUE(state
.native_widget_deleted
);
469 // NativeWidget owns its Widget, part 2: NativeWidget is a NativeWidget.
470 TEST_F(WidgetOwnershipTest
, Ownership_ViewsNativeWidgetOwnsWidget
) {
471 OwnershipTestState state
;
473 Widget
* toplevel
= CreateTopLevelPlatformWidget();
475 Widget
* widget
= new OwnershipTestWidget(&state
);
476 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
477 params
.native_widget
=
478 new OwnershipTestNativeWidgetPlatform(widget
, &state
);
479 params
.parent
= toplevel
->GetNativeView();
480 widget
->Init(params
);
482 // Now destroy the native widget. This is achieved by closing the toplevel.
483 toplevel
->CloseNow();
485 // The NativeWidget won't be deleted until after a return to the message loop
486 // so we have to run pending messages before testing the destruction status.
487 RunPendingMessages();
489 EXPECT_TRUE(state
.widget_deleted
);
490 EXPECT_TRUE(state
.native_widget_deleted
);
493 // NativeWidget owns its Widget, part 3: NativeWidget is a platform-native
494 // widget, destroyed out from under it by the OS.
495 TEST_F(WidgetOwnershipTest
,
496 Ownership_PlatformNativeWidgetOwnsWidget_NativeDestroy
) {
497 OwnershipTestState state
;
499 Widget
* widget
= new OwnershipTestWidget(&state
);
500 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
501 params
.native_widget
=
502 new OwnershipTestNativeWidgetPlatform(widget
, &state
);
503 widget
->Init(params
);
505 // Now simulate a destroy of the platform native widget from the OS:
506 #if defined(USE_AURA)
507 delete widget
->GetNativeView();
508 #elif defined(OS_WIN)
509 DestroyWindow(widget
->GetNativeView());
512 EXPECT_TRUE(state
.widget_deleted
);
513 EXPECT_TRUE(state
.native_widget_deleted
);
516 // NativeWidget owns its Widget, part 4: NativeWidget is a NativeWidget,
517 // destroyed by the view hierarchy that contains it.
518 TEST_F(WidgetOwnershipTest
,
519 Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy
) {
520 OwnershipTestState state
;
522 Widget
* toplevel
= CreateTopLevelPlatformWidget();
524 Widget
* widget
= new OwnershipTestWidget(&state
);
525 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
526 params
.native_widget
=
527 new OwnershipTestNativeWidgetPlatform(widget
, &state
);
528 params
.parent
= toplevel
->GetNativeView();
529 widget
->Init(params
);
531 // Destroy the widget (achieved by closing the toplevel).
532 toplevel
->CloseNow();
534 // The NativeWidget won't be deleted until after a return to the message loop
535 // so we have to run pending messages before testing the destruction status.
536 RunPendingMessages();
538 EXPECT_TRUE(state
.widget_deleted
);
539 EXPECT_TRUE(state
.native_widget_deleted
);
542 // NativeWidget owns its Widget, part 5: NativeWidget is a NativeWidget,
543 // we close it directly.
544 TEST_F(WidgetOwnershipTest
,
545 Ownership_ViewsNativeWidgetOwnsWidget_Close
) {
546 OwnershipTestState state
;
548 Widget
* toplevel
= CreateTopLevelPlatformWidget();
550 Widget
* widget
= new OwnershipTestWidget(&state
);
551 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
552 params
.native_widget
=
553 new OwnershipTestNativeWidgetPlatform(widget
, &state
);
554 params
.parent
= toplevel
->GetNativeView();
555 widget
->Init(params
);
557 // Destroy the widget.
559 toplevel
->CloseNow();
561 // The NativeWidget won't be deleted until after a return to the message loop
562 // so we have to run pending messages before testing the destruction status.
563 RunPendingMessages();
565 EXPECT_TRUE(state
.widget_deleted
);
566 EXPECT_TRUE(state
.native_widget_deleted
);
569 // Widget owns its NativeWidget and has a WidgetDelegateView as its contents.
570 TEST_F(WidgetOwnershipTest
,
571 Ownership_WidgetOwnsNativeWidgetWithWithWidgetDelegateView
) {
572 OwnershipTestState state
;
574 WidgetDelegateView
* delegate_view
= new WidgetDelegateView
;
576 scoped_ptr
<Widget
> widget(new OwnershipTestWidget(&state
));
577 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
578 params
.native_widget
=
579 new OwnershipTestNativeWidgetPlatform(widget
.get(), &state
);
580 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
581 params
.delegate
= delegate_view
;
582 widget
->Init(params
);
583 widget
->SetContentsView(delegate_view
);
585 // Now delete the Widget. There should be no crash or use-after-free.
588 EXPECT_TRUE(state
.widget_deleted
);
589 EXPECT_TRUE(state
.native_widget_deleted
);
592 ////////////////////////////////////////////////////////////////////////////////
593 // Test to verify using various Widget methods doesn't crash when the underlying
594 // NativeView is destroyed.
596 class WidgetWithDestroyedNativeViewTest
: public ViewsTestBase
{
598 WidgetWithDestroyedNativeViewTest() {}
599 virtual ~WidgetWithDestroyedNativeViewTest() {}
601 void InvokeWidgetMethods(Widget
* widget
) {
602 widget
->GetNativeView();
603 widget
->GetNativeWindow();
604 ui::Accelerator accelerator
;
605 widget
->GetAccelerator(0, &accelerator
);
606 widget
->GetTopLevelWidget();
607 widget
->GetWindowBoundsInScreen();
608 widget
->GetClientAreaBoundsInScreen();
609 widget
->SetBounds(gfx::Rect(0, 0, 100, 80));
610 widget
->SetSize(gfx::Size(10, 11));
611 widget
->SetBoundsConstrained(gfx::Rect(0, 0, 120, 140));
612 widget
->SetVisibilityChangedAnimationsEnabled(false);
613 widget
->StackAtTop();
619 widget
->Deactivate();
621 widget
->DisableInactiveRendering();
622 widget
->SetAlwaysOnTop(true);
623 widget
->IsAlwaysOnTop();
627 widget
->IsMaximized();
628 widget
->IsFullscreen();
629 widget
->SetOpacity(0);
630 widget
->SetUseDragFrame(true);
631 widget
->FlashFrame(true);
633 widget
->GetThemeProvider();
634 widget
->GetNativeTheme();
635 widget
->GetFocusManager();
636 widget
->GetInputMethod();
637 widget
->SchedulePaintInRect(gfx::Rect(0, 0, 1, 2));
638 widget
->IsMouseEventsEnabled();
639 widget
->SetNativeWindowProperty("xx", widget
);
640 widget
->GetNativeWindowProperty("xx");
641 widget
->GetFocusTraversable();
643 widget
->ReorderNativeViews();
644 widget
->SetCapture(widget
->GetRootView());
645 widget
->ReleaseCapture();
646 widget
->HasCapture();
647 widget
->GetWorkAreaBoundsInScreen();
648 // These three crash with NativeWidgetWin, so I'm assuming we don't need
649 // them to work for the other NativeWidget impls.
650 // widget->CenterWindow(gfx::Size(50, 60));
651 // widget->GetRestoredBounds();
652 // widget->ShowInactive();
656 DISALLOW_COPY_AND_ASSIGN(WidgetWithDestroyedNativeViewTest
);
659 TEST_F(WidgetWithDestroyedNativeViewTest
, Test
) {
662 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
663 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
667 widget
.native_widget_private()->CloseNow();
668 InvokeWidgetMethods(&widget
);
670 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
673 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
674 params
.native_widget
= new DesktopNativeWidgetAura(&widget
);
675 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
679 widget
.native_widget_private()->CloseNow();
680 InvokeWidgetMethods(&widget
);
685 ////////////////////////////////////////////////////////////////////////////////
686 // Widget observer tests.
689 class WidgetObserverTest
: public WidgetTest
, public WidgetObserver
{
693 widget_closed_(NULL
),
694 widget_activated_(NULL
),
696 widget_hidden_(NULL
),
697 widget_bounds_changed_(NULL
) {
700 virtual ~WidgetObserverTest() {}
702 // Overridden from WidgetObserver:
703 virtual void OnWidgetDestroying(Widget
* widget
) OVERRIDE
{
704 if (active_
== widget
)
706 widget_closed_
= widget
;
709 virtual void OnWidgetActivationChanged(Widget
* widget
,
710 bool active
) OVERRIDE
{
712 if (widget_activated_
)
713 widget_activated_
->Deactivate();
714 widget_activated_
= widget
;
717 if (widget_activated_
== widget
)
718 widget_activated_
= NULL
;
719 widget_deactivated_
= widget
;
723 virtual void OnWidgetVisibilityChanged(Widget
* widget
,
724 bool visible
) OVERRIDE
{
726 widget_shown_
= widget
;
728 widget_hidden_
= widget
;
731 virtual void OnWidgetBoundsChanged(Widget
* widget
,
732 const gfx::Rect
& new_bounds
) OVERRIDE
{
733 widget_bounds_changed_
= widget
;
738 widget_closed_
= NULL
;
739 widget_activated_
= NULL
;
740 widget_deactivated_
= NULL
;
741 widget_shown_
= NULL
;
742 widget_hidden_
= NULL
;
743 widget_bounds_changed_
= NULL
;
746 Widget
* NewWidget() {
747 Widget
* widget
= CreateTopLevelNativeWidget();
748 widget
->AddObserver(this);
752 const Widget
* active() const { return active_
; }
753 const Widget
* widget_closed() const { return widget_closed_
; }
754 const Widget
* widget_activated() const { return widget_activated_
; }
755 const Widget
* widget_deactivated() const { return widget_deactivated_
; }
756 const Widget
* widget_shown() const { return widget_shown_
; }
757 const Widget
* widget_hidden() const { return widget_hidden_
; }
758 const Widget
* widget_bounds_changed() const { return widget_bounds_changed_
; }
763 Widget
* widget_closed_
;
764 Widget
* widget_activated_
;
765 Widget
* widget_deactivated_
;
766 Widget
* widget_shown_
;
767 Widget
* widget_hidden_
;
768 Widget
* widget_bounds_changed_
;
771 TEST_F(WidgetObserverTest
, DISABLED_ActivationChange
) {
772 Widget
* toplevel
= CreateTopLevelPlatformWidget();
774 Widget
* toplevel1
= NewWidget();
775 Widget
* toplevel2
= NewWidget();
782 toplevel1
->Activate();
784 RunPendingMessages();
785 EXPECT_EQ(toplevel1
, widget_activated());
787 toplevel2
->Activate();
788 RunPendingMessages();
789 EXPECT_EQ(toplevel1
, widget_deactivated());
790 EXPECT_EQ(toplevel2
, widget_activated());
791 EXPECT_EQ(toplevel2
, active());
793 toplevel
->CloseNow();
796 TEST_F(WidgetObserverTest
, DISABLED_VisibilityChange
) {
797 Widget
* toplevel
= CreateTopLevelPlatformWidget();
799 Widget
* child1
= NewWidget();
800 Widget
* child2
= NewWidget();
809 EXPECT_EQ(child1
, widget_hidden());
812 EXPECT_EQ(child2
, widget_hidden());
815 EXPECT_EQ(child1
, widget_shown());
818 EXPECT_EQ(child2
, widget_shown());
820 toplevel
->CloseNow();
823 TEST_F(WidgetObserverTest
, DestroyBubble
) {
824 Widget
* anchor
= CreateTopLevelPlatformWidget();
827 BubbleDelegateView
* bubble_delegate
=
828 new BubbleDelegateView(anchor
->client_view(), BubbleBorder::NONE
);
829 Widget
* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate
));
830 bubble_widget
->Show();
831 bubble_widget
->CloseNow();
837 TEST_F(WidgetObserverTest
, WidgetBoundsChanged
) {
838 Widget
* child1
= NewWidget();
839 Widget
* child2
= NewWidget();
841 child1
->OnNativeWidgetMove();
842 EXPECT_EQ(child1
, widget_bounds_changed());
844 child2
->OnNativeWidgetMove();
845 EXPECT_EQ(child2
, widget_bounds_changed());
847 child1
->OnNativeWidgetSizeChanged(gfx::Size());
848 EXPECT_EQ(child1
, widget_bounds_changed());
850 child2
->OnNativeWidgetSizeChanged(gfx::Size());
851 EXPECT_EQ(child2
, widget_bounds_changed());
854 #if !defined(USE_AURA) && defined(OS_WIN)
855 // Aura needs shell to maximize/fullscreen window.
856 // NativeWidgetGtk doesn't implement GetRestoredBounds.
857 TEST_F(WidgetTest
, GetRestoredBounds
) {
858 Widget
* toplevel
= CreateTopLevelPlatformWidget();
859 EXPECT_EQ(toplevel
->GetWindowBoundsInScreen().ToString(),
860 toplevel
->GetRestoredBounds().ToString());
862 toplevel
->Maximize();
863 RunPendingMessages();
864 EXPECT_NE(toplevel
->GetWindowBoundsInScreen().ToString(),
865 toplevel
->GetRestoredBounds().ToString());
866 EXPECT_GT(toplevel
->GetRestoredBounds().width(), 0);
867 EXPECT_GT(toplevel
->GetRestoredBounds().height(), 0);
870 RunPendingMessages();
871 EXPECT_EQ(toplevel
->GetWindowBoundsInScreen().ToString(),
872 toplevel
->GetRestoredBounds().ToString());
874 toplevel
->SetFullscreen(true);
875 RunPendingMessages();
876 EXPECT_NE(toplevel
->GetWindowBoundsInScreen().ToString(),
877 toplevel
->GetRestoredBounds().ToString());
878 EXPECT_GT(toplevel
->GetRestoredBounds().width(), 0);
879 EXPECT_GT(toplevel
->GetRestoredBounds().height(), 0);
883 // Test that window state is not changed after getting out of full screen.
884 TEST_F(WidgetTest
, ExitFullscreenRestoreState
) {
885 Widget
* toplevel
= CreateTopLevelPlatformWidget();
888 RunPendingMessages();
890 // This should be a normal state window.
891 EXPECT_EQ(ui::SHOW_STATE_NORMAL
, GetWidgetShowState(toplevel
));
893 toplevel
->SetFullscreen(true);
894 while (GetWidgetShowState(toplevel
) != ui::SHOW_STATE_FULLSCREEN
)
895 RunPendingMessages();
896 toplevel
->SetFullscreen(false);
897 while (GetWidgetShowState(toplevel
) == ui::SHOW_STATE_FULLSCREEN
)
898 RunPendingMessages();
900 // And it should still be in normal state after getting out of full screen.
901 EXPECT_EQ(ui::SHOW_STATE_NORMAL
, GetWidgetShowState(toplevel
));
903 // Now, make it maximized.
904 toplevel
->Maximize();
905 while (GetWidgetShowState(toplevel
) != ui::SHOW_STATE_MAXIMIZED
)
906 RunPendingMessages();
908 toplevel
->SetFullscreen(true);
909 while (GetWidgetShowState(toplevel
) != ui::SHOW_STATE_FULLSCREEN
)
910 RunPendingMessages();
911 toplevel
->SetFullscreen(false);
912 while (GetWidgetShowState(toplevel
) == ui::SHOW_STATE_FULLSCREEN
)
913 RunPendingMessages();
915 // And it stays maximized after getting out of full screen.
916 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED
, GetWidgetShowState(toplevel
));
920 RunPendingMessages();
923 #if defined(USE_AURA)
924 // The key-event propagation from Widget happens differently on aura and
925 // non-aura systems because of the difference in IME. So this test works only on
927 TEST_F(WidgetTest
, KeyboardInputEvent
) {
928 Widget
* toplevel
= CreateTopLevelPlatformWidget();
929 View
* container
= toplevel
->client_view();
931 Textfield
* textfield
= new Textfield();
932 textfield
->SetText(ASCIIToUTF16("some text"));
933 container
->AddChildView(textfield
);
935 textfield
->RequestFocus();
937 // The press gets handled. The release doesn't have an effect.
938 ui::KeyEvent
backspace_p(ui::ET_KEY_PRESSED
, ui::VKEY_DELETE
, 0, false);
939 toplevel
->OnKeyEvent(&backspace_p
);
940 EXPECT_TRUE(backspace_p
.stopped_propagation());
941 ui::KeyEvent
backspace_r(ui::ET_KEY_RELEASED
, ui::VKEY_DELETE
, 0, false);
942 toplevel
->OnKeyEvent(&backspace_r
);
943 EXPECT_FALSE(backspace_r
.handled());
948 // Verifies bubbles result in a focus lost when shown.
949 // TODO(msw): this tests relies on focus, it needs to be in
950 // interactive_ui_tests.
951 TEST_F(WidgetTest
, DISABLED_FocusChangesOnBubble
) {
952 // Create a widget, show and activate it and focus the contents view.
953 View
* contents_view
= new View
;
954 contents_view
->set_focusable(true);
956 Widget::InitParams init_params
=
957 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS
);
958 init_params
.bounds
= gfx::Rect(0, 0, 200, 200);
959 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
960 #if !defined(OS_CHROMEOS)
961 init_params
.native_widget
= new DesktopNativeWidgetAura(&widget
);
963 widget
.Init(init_params
);
964 widget
.SetContentsView(contents_view
);
967 contents_view
->RequestFocus();
968 EXPECT_TRUE(contents_view
->HasFocus());
971 BubbleDelegateView
* bubble_delegate_view
=
972 new BubbleDelegateView(contents_view
, BubbleBorder::TOP_LEFT
);
973 bubble_delegate_view
->set_focusable(true);
974 BubbleDelegateView::CreateBubble(bubble_delegate_view
)->Show();
975 bubble_delegate_view
->RequestFocus();
977 // |contents_view_| should no longer have focus.
978 EXPECT_FALSE(contents_view
->HasFocus());
979 EXPECT_TRUE(bubble_delegate_view
->HasFocus());
981 bubble_delegate_view
->GetWidget()->CloseNow();
983 // Closing the bubble should result in focus going back to the contents view.
984 EXPECT_TRUE(contents_view
->HasFocus());
987 // Desktop native widget Aura tests are for non Chrome OS platforms.
988 #if !defined(OS_CHROMEOS)
989 // Test to ensure that after minimize, view width is set to zero.
990 TEST_F(WidgetTest
, TestViewWidthAfterMinimizingWidget
) {
993 Widget::InitParams init_params
=
994 CreateParams(Widget::InitParams::TYPE_WINDOW
);
995 init_params
.show_state
= ui::SHOW_STATE_NORMAL
;
996 gfx::Rect
initial_bounds(0, 0, 300, 400);
997 init_params
.bounds
= initial_bounds
;
998 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
999 init_params
.native_widget
= new DesktopNativeWidgetAura(&widget
);
1000 widget
.Init(init_params
);
1001 NonClientView
* non_client_view
= widget
.non_client_view();
1002 NonClientFrameView
* frame_view
= new MinimumSizeFrameView(&widget
);
1003 non_client_view
->SetFrameView(frame_view
);
1006 EXPECT_EQ(0, frame_view
->width());
1009 // This class validates whether paints are received for a visible Widget.
1010 // To achieve this it overrides the Show and Close methods on the Widget class
1011 // and sets state whether subsequent paints are expected.
1012 class DesktopAuraTestValidPaintWidget
: public views::Widget
{
1014 DesktopAuraTestValidPaintWidget()
1015 : expect_paint_(true),
1016 received_paint_while_hidden_(false) {
1019 virtual ~DesktopAuraTestValidPaintWidget() {
1022 virtual void Show() OVERRIDE
{
1023 expect_paint_
= true;
1024 views::Widget::Show();
1027 virtual void Close() OVERRIDE
{
1028 expect_paint_
= false;
1029 views::Widget::Close();
1033 expect_paint_
= false;
1034 views::Widget::Hide();
1037 virtual void OnNativeWidgetPaint(gfx::Canvas
* canvas
) OVERRIDE
{
1038 EXPECT_TRUE(expect_paint_
);
1040 received_paint_while_hidden_
= true;
1041 views::Widget::OnNativeWidgetPaint(canvas
);
1044 bool received_paint_while_hidden() const {
1045 return received_paint_while_hidden_
;
1050 bool received_paint_while_hidden_
;
1053 TEST_F(WidgetTest
, DesktopNativeWidgetAuraNoPaintAfterCloseTest
) {
1054 View
* contents_view
= new View
;
1055 contents_view
->set_focusable(true);
1056 DesktopAuraTestValidPaintWidget widget
;
1057 Widget::InitParams init_params
=
1058 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS
);
1059 init_params
.bounds
= gfx::Rect(0, 0, 200, 200);
1060 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1061 init_params
.native_widget
= new DesktopNativeWidgetAura(&widget
);
1062 widget
.Init(init_params
);
1063 widget
.SetContentsView(contents_view
);
1066 RunPendingMessages();
1067 widget
.SchedulePaintInRect(init_params
.bounds
);
1069 RunPendingMessages();
1070 EXPECT_FALSE(widget
.received_paint_while_hidden());
1073 TEST_F(WidgetTest
, DesktopNativeWidgetAuraNoPaintAfterHideTest
) {
1074 View
* contents_view
= new View
;
1075 contents_view
->set_focusable(true);
1076 DesktopAuraTestValidPaintWidget widget
;
1077 Widget::InitParams init_params
=
1078 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS
);
1079 init_params
.bounds
= gfx::Rect(0, 0, 200, 200);
1080 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1081 init_params
.native_widget
= new DesktopNativeWidgetAura(&widget
);
1082 widget
.Init(init_params
);
1083 widget
.SetContentsView(contents_view
);
1086 RunPendingMessages();
1087 widget
.SchedulePaintInRect(init_params
.bounds
);
1089 RunPendingMessages();
1090 EXPECT_FALSE(widget
.received_paint_while_hidden());
1094 // This class provides functionality to create fullscreen and top level popup
1095 // windows. It additionally tests whether the destruction of these windows
1096 // occurs correctly in desktop AURA without crashing.
1097 // It provides facilities to test the following cases:-
1098 // 1. Child window destroyed which should lead to the destruction of the
1100 // 2. Parent window destroyed which should lead to the child being destroyed.
1101 class DesktopAuraTopLevelWindowTest
1102 : public views::TestViewsDelegate
,
1103 public aura::WindowObserver
{
1105 DesktopAuraTopLevelWindowTest()
1106 : top_level_widget_(NULL
),
1107 owned_window_(NULL
),
1108 owner_destroyed_(false),
1109 owned_window_destroyed_(false) {}
1111 virtual ~DesktopAuraTopLevelWindowTest() {
1112 EXPECT_TRUE(owner_destroyed_
);
1113 EXPECT_TRUE(owned_window_destroyed_
);
1114 top_level_widget_
= NULL
;
1115 owned_window_
= NULL
;
1118 // views::TestViewsDelegate overrides.
1119 virtual void OnBeforeWidgetInit(
1120 Widget::InitParams
* params
,
1121 internal::NativeWidgetDelegate
* delegate
) OVERRIDE
{
1122 if (!params
->native_widget
)
1123 params
->native_widget
= new views::DesktopNativeWidgetAura(delegate
);
1126 void CreateTopLevelWindow(const gfx::Rect
& bounds
, bool fullscreen
) {
1127 Widget::InitParams init_params
;
1128 init_params
.type
= Widget::InitParams::TYPE_WINDOW
;
1129 init_params
.bounds
= bounds
;
1130 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1131 init_params
.layer_type
= ui::LAYER_NOT_DRAWN
;
1132 init_params
.accept_events
= fullscreen
;
1134 widget_
.Init(init_params
);
1136 owned_window_
= new aura::Window(&child_window_delegate_
);
1137 owned_window_
->SetType(aura::client::WINDOW_TYPE_NORMAL
);
1138 owned_window_
->SetName("TestTopLevelWindow");
1140 owned_window_
->SetProperty(aura::client::kShowStateKey
,
1141 ui::SHOW_STATE_FULLSCREEN
);
1143 owned_window_
->SetType(aura::client::WINDOW_TYPE_MENU
);
1145 owned_window_
->Init(ui::LAYER_TEXTURED
);
1146 aura::client::ParentWindowWithContext(
1148 widget_
.GetNativeView()->GetRootWindow(),
1149 gfx::Rect(0, 0, 1900, 1600));
1150 owned_window_
->Show();
1151 owned_window_
->AddObserver(this);
1153 ASSERT_TRUE(owned_window_
->parent() != NULL
);
1154 owned_window_
->parent()->AddObserver(this);
1157 views::Widget::GetWidgetForNativeView(owned_window_
->parent());
1158 ASSERT_TRUE(top_level_widget_
!= NULL
);
1161 void DestroyOwnedWindow() {
1162 ASSERT_TRUE(owned_window_
!= NULL
);
1163 delete owned_window_
;
1166 void DestroyOwnerWindow() {
1167 ASSERT_TRUE(top_level_widget_
!= NULL
);
1168 top_level_widget_
->CloseNow();
1171 virtual void OnWindowDestroying(aura::Window
* window
) OVERRIDE
{
1172 window
->RemoveObserver(this);
1173 if (window
== owned_window_
) {
1174 owned_window_destroyed_
= true;
1175 } else if (window
== top_level_widget_
->GetNativeView()) {
1176 owner_destroyed_
= true;
1178 ADD_FAILURE() << "Unexpected window destroyed callback: " << window
;
1183 views::Widget widget_
;
1184 views::Widget
* top_level_widget_
;
1185 aura::Window
* owned_window_
;
1186 bool owner_destroyed_
;
1187 bool owned_window_destroyed_
;
1188 aura::test::TestWindowDelegate child_window_delegate_
;
1190 DISALLOW_COPY_AND_ASSIGN(DesktopAuraTopLevelWindowTest
);
1193 TEST_F(WidgetTest
, DesktopAuraFullscreenWindowDestroyedBeforeOwnerTest
) {
1194 ViewsDelegate::views_delegate
= NULL
;
1195 DesktopAuraTopLevelWindowTest fullscreen_window
;
1196 ASSERT_NO_FATAL_FAILURE(fullscreen_window
.CreateTopLevelWindow(
1197 gfx::Rect(0, 0, 200, 200), true));
1199 RunPendingMessages();
1200 ASSERT_NO_FATAL_FAILURE(fullscreen_window
.DestroyOwnedWindow());
1201 RunPendingMessages();
1204 TEST_F(WidgetTest
, DesktopAuraFullscreenWindowOwnerDestroyed
) {
1205 ViewsDelegate::views_delegate
= NULL
;
1207 DesktopAuraTopLevelWindowTest fullscreen_window
;
1208 ASSERT_NO_FATAL_FAILURE(fullscreen_window
.CreateTopLevelWindow(
1209 gfx::Rect(0, 0, 200, 200), true));
1211 RunPendingMessages();
1212 ASSERT_NO_FATAL_FAILURE(fullscreen_window
.DestroyOwnerWindow());
1213 RunPendingMessages();
1216 // TODO(erg): Disabled on desktop linux until http://crbug.com/288988 is fixed.
1217 #if !defined(OS_LINUX)
1218 TEST_F(WidgetTest
, DesktopAuraTopLevelOwnedPopupTest
) {
1219 ViewsDelegate::views_delegate
= NULL
;
1220 DesktopAuraTopLevelWindowTest popup_window
;
1221 ASSERT_NO_FATAL_FAILURE(popup_window
.CreateTopLevelWindow(
1222 gfx::Rect(0, 0, 200, 200), false));
1224 RunPendingMessages();
1225 ASSERT_NO_FATAL_FAILURE(popup_window
.DestroyOwnedWindow());
1226 RunPendingMessages();
1230 // Test to ensure that the aura Window's visiblity state is set to visible if
1231 // the underlying widget is hidden and then shown.
1232 TEST_F(WidgetTest
, TestWindowVisibilityAfterHide
) {
1235 Widget::InitParams init_params
=
1236 CreateParams(Widget::InitParams::TYPE_WINDOW
);
1237 init_params
.show_state
= ui::SHOW_STATE_NORMAL
;
1238 gfx::Rect
initial_bounds(0, 0, 300, 400);
1239 init_params
.bounds
= initial_bounds
;
1240 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1241 init_params
.native_widget
= new DesktopNativeWidgetAura(&widget
);
1242 widget
.Init(init_params
);
1243 NonClientView
* non_client_view
= widget
.non_client_view();
1244 NonClientFrameView
* frame_view
= new MinimumSizeFrameView(&widget
);
1245 non_client_view
->SetFrameView(frame_view
);
1248 EXPECT_FALSE(widget
.GetNativeView()->IsVisible());
1250 EXPECT_TRUE(widget
.GetNativeView()->IsVisible());
1253 // The following code verifies we can correctly destroy a Widget from a mouse
1254 // enter/exit. We could test move/drag/enter/exit but in general we don't run
1255 // nested message loops from such events, nor has the code ever really dealt
1256 // with this situation.
1258 // Class that closes the widget (which ends up deleting it immediately) when the
1259 // appropriate event is received.
1260 class CloseWidgetView
: public View
{
1262 explicit CloseWidgetView(ui::EventType event_type
)
1263 : event_type_(event_type
) {
1267 virtual bool OnMousePressed(const ui::MouseEvent
& event
) OVERRIDE
{
1268 if (!CloseWidget(event
))
1269 View::OnMousePressed(event
);
1272 virtual bool OnMouseDragged(const ui::MouseEvent
& event
) OVERRIDE
{
1273 if (!CloseWidget(event
))
1274 View::OnMouseDragged(event
);
1277 virtual void OnMouseReleased(const ui::MouseEvent
& event
) OVERRIDE
{
1278 if (!CloseWidget(event
))
1279 View::OnMouseReleased(event
);
1281 virtual void OnMouseMoved(const ui::MouseEvent
& event
) OVERRIDE
{
1282 if (!CloseWidget(event
))
1283 View::OnMouseMoved(event
);
1285 virtual void OnMouseEntered(const ui::MouseEvent
& event
) OVERRIDE
{
1286 if (!CloseWidget(event
))
1287 View::OnMouseEntered(event
);
1291 bool CloseWidget(const ui::LocatedEvent
& event
) {
1292 if (event
.type() == event_type_
) {
1293 // Go through NativeWidgetPrivate to simulate what happens if the OS
1294 // deletes the NativeWindow out from under us.
1295 GetWidget()->native_widget_private()->CloseNow();
1301 const ui::EventType event_type_
;
1303 DISALLOW_COPY_AND_ASSIGN(CloseWidgetView
);
1306 // Generates two moves (first generates enter, second real move), a press, drag
1307 // and release stopping at |last_event_type|.
1308 void GenerateMouseEvents(Widget
* widget
, ui::EventType last_event_type
) {
1309 const gfx::Rect
screen_bounds(widget
->GetWindowBoundsInScreen());
1310 ui::MouseEvent
move_event(ui::ET_MOUSE_MOVED
, screen_bounds
.CenterPoint(),
1311 screen_bounds
.CenterPoint(), 0);
1312 aura::RootWindowHostDelegate
* rwhd
=
1313 widget
->GetNativeWindow()->GetDispatcher()->AsRootWindowHostDelegate();
1314 rwhd
->OnHostMouseEvent(&move_event
);
1315 if (last_event_type
== ui::ET_MOUSE_ENTERED
)
1317 rwhd
->OnHostMouseEvent(&move_event
);
1318 if (last_event_type
== ui::ET_MOUSE_MOVED
)
1321 ui::MouseEvent
press_event(ui::ET_MOUSE_PRESSED
, screen_bounds
.CenterPoint(),
1322 screen_bounds
.CenterPoint(), 0);
1323 rwhd
->OnHostMouseEvent(&press_event
);
1324 if (last_event_type
== ui::ET_MOUSE_PRESSED
)
1327 gfx::Point
end_point(screen_bounds
.CenterPoint());
1328 end_point
.Offset(1, 1);
1329 ui::MouseEvent
drag_event(ui::ET_MOUSE_DRAGGED
, end_point
, end_point
, 0);
1330 rwhd
->OnHostMouseEvent(&drag_event
);
1331 if (last_event_type
== ui::ET_MOUSE_DRAGGED
)
1334 ui::MouseEvent
release_event(ui::ET_MOUSE_RELEASED
, end_point
, end_point
, 0);
1335 rwhd
->OnHostMouseEvent(&release_event
);
1338 // Creates a widget and invokes GenerateMouseEvents() with |last_event_type|.
1339 void RunCloseWidgetDuringDispatchTest(WidgetTest
* test
,
1340 ui::EventType last_event_type
) {
1341 // |widget| is deleted by CloseWidgetView.
1342 Widget
* widget
= new Widget
;
1343 Widget::InitParams params
=
1344 test
->CreateParams(Widget::InitParams::TYPE_POPUP
);
1345 params
.native_widget
= new DesktopNativeWidgetAura(widget
);
1346 params
.bounds
= gfx::Rect(0, 0, 50, 100);
1347 widget
->Init(params
);
1348 widget
->SetContentsView(new CloseWidgetView(last_event_type
));
1350 GenerateMouseEvents(widget
, last_event_type
);
1353 // Verifies deleting the widget from a mouse pressed event doesn't crash.
1354 TEST_F(WidgetTest
, CloseWidgetDuringMousePress
) {
1355 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_PRESSED
);
1358 // Verifies deleting the widget from a mouse released event doesn't crash.
1359 TEST_F(WidgetTest
, CloseWidgetDuringMouseReleased
) {
1360 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_RELEASED
);
1363 #endif // !defined(OS_CHROMEOS)
1365 // Tests that wheel events generated from scroll events are targetted to the
1366 // views under the cursor when the focused view does not processed them.
1367 TEST_F(WidgetTest
, WheelEventsFromScrollEventTarget
) {
1368 EventCountView
* cursor_view
= new EventCountView
;
1369 cursor_view
->SetBounds(60, 0, 50, 40);
1371 Widget
* widget
= CreateTopLevelPlatformWidget();
1372 widget
->GetRootView()->AddChildView(cursor_view
);
1374 // Generate a scroll event on the cursor view.
1375 ui::ScrollEvent
scroll(ui::ET_SCROLL
,
1377 ui::EventTimeForNow(),
1382 widget
->OnScrollEvent(&scroll
);
1384 EXPECT_EQ(1, cursor_view
->GetEventCount(ui::ET_SCROLL
));
1385 EXPECT_EQ(1, cursor_view
->GetEventCount(ui::ET_MOUSEWHEEL
));
1387 cursor_view
->ResetCounts();
1389 ui::ScrollEvent
scroll2(ui::ET_SCROLL
,
1391 ui::EventTimeForNow(),
1396 widget
->OnScrollEvent(&scroll2
);
1398 EXPECT_EQ(0, cursor_view
->GetEventCount(ui::ET_SCROLL
));
1399 EXPECT_EQ(0, cursor_view
->GetEventCount(ui::ET_MOUSEWHEEL
));
1404 #endif // defined(USE_AURA)
1406 // Tests that if a scroll-begin gesture is not handled, then subsequent scroll
1407 // events are not dispatched to any view.
1408 TEST_F(WidgetTest
, GestureScrollEventDispatching
) {
1409 EventCountView
* noscroll_view
= new EventCountView
;
1410 EventCountView
* scroll_view
= new ScrollableEventCountView
;
1412 noscroll_view
->SetBounds(0, 0, 50, 40);
1413 scroll_view
->SetBounds(60, 0, 40, 40);
1415 Widget
* widget
= CreateTopLevelPlatformWidget();
1416 widget
->GetRootView()->AddChildView(noscroll_view
);
1417 widget
->GetRootView()->AddChildView(scroll_view
);
1420 ui::GestureEvent
begin(ui::ET_GESTURE_SCROLL_BEGIN
,
1421 5, 5, 0, base::TimeDelta(),
1422 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN
, 0, 0),
1424 widget
->OnGestureEvent(&begin
);
1425 ui::GestureEvent
update(ui::ET_GESTURE_SCROLL_UPDATE
,
1426 25, 15, 0, base::TimeDelta(),
1427 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE
, 20, 10),
1429 widget
->OnGestureEvent(&update
);
1430 ui::GestureEvent
end(ui::ET_GESTURE_SCROLL_END
,
1431 25, 15, 0, base::TimeDelta(),
1432 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END
, 0, 0),
1434 widget
->OnGestureEvent(&end
);
1436 EXPECT_EQ(1, noscroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
1437 EXPECT_EQ(0, noscroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
1438 EXPECT_EQ(0, noscroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
1442 ui::GestureEvent
begin(ui::ET_GESTURE_SCROLL_BEGIN
,
1443 65, 5, 0, base::TimeDelta(),
1444 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN
, 0, 0),
1446 widget
->OnGestureEvent(&begin
);
1447 ui::GestureEvent
update(ui::ET_GESTURE_SCROLL_UPDATE
,
1448 85, 15, 0, base::TimeDelta(),
1449 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE
, 20, 10),
1451 widget
->OnGestureEvent(&update
);
1452 ui::GestureEvent
end(ui::ET_GESTURE_SCROLL_END
,
1453 85, 15, 0, base::TimeDelta(),
1454 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END
, 0, 0),
1456 widget
->OnGestureEvent(&end
);
1458 EXPECT_EQ(1, scroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN
));
1459 EXPECT_EQ(1, scroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE
));
1460 EXPECT_EQ(1, scroll_view
->GetEventCount(ui::ET_GESTURE_SCROLL_END
));
1466 // Tests that event-handlers installed on the RootView get triggered correctly.
1467 TEST_F(WidgetTest
, EventHandlersOnRootView
) {
1468 Widget
* widget
= CreateTopLevelNativeWidget();
1469 View
* root_view
= widget
->GetRootView();
1471 EventCountView
* view
= new EventCountView
;
1472 view
->SetBounds(0, 0, 20, 20);
1473 root_view
->AddChildView(view
);
1475 EventCountHandler h1
;
1476 root_view
->AddPreTargetHandler(&h1
);
1478 EventCountHandler h2
;
1479 root_view
->AddPostTargetHandler(&h2
);
1481 widget
->SetBounds(gfx::Rect(0, 0, 100, 100));
1484 ui::TouchEvent
pressed(ui::ET_TOUCH_PRESSED
,
1487 ui::EventTimeForNow(),
1488 1.0, 0.0, 1.0, 0.0);
1489 widget
->OnTouchEvent(&pressed
);
1490 EXPECT_EQ(1, h1
.GetEventCount(ui::ET_TOUCH_PRESSED
));
1491 EXPECT_EQ(1, view
->GetEventCount(ui::ET_TOUCH_PRESSED
));
1492 EXPECT_EQ(1, h2
.GetEventCount(ui::ET_TOUCH_PRESSED
));
1494 ui::GestureEvent
begin(ui::ET_GESTURE_BEGIN
,
1495 5, 5, 0, ui::EventTimeForNow(),
1496 ui::GestureEventDetails(ui::ET_GESTURE_BEGIN
, 0, 0), 1);
1497 ui::GestureEvent
end(ui::ET_GESTURE_END
,
1498 5, 5, 0, ui::EventTimeForNow(),
1499 ui::GestureEventDetails(ui::ET_GESTURE_END
, 0, 0), 1);
1500 widget
->OnGestureEvent(&begin
);
1501 EXPECT_EQ(1, h1
.GetEventCount(ui::ET_GESTURE_BEGIN
));
1502 EXPECT_EQ(1, view
->GetEventCount(ui::ET_GESTURE_BEGIN
));
1503 EXPECT_EQ(1, h2
.GetEventCount(ui::ET_GESTURE_BEGIN
));
1505 ui::TouchEvent
released(ui::ET_TOUCH_RELEASED
,
1508 ui::EventTimeForNow(),
1509 1.0, 0.0, 1.0, 0.0);
1510 widget
->OnTouchEvent(&released
);
1511 EXPECT_EQ(1, h1
.GetEventCount(ui::ET_TOUCH_RELEASED
));
1512 EXPECT_EQ(1, view
->GetEventCount(ui::ET_TOUCH_RELEASED
));
1513 EXPECT_EQ(1, h2
.GetEventCount(ui::ET_TOUCH_RELEASED
));
1515 widget
->OnGestureEvent(&end
);
1516 EXPECT_EQ(1, h1
.GetEventCount(ui::ET_GESTURE_END
));
1517 EXPECT_EQ(1, view
->GetEventCount(ui::ET_GESTURE_END
));
1518 EXPECT_EQ(1, h2
.GetEventCount(ui::ET_GESTURE_END
));
1520 ui::ScrollEvent
scroll(ui::ET_SCROLL
,
1522 ui::EventTimeForNow(),
1527 widget
->OnScrollEvent(&scroll
);
1528 EXPECT_EQ(1, h1
.GetEventCount(ui::ET_SCROLL
));
1529 EXPECT_EQ(1, view
->GetEventCount(ui::ET_SCROLL
));
1530 EXPECT_EQ(1, h2
.GetEventCount(ui::ET_SCROLL
));
1535 TEST_F(WidgetTest
, SynthesizeMouseMoveEvent
) {
1536 Widget
* widget
= CreateTopLevelNativeWidget();
1537 View
* root_view
= widget
->GetRootView();
1539 EventCountView
* v1
= new EventCountView();
1540 v1
->SetBounds(0, 0, 10, 10);
1541 root_view
->AddChildView(v1
);
1542 EventCountView
* v2
= new EventCountView();
1543 v2
->SetBounds(0, 10, 10, 10);
1544 root_view
->AddChildView(v2
);
1546 gfx::Point
cursor_location(5, 5);
1547 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
, cursor_location
, cursor_location
,
1549 widget
->OnMouseEvent(&move
);
1551 EXPECT_EQ(1, v1
->GetEventCount(ui::ET_MOUSE_ENTERED
));
1552 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_MOUSE_ENTERED
));
1555 v2
->SetBounds(0, 0, 10, 10);
1556 EXPECT_EQ(0, v2
->GetEventCount(ui::ET_MOUSE_ENTERED
));
1558 widget
->SynthesizeMouseMoveEvent();
1559 EXPECT_EQ(1, v2
->GetEventCount(ui::ET_MOUSE_ENTERED
));
1562 // Used by SingleWindowClosing to count number of times WindowClosing() has
1564 class ClosingDelegate
: public WidgetDelegate
{
1566 ClosingDelegate() : count_(0), widget_(NULL
) {}
1568 int count() const { return count_
; }
1570 void set_widget(views::Widget
* widget
) { widget_
= widget
; }
1572 // WidgetDelegate overrides:
1573 virtual Widget
* GetWidget() OVERRIDE
{ return widget_
; }
1574 virtual const Widget
* GetWidget() const OVERRIDE
{ return widget_
; }
1575 virtual void WindowClosing() OVERRIDE
{
1581 views::Widget
* widget_
;
1583 DISALLOW_COPY_AND_ASSIGN(ClosingDelegate
);
1586 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget
1588 TEST_F(WidgetTest
, SingleWindowClosing
) {
1589 scoped_ptr
<ClosingDelegate
> delegate(new ClosingDelegate());
1590 Widget
* widget
= new Widget(); // Destroyed by CloseNow() below.
1591 Widget::InitParams init_params
=
1592 CreateParams(Widget::InitParams::TYPE_WINDOW
);
1593 init_params
.bounds
= gfx::Rect(0, 0, 200, 200);
1594 init_params
.delegate
= delegate
.get();
1595 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1596 init_params
.native_widget
= new DesktopNativeWidgetAura(widget
);
1598 widget
->Init(init_params
);
1599 EXPECT_EQ(0, delegate
->count());
1601 EXPECT_EQ(1, delegate
->count());
1604 // Used by SetTopLevelCorrectly to track calls to OnBeforeWidgetInit().
1605 class VerifyTopLevelDelegate
: public TestViewsDelegate
{
1607 VerifyTopLevelDelegate()
1608 : on_before_init_called_(false),
1609 is_top_level_(false) {
1612 bool on_before_init_called() const { return on_before_init_called_
; }
1613 bool is_top_level() const { return is_top_level_
; }
1615 virtual void OnBeforeWidgetInit(
1616 Widget::InitParams
* params
,
1617 internal::NativeWidgetDelegate
* delegate
) OVERRIDE
{
1618 on_before_init_called_
= true;
1619 is_top_level_
= params
->top_level
;
1623 bool on_before_init_called_
;
1626 DISALLOW_COPY_AND_ASSIGN(VerifyTopLevelDelegate
);
1629 // Verifies |top_level| is correctly passed to
1630 // ViewsDelegate::OnBeforeWidgetInit().
1631 TEST_F(WidgetTest
, SetTopLevelCorrectly
) {
1632 set_views_delegate(NULL
);
1633 VerifyTopLevelDelegate
* delegate
= new VerifyTopLevelDelegate
;
1634 set_views_delegate(delegate
); // ViewsTestBase takes ownership.
1635 scoped_ptr
<Widget
> widget(new Widget
);
1636 Widget::InitParams params
=
1637 CreateParams(views::Widget::InitParams::TYPE_POPUP
);
1638 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1639 widget
->Init(params
);
1640 EXPECT_TRUE(delegate
->on_before_init_called());
1641 EXPECT_TRUE(delegate
->is_top_level());
1644 // A scumbag View that deletes its owning widget OnMousePressed.
1645 class WidgetDeleterView
: public View
{
1647 WidgetDeleterView() : View() {}
1649 // Overridden from View.
1650 virtual bool OnMousePressed(const ui::MouseEvent
& event
) OVERRIDE
{
1656 DISALLOW_COPY_AND_ASSIGN(WidgetDeleterView
);
1659 TEST_F(WidgetTest
, TestWidgetDeletedInOnMousePressed
) {
1660 Widget
* widget
= new Widget
;
1661 Widget::InitParams params
=
1662 CreateParams(views::Widget::InitParams::TYPE_POPUP
);
1663 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
1664 widget
->Init(params
);
1666 widget
->SetContentsView(new WidgetDeleterView
);
1668 widget
->SetSize(gfx::Size(100, 100));
1671 gfx::Point
click_location(45, 15);
1672 ui::MouseEvent
press(ui::ET_MOUSE_PRESSED
, click_location
, click_location
,
1673 ui::EF_LEFT_MOUSE_BUTTON
);
1674 widget
->OnMouseEvent(&press
);
1676 // Yay we did not crash!
1679 // See description of RunGetNativeThemeFromDestructor() for details.
1680 class GetNativeThemeFromDestructorView
: public WidgetDelegateView
{
1682 GetNativeThemeFromDestructorView() {}
1683 virtual ~GetNativeThemeFromDestructorView() {
1684 VerifyNativeTheme();
1687 virtual View
* GetContentsView() OVERRIDE
{
1692 void VerifyNativeTheme() {
1693 ASSERT_TRUE(GetNativeTheme() != NULL
);
1696 DISALLOW_COPY_AND_ASSIGN(GetNativeThemeFromDestructorView
);
1699 // Verifies GetNativeTheme() from the destructor of a WidgetDelegateView doesn't
1700 // crash. |is_first_run| is true if this is the first call. A return value of
1701 // true indicates this should be run again with a value of false.
1702 // First run uses DesktopNativeWidgetAura (if possible). Second run doesn't.
1703 bool RunGetNativeThemeFromDestructor(const Widget::InitParams
& in_params
,
1704 bool is_first_run
) {
1705 bool needs_second_run
= false;
1706 // Destroyed by CloseNow() below.
1707 Widget
* widget
= new Widget
;
1708 Widget::InitParams
params(in_params
);
1709 // Deletes itself when the Widget is destroyed.
1710 params
.delegate
= new GetNativeThemeFromDestructorView
;
1711 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1713 params
.native_widget
= new DesktopNativeWidgetAura(widget
);
1714 needs_second_run
= true;
1717 widget
->Init(params
);
1719 return needs_second_run
;
1722 // See description of RunGetNativeThemeFromDestructor() for details.
1723 TEST_F(WidgetTest
, GetNativeThemeFromDestructor
) {
1724 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
1725 if (RunGetNativeThemeFromDestructor(params
, true))
1726 RunGetNativeThemeFromDestructor(params
, false);
1729 // Used by HideCloseDestroy. Allows setting a boolean when the widget is
1731 class CloseDestroysWidget
: public Widget
{
1733 explicit CloseDestroysWidget(bool* destroyed
)
1734 : destroyed_(destroyed
) {
1737 virtual ~CloseDestroysWidget() {
1740 base::MessageLoop::current()->QuitNow();
1744 void Detach() { destroyed_
= NULL
; }
1747 // If non-null set to true from destructor.
1750 DISALLOW_COPY_AND_ASSIGN(CloseDestroysWidget
);
1753 // Verifies Close() results in destroying.
1754 TEST_F(WidgetTest
, CloseDestroys
) {
1755 bool destroyed
= false;
1756 CloseDestroysWidget
* widget
= new CloseDestroysWidget(&destroyed
);
1757 Widget::InitParams params
=
1758 CreateParams(views::Widget::InitParams::TYPE_MENU
);
1759 params
.opacity
= Widget::InitParams::OPAQUE_WINDOW
;
1760 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1761 params
.native_widget
= new DesktopNativeWidgetAura(widget
);
1763 widget
->Init(params
);
1767 // Run the message loop as Close() asynchronously deletes.
1768 RunPendingMessages();
1769 EXPECT_TRUE(destroyed
);
1770 // Close() should destroy the widget. If not we'll cleanup to avoid leaks.
1777 // A view that consumes mouse-pressed event and gesture-tap-down events.
1778 class RootViewTestView
: public View
{
1780 RootViewTestView(): View() {}
1783 virtual bool OnMousePressed(const ui::MouseEvent
& event
) OVERRIDE
{
1787 virtual void OnGestureEvent(ui::GestureEvent
* event
) OVERRIDE
{
1788 if (event
->type() == ui::ET_GESTURE_TAP_DOWN
)
1789 event
->SetHandled();
1793 // Checks if RootView::*_handler_ fields are unset when widget is hidden.
1794 // Fails on chromium.webkit Windows bot, see crbug.com/264872.
1796 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1797 DISABLED_TestRootViewHandlersWhenHidden
1799 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1800 TestRootViewHandlersWhenHidden
1802 TEST_F(WidgetTest
, MAYBE_DisableTestRootViewHandlersWhenHidden
) {
1803 Widget
* widget
= CreateTopLevelNativeWidget();
1804 widget
->SetBounds(gfx::Rect(0, 0, 300, 300));
1805 View
* view
= new RootViewTestView();
1806 view
->SetBounds(0, 0, 300, 300);
1807 internal::RootView
* root_view
=
1808 static_cast<internal::RootView
*>(widget
->GetRootView());
1809 root_view
->AddChildView(view
);
1811 // Check RootView::mouse_pressed_handler_.
1813 EXPECT_EQ(NULL
, GetMousePressedHandler(root_view
));
1814 gfx::Point
click_location(45, 15);
1815 ui::MouseEvent
press(ui::ET_MOUSE_PRESSED
, click_location
, click_location
,
1816 ui::EF_LEFT_MOUSE_BUTTON
);
1817 widget
->OnMouseEvent(&press
);
1818 EXPECT_EQ(view
, GetMousePressedHandler(root_view
));
1820 EXPECT_EQ(NULL
, GetMousePressedHandler(root_view
));
1822 // Check RootView::mouse_move_handler_.
1824 EXPECT_EQ(NULL
, GetMouseMoveHandler(root_view
));
1825 gfx::Point
move_location(45, 15);
1826 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
, move_location
, move_location
, 0);
1827 widget
->OnMouseEvent(&move
);
1828 EXPECT_EQ(view
, GetMouseMoveHandler(root_view
));
1830 EXPECT_EQ(NULL
, GetMouseMoveHandler(root_view
));
1832 // Check RootView::gesture_handler_.
1834 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
1835 ui::GestureEvent
tap_down(
1836 ui::ET_GESTURE_TAP_DOWN
,
1841 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN
, 0, 0),
1843 widget
->OnGestureEvent(&tap_down
);
1844 EXPECT_EQ(view
, GetGestureHandler(root_view
));
1846 EXPECT_EQ(NULL
, GetGestureHandler(root_view
));
1851 // Test the result of Widget::GetAllChildWidgets().
1852 TEST_F(WidgetTest
, GetAllChildWidgets
) {
1853 // Create the following widget hierarchy:
1861 Widget
* toplevel
= CreateTopLevelPlatformWidget();
1862 Widget
* w1
= CreateChildPlatformWidget(toplevel
->GetNativeView());
1863 Widget
* w11
= CreateChildPlatformWidget(w1
->GetNativeView());
1864 Widget
* w2
= CreateChildPlatformWidget(toplevel
->GetNativeView());
1865 Widget
* w21
= CreateChildPlatformWidget(w2
->GetNativeView());
1866 Widget
* w22
= CreateChildPlatformWidget(w2
->GetNativeView());
1868 std::set
<Widget
*> expected
;
1869 expected
.insert(toplevel
);
1870 expected
.insert(w1
);
1871 expected
.insert(w11
);
1872 expected
.insert(w2
);
1873 expected
.insert(w21
);
1874 expected
.insert(w22
);
1876 std::set
<Widget
*> widgets
;
1877 Widget::GetAllChildWidgets(toplevel
->GetNativeView(), &widgets
);
1879 EXPECT_EQ(expected
.size(), widgets
.size());
1880 EXPECT_TRUE(std::equal(expected
.begin(), expected
.end(), widgets
.begin()));
1883 // Used by DestroyChildWidgetsInOrder. On destruction adds the supplied name to
1885 class DestroyedTrackingView
: public View
{
1887 DestroyedTrackingView(const std::string
& name
,
1888 std::vector
<std::string
>* add_to
)
1893 virtual ~DestroyedTrackingView() {
1894 add_to_
->push_back(name_
);
1898 const std::string name_
;
1899 std::vector
<std::string
>* add_to_
;
1901 DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingView
);
1904 class WidgetChildDestructionTest
: public WidgetTest
{
1906 WidgetChildDestructionTest() {}
1908 // Creates a top level and a child, destroys the child and verifies the views
1909 // of the child are destroyed before the views of the parent.
1910 void RunDestroyChildWidgetsTest(bool top_level_has_desktop_native_widget_aura
,
1911 bool child_has_desktop_native_widget_aura
) {
1912 // When a View is destroyed its name is added here.
1913 std::vector
<std::string
> destroyed
;
1915 Widget
* top_level
= new Widget
;
1916 Widget::InitParams params
=
1917 CreateParams(views::Widget::InitParams::TYPE_WINDOW
);
1918 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1919 if (top_level_has_desktop_native_widget_aura
)
1920 params
.native_widget
= new DesktopNativeWidgetAura(top_level
);
1922 top_level
->Init(params
);
1923 top_level
->GetRootView()->AddChildView(
1924 new DestroyedTrackingView("parent", &destroyed
));
1927 Widget
* child
= new Widget
;
1928 Widget::InitParams child_params
=
1929 CreateParams(views::Widget::InitParams::TYPE_POPUP
);
1930 child_params
.parent
= top_level
->GetNativeView();
1931 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1932 if (child_has_desktop_native_widget_aura
)
1933 child_params
.native_widget
= new DesktopNativeWidgetAura(child
);
1935 child
->Init(child_params
);
1936 child
->GetRootView()->AddChildView(
1937 new DestroyedTrackingView("child", &destroyed
));
1940 // Should trigger destruction of the child too.
1941 top_level
->native_widget_private()->CloseNow();
1943 // Child should be destroyed first.
1944 ASSERT_EQ(2u, destroyed
.size());
1945 EXPECT_EQ("child", destroyed
[0]);
1946 EXPECT_EQ("parent", destroyed
[1]);
1950 DISALLOW_COPY_AND_ASSIGN(WidgetChildDestructionTest
);
1953 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1954 // See description of RunDestroyChildWidgetsTest(). Parent uses
1955 // DesktopNativeWidgetAura.
1956 TEST_F(WidgetChildDestructionTest
,
1957 DestroyChildWidgetsInOrderWithDesktopNativeWidget
) {
1958 RunDestroyChildWidgetsTest(true, false);
1961 // See description of RunDestroyChildWidgetsTest(). Both parent and child use
1962 // DesktopNativeWidgetAura.
1963 TEST_F(WidgetChildDestructionTest
,
1964 DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth
) {
1965 RunDestroyChildWidgetsTest(true, true);
1969 // See description of RunDestroyChildWidgetsTest().
1970 TEST_F(WidgetChildDestructionTest
, DestroyChildWidgetsInOrder
) {
1971 RunDestroyChildWidgetsTest(false, false);
1974 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1975 // Provides functionality to create a window modal dialog.
1976 class ModalDialogDelegate
: public DialogDelegateView
{
1978 ModalDialogDelegate() {}
1979 virtual ~ModalDialogDelegate() {}
1981 // WidgetDelegate overrides.
1982 virtual ui::ModalType
GetModalType() const OVERRIDE
{
1983 return ui::MODAL_TYPE_WINDOW
;
1987 DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate
);
1990 // This test verifies that whether mouse events when a modal dialog is
1991 // displayed are eaten or recieved by the dialog.
1992 TEST_F(WidgetTest
, WindowMouseModalityTest
) {
1993 // Create a top level widget.
1994 Widget top_level_widget
;
1995 Widget::InitParams init_params
=
1996 CreateParams(Widget::InitParams::TYPE_WINDOW
);
1997 init_params
.show_state
= ui::SHOW_STATE_NORMAL
;
1998 gfx::Rect
initial_bounds(0, 0, 500, 500);
1999 init_params
.bounds
= initial_bounds
;
2000 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
2001 init_params
.native_widget
= new DesktopNativeWidgetAura(&top_level_widget
);
2002 top_level_widget
.Init(init_params
);
2003 top_level_widget
.Show();
2004 EXPECT_TRUE(top_level_widget
.IsVisible());
2006 // Create a view and validate that a mouse moves makes it to the view.
2007 EventCountView
* widget_view
= new EventCountView();
2008 widget_view
->SetBounds(0, 0, 10, 10);
2009 top_level_widget
.GetRootView()->AddChildView(widget_view
);
2011 gfx::Point
cursor_location_main(5, 5);
2012 ui::MouseEvent
move_main(ui::ET_MOUSE_MOVED
,
2013 cursor_location_main
,
2014 cursor_location_main
,
2016 top_level_widget
.GetNativeView()->GetDispatcher()->
2017 AsRootWindowHostDelegate()->OnHostMouseEvent(&move_main
);
2019 EXPECT_EQ(1, widget_view
->GetEventCount(ui::ET_MOUSE_ENTERED
));
2020 widget_view
->ResetCounts();
2022 // Create a modal dialog and validate that a mouse down message makes it to
2023 // the main view within the dialog.
2025 // This instance will be destroyed when the dialog is destroyed.
2026 ModalDialogDelegate
* dialog_delegate
= new ModalDialogDelegate
;
2028 Widget
* modal_dialog_widget
= views::DialogDelegate::CreateDialogWidget(
2029 dialog_delegate
, NULL
, top_level_widget
.GetNativeWindow());
2030 modal_dialog_widget
->SetBounds(gfx::Rect(100, 100, 200, 200));
2031 EventCountView
* dialog_widget_view
= new EventCountView();
2032 dialog_widget_view
->SetBounds(0, 0, 50, 50);
2033 modal_dialog_widget
->GetRootView()->AddChildView(dialog_widget_view
);
2034 modal_dialog_widget
->Show();
2035 EXPECT_TRUE(modal_dialog_widget
->IsVisible());
2037 gfx::Point
cursor_location_dialog(100, 100);
2038 ui::MouseEvent
mouse_down_dialog(ui::ET_MOUSE_PRESSED
,
2039 cursor_location_dialog
,
2040 cursor_location_dialog
,
2042 top_level_widget
.GetNativeView()->GetDispatcher()->
2043 AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse_down_dialog
);
2044 EXPECT_EQ(1, dialog_widget_view
->GetEventCount(ui::ET_MOUSE_PRESSED
));
2046 // Send a mouse move message to the main window. It should not be received by
2047 // the main window as the modal dialog is still active.
2048 gfx::Point
cursor_location_main2(6, 6);
2049 ui::MouseEvent
mouse_down_main(ui::ET_MOUSE_MOVED
,
2050 cursor_location_main2
,
2051 cursor_location_main2
,
2053 top_level_widget
.GetNativeView()->GetDispatcher()->
2054 AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse_down_main
);
2055 EXPECT_EQ(0, widget_view
->GetEventCount(ui::ET_MOUSE_MOVED
));
2057 modal_dialog_widget
->CloseNow();
2058 top_level_widget
.CloseNow();
2063 // Provides functionality to test widget activation via an activation flag
2064 // which can be set by an accessor.
2065 class ModalWindowTestWidgetDelegate
: public WidgetDelegate
{
2067 ModalWindowTestWidgetDelegate()
2069 can_activate_(true) {}
2071 virtual ~ModalWindowTestWidgetDelegate() {}
2073 // Overridden from WidgetDelegate:
2074 virtual void DeleteDelegate() OVERRIDE
{
2077 virtual Widget
* GetWidget() OVERRIDE
{
2080 virtual const Widget
* GetWidget() const OVERRIDE
{
2083 virtual bool CanActivate() const OVERRIDE
{
2084 return can_activate_
;
2086 virtual bool ShouldAdvanceFocusToTopLevelWidget() const OVERRIDE
{
2090 void set_can_activate(bool can_activate
) {
2091 can_activate_
= can_activate
;
2094 void set_widget(Widget
* widget
) {
2102 DISALLOW_COPY_AND_ASSIGN(ModalWindowTestWidgetDelegate
);
2105 // Tests whether we can activate the top level widget when a modal dialog is
2107 TEST_F(WidgetTest
, WindowModalityActivationTest
) {
2108 // Destroyed when the top level widget created below is destroyed.
2109 ModalWindowTestWidgetDelegate
* widget_delegate
=
2110 new ModalWindowTestWidgetDelegate
;
2111 // Create a top level widget.
2112 Widget top_level_widget
;
2113 Widget::InitParams init_params
=
2114 CreateParams(Widget::InitParams::TYPE_WINDOW
);
2115 init_params
.show_state
= ui::SHOW_STATE_NORMAL
;
2116 gfx::Rect
initial_bounds(0, 0, 500, 500);
2117 init_params
.bounds
= initial_bounds
;
2118 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
2119 init_params
.native_widget
= new DesktopNativeWidgetAura(&top_level_widget
);
2120 init_params
.delegate
= widget_delegate
;
2121 top_level_widget
.Init(init_params
);
2122 widget_delegate
->set_widget(&top_level_widget
);
2123 top_level_widget
.Show();
2124 EXPECT_TRUE(top_level_widget
.IsVisible());
2126 HWND win32_window
= views::HWNDForWidget(&top_level_widget
);
2127 EXPECT_TRUE(::IsWindow(win32_window
));
2129 // This instance will be destroyed when the dialog is destroyed.
2130 ModalDialogDelegate
* dialog_delegate
= new ModalDialogDelegate
;
2132 // We should be able to activate the window even if the WidgetDelegate
2133 // says no, when a modal dialog is active.
2134 widget_delegate
->set_can_activate(false);
2136 Widget
* modal_dialog_widget
= views::DialogDelegate::CreateDialogWidget(
2137 dialog_delegate
, NULL
, top_level_widget
.GetNativeWindow());
2138 modal_dialog_widget
->SetBounds(gfx::Rect(100, 100, 200, 200));
2139 modal_dialog_widget
->Show();
2140 EXPECT_TRUE(modal_dialog_widget
->IsVisible());
2142 LRESULT activate_result
= ::SendMessage(
2145 reinterpret_cast<WPARAM
>(win32_window
),
2146 MAKELPARAM(WM_LBUTTONDOWN
, HTCLIENT
));
2147 EXPECT_EQ(activate_result
, MA_ACTIVATE
);
2149 modal_dialog_widget
->CloseNow();
2150 top_level_widget
.CloseNow();
2156 } // namespace views