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/events/event_utils.h"
17 #include "ui/gfx/native_widget_types.h"
18 #include "ui/gfx/point.h"
19 #include "ui/views/bubble/bubble_delegate.h"
20 #include "ui/views/controls/textfield/textfield.h"
21 #include "ui/views/test/test_views_delegate.h"
22 #include "ui/views/test/widget_test.h"
23 #include "ui/views/views_delegate.h"
24 #include "ui/views/widget/native_widget_delegate.h"
25 #include "ui/views/widget/root_view.h"
26 #include "ui/views/window/dialog_delegate.h"
27 #include "ui/views/window/native_frame_view.h"
30 #include "ui/aura/client/aura_constants.h"
31 #include "ui/aura/client/window_tree_client.h"
32 #include "ui/aura/root_window.h"
33 #include "ui/aura/test/test_window_delegate.h"
34 #include "ui/aura/window.h"
35 #include "ui/views/widget/native_widget_aura.h"
36 #if !defined(OS_CHROMEOS)
37 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
40 #include "ui/views/widget/native_widget_win.h"
44 #include "ui/views/win/hwnd_util.h"
50 // A view that keeps track of the events it receives, but consumes no events.
51 class EventCountView : public View {
54 virtual ~EventCountView() {}
56 int GetEventCount(ui::EventType type) {
57 return event_count_[type];
65 // Overridden from ui::EventHandler:
66 virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
69 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
72 virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE {
75 virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE {
78 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
83 void RecordEvent(const ui::Event& event) {
84 ++event_count_[event.type()];
87 std::map<ui::EventType, int> event_count_;
89 DISALLOW_COPY_AND_ASSIGN(EventCountView);
92 // A view that keeps track of the events it receives, and consumes all scroll
94 class ScrollableEventCountView : public EventCountView {
96 ScrollableEventCountView() {}
97 virtual ~ScrollableEventCountView() {}
100 // Overridden from ui::EventHandler:
101 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
102 EventCountView::OnGestureEvent(event);
103 switch (event->type()) {
104 case ui::ET_GESTURE_SCROLL_BEGIN:
105 case ui::ET_GESTURE_SCROLL_UPDATE:
106 case ui::ET_GESTURE_SCROLL_END:
107 case ui::ET_SCROLL_FLING_START:
115 DISALLOW_COPY_AND_ASSIGN(ScrollableEventCountView);
118 // A view that implements GetMinimumSize.
119 class MinimumSizeFrameView : public NativeFrameView {
121 explicit MinimumSizeFrameView(Widget* frame): NativeFrameView(frame) {}
122 virtual ~MinimumSizeFrameView() {}
125 // Overridden from View:
126 virtual gfx::Size GetMinimumSize() OVERRIDE {
127 return gfx::Size(300, 400);
130 DISALLOW_COPY_AND_ASSIGN(MinimumSizeFrameView);
133 // An event handler that simply keeps a count of the different types of events
135 class EventCountHandler : public ui::EventHandler {
137 EventCountHandler() {}
138 virtual ~EventCountHandler() {}
140 int GetEventCount(ui::EventType type) {
141 return event_count_[type];
145 event_count_.clear();
149 // Overridden from ui::EventHandler:
150 virtual void OnEvent(ui::Event* event) OVERRIDE {
152 ui::EventHandler::OnEvent(event);
156 void RecordEvent(const ui::Event& event) {
157 ++event_count_[event.type()];
160 std::map<ui::EventType, int> event_count_;
162 DISALLOW_COPY_AND_ASSIGN(EventCountHandler);
165 ui::WindowShowState GetWidgetShowState(const Widget* widget) {
166 // Use IsMaximized/IsMinimized/IsFullScreen instead of GetWindowPlacement
167 // because the former is implemented on all platforms but the latter is not.
168 return widget->IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN :
169 widget->IsMaximized() ? ui::SHOW_STATE_MAXIMIZED :
170 widget->IsMinimized() ? ui::SHOW_STATE_MINIMIZED :
171 widget->IsActive() ? ui::SHOW_STATE_NORMAL :
172 ui::SHOW_STATE_INACTIVE;
175 TEST_F(WidgetTest, WidgetInitParams) {
176 // Widgets are not transparent by default.
177 Widget::InitParams init1;
178 EXPECT_EQ(Widget::InitParams::INFER_OPACITY, init1.opacity);
181 ////////////////////////////////////////////////////////////////////////////////
182 // Widget::GetTopLevelWidget tests.
184 TEST_F(WidgetTest, GetTopLevelWidget_Native) {
185 // Create a hierarchy of native widgets.
186 Widget* toplevel = CreateTopLevelPlatformWidget();
187 gfx::NativeView parent = toplevel->GetNativeView();
188 Widget* child = CreateChildPlatformWidget(parent);
190 EXPECT_EQ(toplevel, toplevel->GetTopLevelWidget());
191 EXPECT_EQ(toplevel, child->GetTopLevelWidget());
193 toplevel->CloseNow();
194 // |child| should be automatically destroyed with |toplevel|.
197 // Test if a focus manager and an inputmethod work without CHECK failure
198 // when window activation changes.
199 TEST_F(WidgetTest, ChangeActivation) {
200 Widget* top1 = CreateTopLevelPlatformWidget();
201 // CreateInputMethod before activated
202 top1->GetInputMethod();
204 RunPendingMessages();
206 Widget* top2 = CreateTopLevelPlatformWidget();
208 RunPendingMessages();
211 RunPendingMessages();
213 // Create InputMethod after deactivated.
214 top2->GetInputMethod();
216 RunPendingMessages();
219 RunPendingMessages();
225 // Tests visibility of child widgets.
226 TEST_F(WidgetTest, Visibility) {
227 Widget* toplevel = CreateTopLevelPlatformWidget();
228 gfx::NativeView parent = toplevel->GetNativeView();
229 Widget* child = CreateChildPlatformWidget(parent);
231 EXPECT_FALSE(toplevel->IsVisible());
232 EXPECT_FALSE(child->IsVisible());
236 EXPECT_FALSE(toplevel->IsVisible());
237 EXPECT_FALSE(child->IsVisible());
241 EXPECT_TRUE(toplevel->IsVisible());
242 EXPECT_TRUE(child->IsVisible());
244 toplevel->CloseNow();
245 // |child| should be automatically destroyed with |toplevel|.
248 ////////////////////////////////////////////////////////////////////////////////
249 // Widget ownership tests.
251 // Tests various permutations of Widget ownership specified in the
252 // InitParams::Ownership param.
254 // A WidgetTest that supplies a toplevel widget for NativeWidget to parent to.
255 class WidgetOwnershipTest : public WidgetTest {
257 WidgetOwnershipTest() {}
258 virtual ~WidgetOwnershipTest() {}
260 virtual void SetUp() {
262 desktop_widget_ = CreateTopLevelPlatformWidget();
265 virtual void TearDown() {
266 desktop_widget_->CloseNow();
267 WidgetTest::TearDown();
271 Widget* desktop_widget_;
273 DISALLOW_COPY_AND_ASSIGN(WidgetOwnershipTest);
276 // A bag of state to monitor destructions.
277 struct OwnershipTestState {
278 OwnershipTestState() : widget_deleted(false), native_widget_deleted(false) {}
281 bool native_widget_deleted;
284 // A platform NativeWidget subclass that updates a bag of state when it is
286 class OwnershipTestNativeWidget : public NativeWidgetPlatform {
288 OwnershipTestNativeWidget(internal::NativeWidgetDelegate* delegate,
289 OwnershipTestState* state)
290 : NativeWidgetPlatform(delegate),
293 virtual ~OwnershipTestNativeWidget() {
294 state_->native_widget_deleted = true;
298 OwnershipTestState* state_;
300 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidget);
303 // A views NativeWidget subclass that updates a bag of state when it is
305 class OwnershipTestNativeWidgetPlatform : public NativeWidgetPlatformForTest {
307 OwnershipTestNativeWidgetPlatform(internal::NativeWidgetDelegate* delegate,
308 OwnershipTestState* state)
309 : NativeWidgetPlatformForTest(delegate),
312 virtual ~OwnershipTestNativeWidgetPlatform() {
313 state_->native_widget_deleted = true;
317 OwnershipTestState* state_;
319 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetPlatform);
322 // A Widget subclass that updates a bag of state when it is destroyed.
323 class OwnershipTestWidget : public Widget {
325 explicit OwnershipTestWidget(OwnershipTestState* state) : state_(state) {}
326 virtual ~OwnershipTestWidget() {
327 state_->widget_deleted = true;
331 OwnershipTestState* state_;
333 DISALLOW_COPY_AND_ASSIGN(OwnershipTestWidget);
336 // Widget owns its NativeWidget, part 1: NativeWidget is a platform-native
338 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsPlatformNativeWidget) {
339 OwnershipTestState state;
341 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
342 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
343 params.native_widget =
344 new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
345 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
346 widget->Init(params);
348 // Now delete the Widget, which should delete the NativeWidget.
351 EXPECT_TRUE(state.widget_deleted);
352 EXPECT_TRUE(state.native_widget_deleted);
354 // TODO(beng): write test for this ownership scenario and the NativeWidget
355 // being deleted out from under the Widget.
358 // Widget owns its NativeWidget, part 2: NativeWidget is a NativeWidget.
359 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsViewsNativeWidget) {
360 OwnershipTestState state;
362 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
363 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
364 params.native_widget =
365 new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
366 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
367 widget->Init(params);
369 // Now delete the Widget, which should delete the NativeWidget.
372 EXPECT_TRUE(state.widget_deleted);
373 EXPECT_TRUE(state.native_widget_deleted);
375 // TODO(beng): write test for this ownership scenario and the NativeWidget
376 // being deleted out from under the Widget.
379 // Widget owns its NativeWidget, part 3: NativeWidget is a NativeWidget,
380 // destroy the parent view.
381 TEST_F(WidgetOwnershipTest,
382 Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView) {
383 OwnershipTestState state;
385 Widget* toplevel = CreateTopLevelPlatformWidget();
387 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
388 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
389 params.native_widget =
390 new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
391 params.parent = toplevel->GetNativeView();
392 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
393 widget->Init(params);
395 // Now close the toplevel, which deletes the view hierarchy.
396 toplevel->CloseNow();
398 RunPendingMessages();
400 // This shouldn't delete the widget because it shouldn't be deleted
401 // from the native side.
402 EXPECT_FALSE(state.widget_deleted);
403 EXPECT_FALSE(state.native_widget_deleted);
405 // Now delete it explicitly.
408 EXPECT_TRUE(state.widget_deleted);
409 EXPECT_TRUE(state.native_widget_deleted);
412 // NativeWidget owns its Widget, part 1: NativeWidget is a platform-native
414 TEST_F(WidgetOwnershipTest, Ownership_PlatformNativeWidgetOwnsWidget) {
415 OwnershipTestState state;
417 Widget* widget = new OwnershipTestWidget(&state);
418 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
419 params.native_widget =
420 new OwnershipTestNativeWidgetPlatform(widget, &state);
421 widget->Init(params);
423 // Now destroy the native widget.
426 EXPECT_TRUE(state.widget_deleted);
427 EXPECT_TRUE(state.native_widget_deleted);
430 // NativeWidget owns its Widget, part 2: NativeWidget is a NativeWidget.
431 TEST_F(WidgetOwnershipTest, Ownership_ViewsNativeWidgetOwnsWidget) {
432 OwnershipTestState state;
434 Widget* toplevel = CreateTopLevelPlatformWidget();
436 Widget* widget = new OwnershipTestWidget(&state);
437 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
438 params.native_widget =
439 new OwnershipTestNativeWidgetPlatform(widget, &state);
440 params.parent = toplevel->GetNativeView();
441 widget->Init(params);
443 // Now destroy the native widget. This is achieved by closing the toplevel.
444 toplevel->CloseNow();
446 // The NativeWidget won't be deleted until after a return to the message loop
447 // so we have to run pending messages before testing the destruction status.
448 RunPendingMessages();
450 EXPECT_TRUE(state.widget_deleted);
451 EXPECT_TRUE(state.native_widget_deleted);
454 // NativeWidget owns its Widget, part 3: NativeWidget is a platform-native
455 // widget, destroyed out from under it by the OS.
456 TEST_F(WidgetOwnershipTest,
457 Ownership_PlatformNativeWidgetOwnsWidget_NativeDestroy) {
458 OwnershipTestState state;
460 Widget* widget = new OwnershipTestWidget(&state);
461 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
462 params.native_widget =
463 new OwnershipTestNativeWidgetPlatform(widget, &state);
464 widget->Init(params);
466 // Now simulate a destroy of the platform native widget from the OS:
467 #if defined(USE_AURA)
468 delete widget->GetNativeView();
469 #elif defined(OS_WIN)
470 DestroyWindow(widget->GetNativeView());
473 EXPECT_TRUE(state.widget_deleted);
474 EXPECT_TRUE(state.native_widget_deleted);
477 // NativeWidget owns its Widget, part 4: NativeWidget is a NativeWidget,
478 // destroyed by the view hierarchy that contains it.
479 TEST_F(WidgetOwnershipTest,
480 Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy) {
481 OwnershipTestState state;
483 Widget* toplevel = CreateTopLevelPlatformWidget();
485 Widget* widget = new OwnershipTestWidget(&state);
486 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
487 params.native_widget =
488 new OwnershipTestNativeWidgetPlatform(widget, &state);
489 params.parent = toplevel->GetNativeView();
490 widget->Init(params);
492 // Destroy the widget (achieved by closing the toplevel).
493 toplevel->CloseNow();
495 // The NativeWidget won't be deleted until after a return to the message loop
496 // so we have to run pending messages before testing the destruction status.
497 RunPendingMessages();
499 EXPECT_TRUE(state.widget_deleted);
500 EXPECT_TRUE(state.native_widget_deleted);
503 // NativeWidget owns its Widget, part 5: NativeWidget is a NativeWidget,
504 // we close it directly.
505 TEST_F(WidgetOwnershipTest,
506 Ownership_ViewsNativeWidgetOwnsWidget_Close) {
507 OwnershipTestState state;
509 Widget* toplevel = CreateTopLevelPlatformWidget();
511 Widget* widget = new OwnershipTestWidget(&state);
512 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
513 params.native_widget =
514 new OwnershipTestNativeWidgetPlatform(widget, &state);
515 params.parent = toplevel->GetNativeView();
516 widget->Init(params);
518 // Destroy the widget.
520 toplevel->CloseNow();
522 // The NativeWidget won't be deleted until after a return to the message loop
523 // so we have to run pending messages before testing the destruction status.
524 RunPendingMessages();
526 EXPECT_TRUE(state.widget_deleted);
527 EXPECT_TRUE(state.native_widget_deleted);
530 // Widget owns its NativeWidget and has a WidgetDelegateView as its contents.
531 TEST_F(WidgetOwnershipTest,
532 Ownership_WidgetOwnsNativeWidgetWithWithWidgetDelegateView) {
533 OwnershipTestState state;
535 WidgetDelegateView* delegate_view = new WidgetDelegateView;
537 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
538 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
539 params.native_widget =
540 new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
541 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
542 params.delegate = delegate_view;
543 widget->Init(params);
544 widget->SetContentsView(delegate_view);
546 // Now delete the Widget. There should be no crash or use-after-free.
549 EXPECT_TRUE(state.widget_deleted);
550 EXPECT_TRUE(state.native_widget_deleted);
553 ////////////////////////////////////////////////////////////////////////////////
554 // Test to verify using various Widget methods doesn't crash when the underlying
555 // NativeView is destroyed.
557 class WidgetWithDestroyedNativeViewTest : public ViewsTestBase {
559 WidgetWithDestroyedNativeViewTest() {}
560 virtual ~WidgetWithDestroyedNativeViewTest() {}
562 void InvokeWidgetMethods(Widget* widget) {
563 widget->GetNativeView();
564 widget->GetNativeWindow();
565 ui::Accelerator accelerator;
566 widget->GetAccelerator(0, &accelerator);
567 widget->GetTopLevelWidget();
568 widget->GetWindowBoundsInScreen();
569 widget->GetClientAreaBoundsInScreen();
570 widget->SetBounds(gfx::Rect(0, 0, 100, 80));
571 widget->SetSize(gfx::Size(10, 11));
572 widget->SetBoundsConstrained(gfx::Rect(0, 0, 120, 140));
573 widget->SetVisibilityChangedAnimationsEnabled(false);
574 widget->StackAtTop();
579 widget->Deactivate();
581 widget->DisableInactiveRendering();
582 widget->SetAlwaysOnTop(true);
583 widget->IsAlwaysOnTop();
587 widget->IsMaximized();
588 widget->IsFullscreen();
589 widget->SetOpacity(0);
590 widget->SetUseDragFrame(true);
591 widget->FlashFrame(true);
593 widget->GetThemeProvider();
594 widget->GetNativeTheme();
595 widget->GetFocusManager();
596 widget->GetInputMethod();
597 widget->SchedulePaintInRect(gfx::Rect(0, 0, 1, 2));
598 widget->IsMouseEventsEnabled();
599 widget->SetNativeWindowProperty("xx", widget);
600 widget->GetNativeWindowProperty("xx");
601 widget->GetFocusTraversable();
603 widget->ReorderNativeViews();
604 widget->SetCapture(widget->GetRootView());
605 widget->ReleaseCapture();
606 widget->HasCapture();
607 widget->GetWorkAreaBoundsInScreen();
608 // These three crash with NativeWidgetWin, so I'm assuming we don't need
609 // them to work for the other NativeWidget impls.
610 // widget->CenterWindow(gfx::Size(50, 60));
611 // widget->GetRestoredBounds();
612 // widget->ShowInactive();
617 DISALLOW_COPY_AND_ASSIGN(WidgetWithDestroyedNativeViewTest);
620 TEST_F(WidgetWithDestroyedNativeViewTest, Test) {
623 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
624 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
628 widget.native_widget_private()->CloseNow();
629 InvokeWidgetMethods(&widget);
631 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
634 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
635 params.native_widget = new DesktopNativeWidgetAura(&widget);
636 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
640 widget.native_widget_private()->CloseNow();
641 InvokeWidgetMethods(&widget);
646 ////////////////////////////////////////////////////////////////////////////////
647 // Widget observer tests.
650 class WidgetObserverTest : public WidgetTest, public WidgetObserver {
654 widget_closed_(NULL),
655 widget_activated_(NULL),
657 widget_hidden_(NULL),
658 widget_bounds_changed_(NULL) {
661 virtual ~WidgetObserverTest() {}
663 // Overridden from WidgetObserver:
664 virtual void OnWidgetDestroying(Widget* widget) OVERRIDE {
665 if (active_ == widget)
667 widget_closed_ = widget;
670 virtual void OnWidgetActivationChanged(Widget* widget,
671 bool active) OVERRIDE {
673 if (widget_activated_)
674 widget_activated_->Deactivate();
675 widget_activated_ = widget;
678 if (widget_activated_ == widget)
679 widget_activated_ = NULL;
680 widget_deactivated_ = widget;
684 virtual void OnWidgetVisibilityChanged(Widget* widget,
685 bool visible) OVERRIDE {
687 widget_shown_ = widget;
689 widget_hidden_ = widget;
692 virtual void OnWidgetBoundsChanged(Widget* widget,
693 const gfx::Rect& new_bounds) OVERRIDE {
694 widget_bounds_changed_ = widget;
699 widget_closed_ = NULL;
700 widget_activated_ = NULL;
701 widget_deactivated_ = NULL;
702 widget_shown_ = NULL;
703 widget_hidden_ = NULL;
704 widget_bounds_changed_ = NULL;
707 Widget* NewWidget() {
708 Widget* widget = CreateTopLevelNativeWidget();
709 widget->AddObserver(this);
713 const Widget* active() const { return active_; }
714 const Widget* widget_closed() const { return widget_closed_; }
715 const Widget* widget_activated() const { return widget_activated_; }
716 const Widget* widget_deactivated() const { return widget_deactivated_; }
717 const Widget* widget_shown() const { return widget_shown_; }
718 const Widget* widget_hidden() const { return widget_hidden_; }
719 const Widget* widget_bounds_changed() const { return widget_bounds_changed_; }
724 Widget* widget_closed_;
725 Widget* widget_activated_;
726 Widget* widget_deactivated_;
727 Widget* widget_shown_;
728 Widget* widget_hidden_;
729 Widget* widget_bounds_changed_;
732 TEST_F(WidgetObserverTest, DISABLED_ActivationChange) {
733 Widget* toplevel = CreateTopLevelPlatformWidget();
735 Widget* toplevel1 = NewWidget();
736 Widget* toplevel2 = NewWidget();
743 toplevel1->Activate();
745 RunPendingMessages();
746 EXPECT_EQ(toplevel1, widget_activated());
748 toplevel2->Activate();
749 RunPendingMessages();
750 EXPECT_EQ(toplevel1, widget_deactivated());
751 EXPECT_EQ(toplevel2, widget_activated());
752 EXPECT_EQ(toplevel2, active());
754 toplevel->CloseNow();
757 TEST_F(WidgetObserverTest, DISABLED_VisibilityChange) {
758 Widget* toplevel = CreateTopLevelPlatformWidget();
760 Widget* child1 = NewWidget();
761 Widget* child2 = NewWidget();
770 EXPECT_EQ(child1, widget_hidden());
773 EXPECT_EQ(child2, widget_hidden());
776 EXPECT_EQ(child1, widget_shown());
779 EXPECT_EQ(child2, widget_shown());
781 toplevel->CloseNow();
784 TEST_F(WidgetObserverTest, DestroyBubble) {
785 Widget* anchor = CreateTopLevelPlatformWidget();
788 BubbleDelegateView* bubble_delegate =
789 new BubbleDelegateView(anchor->client_view(), BubbleBorder::NONE);
790 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
791 bubble_widget->Show();
792 bubble_widget->CloseNow();
798 TEST_F(WidgetObserverTest, WidgetBoundsChanged) {
799 Widget* child1 = NewWidget();
800 Widget* child2 = NewWidget();
802 child1->OnNativeWidgetMove();
803 EXPECT_EQ(child1, widget_bounds_changed());
805 child2->OnNativeWidgetMove();
806 EXPECT_EQ(child2, widget_bounds_changed());
808 child1->OnNativeWidgetSizeChanged(gfx::Size());
809 EXPECT_EQ(child1, widget_bounds_changed());
811 child2->OnNativeWidgetSizeChanged(gfx::Size());
812 EXPECT_EQ(child2, widget_bounds_changed());
815 #if !defined(USE_AURA) && defined(OS_WIN)
816 // Aura needs shell to maximize/fullscreen window.
817 // NativeWidgetGtk doesn't implement GetRestoredBounds.
818 TEST_F(WidgetTest, GetRestoredBounds) {
819 Widget* toplevel = CreateTopLevelPlatformWidget();
820 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
821 toplevel->GetRestoredBounds().ToString());
823 toplevel->Maximize();
824 RunPendingMessages();
825 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
826 toplevel->GetRestoredBounds().ToString());
827 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
828 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
831 RunPendingMessages();
832 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
833 toplevel->GetRestoredBounds().ToString());
835 toplevel->SetFullscreen(true);
836 RunPendingMessages();
837 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
838 toplevel->GetRestoredBounds().ToString());
839 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
840 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
844 // Test that window state is not changed after getting out of full screen.
845 TEST_F(WidgetTest, ExitFullscreenRestoreState) {
846 Widget* toplevel = CreateTopLevelPlatformWidget();
849 RunPendingMessages();
851 // This should be a normal state window.
852 EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
854 toplevel->SetFullscreen(true);
855 while (GetWidgetShowState(toplevel) != ui::SHOW_STATE_FULLSCREEN)
856 RunPendingMessages();
857 toplevel->SetFullscreen(false);
858 while (GetWidgetShowState(toplevel) == ui::SHOW_STATE_FULLSCREEN)
859 RunPendingMessages();
861 // And it should still be in normal state after getting out of full screen.
862 EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
864 // Now, make it maximized.
865 toplevel->Maximize();
866 while (GetWidgetShowState(toplevel) != ui::SHOW_STATE_MAXIMIZED)
867 RunPendingMessages();
869 toplevel->SetFullscreen(true);
870 while (GetWidgetShowState(toplevel) != ui::SHOW_STATE_FULLSCREEN)
871 RunPendingMessages();
872 toplevel->SetFullscreen(false);
873 while (GetWidgetShowState(toplevel) == ui::SHOW_STATE_FULLSCREEN)
874 RunPendingMessages();
876 // And it stays maximized after getting out of full screen.
877 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
881 RunPendingMessages();
884 #if defined(USE_AURA)
885 // The key-event propagation from Widget happens differently on aura and
886 // non-aura systems because of the difference in IME. So this test works only on
888 TEST_F(WidgetTest, KeyboardInputEvent) {
889 Widget* toplevel = CreateTopLevelPlatformWidget();
890 View* container = toplevel->client_view();
892 Textfield* textfield = new Textfield();
893 textfield->SetText(base::ASCIIToUTF16("some text"));
894 container->AddChildView(textfield);
896 textfield->RequestFocus();
898 // The press gets handled. The release doesn't have an effect.
899 ui::KeyEvent backspace_p(ui::ET_KEY_PRESSED, ui::VKEY_DELETE, 0, false);
900 toplevel->OnKeyEvent(&backspace_p);
901 EXPECT_TRUE(backspace_p.stopped_propagation());
902 ui::KeyEvent backspace_r(ui::ET_KEY_RELEASED, ui::VKEY_DELETE, 0, false);
903 toplevel->OnKeyEvent(&backspace_r);
904 EXPECT_FALSE(backspace_r.handled());
909 // Verifies bubbles result in a focus lost when shown.
910 // TODO(msw): this tests relies on focus, it needs to be in
911 // interactive_ui_tests.
912 TEST_F(WidgetTest, DISABLED_FocusChangesOnBubble) {
913 // Create a widget, show and activate it and focus the contents view.
914 View* contents_view = new View;
915 contents_view->SetFocusable(true);
917 Widget::InitParams init_params =
918 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
919 init_params.bounds = gfx::Rect(0, 0, 200, 200);
920 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
921 #if !defined(OS_CHROMEOS)
922 init_params.native_widget = new DesktopNativeWidgetAura(&widget);
924 widget.Init(init_params);
925 widget.SetContentsView(contents_view);
928 contents_view->RequestFocus();
929 EXPECT_TRUE(contents_view->HasFocus());
932 BubbleDelegateView* bubble_delegate_view =
933 new BubbleDelegateView(contents_view, BubbleBorder::TOP_LEFT);
934 bubble_delegate_view->SetFocusable(true);
935 BubbleDelegateView::CreateBubble(bubble_delegate_view)->Show();
936 bubble_delegate_view->RequestFocus();
938 // |contents_view_| should no longer have focus.
939 EXPECT_FALSE(contents_view->HasFocus());
940 EXPECT_TRUE(bubble_delegate_view->HasFocus());
942 bubble_delegate_view->GetWidget()->CloseNow();
944 // Closing the bubble should result in focus going back to the contents view.
945 EXPECT_TRUE(contents_view->HasFocus());
948 class TestBubbleDelegateView : public BubbleDelegateView {
950 TestBubbleDelegateView(View* anchor)
951 : BubbleDelegateView(anchor, BubbleBorder::NONE),
952 reset_controls_called_(false) {}
953 virtual ~TestBubbleDelegateView() {}
955 virtual bool ShouldShowCloseButton() const OVERRIDE {
956 reset_controls_called_ = true;
960 mutable bool reset_controls_called_;
963 TEST_F(WidgetTest, BubbleControlsResetOnInit) {
964 Widget* anchor = CreateTopLevelPlatformWidget();
967 TestBubbleDelegateView* bubble_delegate =
968 new TestBubbleDelegateView(anchor->client_view());
969 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
970 EXPECT_TRUE(bubble_delegate->reset_controls_called_);
971 bubble_widget->Show();
972 bubble_widget->CloseNow();
978 // Desktop native widget Aura tests are for non Chrome OS platforms.
979 #if !defined(OS_CHROMEOS)
980 // Test to ensure that after minimize, view width is set to zero.
981 TEST_F(WidgetTest, TestViewWidthAfterMinimizingWidget) {
984 Widget::InitParams init_params =
985 CreateParams(Widget::InitParams::TYPE_WINDOW);
986 init_params.show_state = ui::SHOW_STATE_NORMAL;
987 gfx::Rect initial_bounds(0, 0, 300, 400);
988 init_params.bounds = initial_bounds;
989 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
990 init_params.native_widget = new DesktopNativeWidgetAura(&widget);
991 widget.Init(init_params);
992 NonClientView* non_client_view = widget.non_client_view();
993 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
994 non_client_view->SetFrameView(frame_view);
997 EXPECT_EQ(0, frame_view->width());
1000 // This class validates whether paints are received for a visible Widget.
1001 // To achieve this it overrides the Show and Close methods on the Widget class
1002 // and sets state whether subsequent paints are expected.
1003 class DesktopAuraTestValidPaintWidget : public views::Widget {
1005 DesktopAuraTestValidPaintWidget()
1006 : expect_paint_(true),
1007 received_paint_while_hidden_(false) {
1010 virtual ~DesktopAuraTestValidPaintWidget() {
1013 virtual void Show() OVERRIDE {
1014 expect_paint_ = true;
1015 views::Widget::Show();
1018 virtual void Close() OVERRIDE {
1019 expect_paint_ = false;
1020 views::Widget::Close();
1024 expect_paint_ = false;
1025 views::Widget::Hide();
1028 virtual void OnNativeWidgetPaint(gfx::Canvas* canvas) OVERRIDE {
1029 EXPECT_TRUE(expect_paint_);
1031 received_paint_while_hidden_ = true;
1032 views::Widget::OnNativeWidgetPaint(canvas);
1035 bool received_paint_while_hidden() const {
1036 return received_paint_while_hidden_;
1041 bool received_paint_while_hidden_;
1044 TEST_F(WidgetTest, DesktopNativeWidgetAuraNoPaintAfterCloseTest) {
1045 View* contents_view = new View;
1046 contents_view->SetFocusable(true);
1047 DesktopAuraTestValidPaintWidget widget;
1048 Widget::InitParams init_params =
1049 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1050 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1051 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1052 init_params.native_widget = new DesktopNativeWidgetAura(&widget);
1053 widget.Init(init_params);
1054 widget.SetContentsView(contents_view);
1057 RunPendingMessages();
1058 widget.SchedulePaintInRect(init_params.bounds);
1060 RunPendingMessages();
1061 EXPECT_FALSE(widget.received_paint_while_hidden());
1064 TEST_F(WidgetTest, DesktopNativeWidgetAuraNoPaintAfterHideTest) {
1065 View* contents_view = new View;
1066 contents_view->SetFocusable(true);
1067 DesktopAuraTestValidPaintWidget widget;
1068 Widget::InitParams init_params =
1069 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1070 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1071 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1072 init_params.native_widget = new DesktopNativeWidgetAura(&widget);
1073 widget.Init(init_params);
1074 widget.SetContentsView(contents_view);
1077 RunPendingMessages();
1078 widget.SchedulePaintInRect(init_params.bounds);
1080 RunPendingMessages();
1081 EXPECT_FALSE(widget.received_paint_while_hidden());
1085 // This class provides functionality to create fullscreen and top level popup
1086 // windows. It additionally tests whether the destruction of these windows
1087 // occurs correctly in desktop AURA without crashing.
1088 // It provides facilities to test the following cases:-
1089 // 1. Child window destroyed which should lead to the destruction of the
1091 // 2. Parent window destroyed which should lead to the child being destroyed.
1092 class DesktopAuraTopLevelWindowTest
1093 : public views::TestViewsDelegate,
1094 public aura::WindowObserver {
1096 DesktopAuraTopLevelWindowTest()
1097 : top_level_widget_(NULL),
1098 owned_window_(NULL),
1099 owner_destroyed_(false),
1100 owned_window_destroyed_(false) {}
1102 virtual ~DesktopAuraTopLevelWindowTest() {
1103 EXPECT_TRUE(owner_destroyed_);
1104 EXPECT_TRUE(owned_window_destroyed_);
1105 top_level_widget_ = NULL;
1106 owned_window_ = NULL;
1109 // views::TestViewsDelegate overrides.
1110 virtual void OnBeforeWidgetInit(
1111 Widget::InitParams* params,
1112 internal::NativeWidgetDelegate* delegate) OVERRIDE {
1113 if (!params->native_widget)
1114 params->native_widget = new views::DesktopNativeWidgetAura(delegate);
1117 void CreateTopLevelWindow(const gfx::Rect& bounds, bool fullscreen) {
1118 Widget::InitParams init_params;
1119 init_params.type = Widget::InitParams::TYPE_WINDOW;
1120 init_params.bounds = bounds;
1121 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1122 init_params.layer_type = aura::WINDOW_LAYER_NOT_DRAWN;
1123 init_params.accept_events = fullscreen;
1125 widget_.Init(init_params);
1127 owned_window_ = new aura::Window(&child_window_delegate_);
1128 owned_window_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
1129 owned_window_->SetName("TestTopLevelWindow");
1131 owned_window_->SetProperty(aura::client::kShowStateKey,
1132 ui::SHOW_STATE_FULLSCREEN);
1134 owned_window_->SetType(ui::wm::WINDOW_TYPE_MENU);
1136 owned_window_->Init(aura::WINDOW_LAYER_TEXTURED);
1137 aura::client::ParentWindowWithContext(
1139 widget_.GetNativeView()->GetRootWindow(),
1140 gfx::Rect(0, 0, 1900, 1600));
1141 owned_window_->Show();
1142 owned_window_->AddObserver(this);
1144 ASSERT_TRUE(owned_window_->parent() != NULL);
1145 owned_window_->parent()->AddObserver(this);
1148 views::Widget::GetWidgetForNativeView(owned_window_->parent());
1149 ASSERT_TRUE(top_level_widget_ != NULL);
1152 void DestroyOwnedWindow() {
1153 ASSERT_TRUE(owned_window_ != NULL);
1154 delete owned_window_;
1157 void DestroyOwnerWindow() {
1158 ASSERT_TRUE(top_level_widget_ != NULL);
1159 top_level_widget_->CloseNow();
1162 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
1163 window->RemoveObserver(this);
1164 if (window == owned_window_) {
1165 owned_window_destroyed_ = true;
1166 } else if (window == top_level_widget_->GetNativeView()) {
1167 owner_destroyed_ = true;
1169 ADD_FAILURE() << "Unexpected window destroyed callback: " << window;
1173 aura::Window* owned_window() {
1174 return owned_window_;
1177 views::Widget* top_level_widget() {
1178 return top_level_widget_;
1182 views::Widget widget_;
1183 views::Widget* top_level_widget_;
1184 aura::Window* owned_window_;
1185 bool owner_destroyed_;
1186 bool owned_window_destroyed_;
1187 aura::test::TestWindowDelegate child_window_delegate_;
1189 DISALLOW_COPY_AND_ASSIGN(DesktopAuraTopLevelWindowTest);
1192 TEST_F(WidgetTest, DesktopAuraFullscreenWindowDestroyedBeforeOwnerTest) {
1193 ViewsDelegate::views_delegate = NULL;
1194 DesktopAuraTopLevelWindowTest fullscreen_window;
1195 ASSERT_NO_FATAL_FAILURE(fullscreen_window.CreateTopLevelWindow(
1196 gfx::Rect(0, 0, 200, 200), true));
1198 RunPendingMessages();
1199 ASSERT_NO_FATAL_FAILURE(fullscreen_window.DestroyOwnedWindow());
1200 RunPendingMessages();
1203 TEST_F(WidgetTest, DesktopAuraFullscreenWindowOwnerDestroyed) {
1204 ViewsDelegate::views_delegate = NULL;
1206 DesktopAuraTopLevelWindowTest fullscreen_window;
1207 ASSERT_NO_FATAL_FAILURE(fullscreen_window.CreateTopLevelWindow(
1208 gfx::Rect(0, 0, 200, 200), true));
1210 RunPendingMessages();
1211 ASSERT_NO_FATAL_FAILURE(fullscreen_window.DestroyOwnerWindow());
1212 RunPendingMessages();
1215 TEST_F(WidgetTest, DesktopAuraTopLevelOwnedPopupTest) {
1216 ViewsDelegate::views_delegate = NULL;
1217 DesktopAuraTopLevelWindowTest popup_window;
1218 ASSERT_NO_FATAL_FAILURE(popup_window.CreateTopLevelWindow(
1219 gfx::Rect(0, 0, 200, 200), false));
1221 RunPendingMessages();
1222 ASSERT_NO_FATAL_FAILURE(popup_window.DestroyOwnedWindow());
1223 RunPendingMessages();
1226 // This test validates that when a top level owned popup Aura window is
1227 // resized, the widget is resized as well.
1228 TEST_F(WidgetTest, DesktopAuraTopLevelOwnedPopupResizeTest) {
1229 ViewsDelegate::views_delegate = NULL;
1230 DesktopAuraTopLevelWindowTest popup_window;
1231 ASSERT_NO_FATAL_FAILURE(popup_window.CreateTopLevelWindow(
1232 gfx::Rect(0, 0, 200, 200), false));
1234 gfx::Rect new_size(0, 0, 400, 400);
1235 popup_window.owned_window()->SetBounds(new_size);
1237 EXPECT_EQ(popup_window.top_level_widget()->GetNativeView()->bounds().size(),
1239 RunPendingMessages();
1240 ASSERT_NO_FATAL_FAILURE(popup_window.DestroyOwnedWindow());
1241 RunPendingMessages();
1244 // Test to ensure that the aura Window's visiblity state is set to visible if
1245 // the underlying widget is hidden and then shown.
1246 TEST_F(WidgetTest, TestWindowVisibilityAfterHide) {
1249 Widget::InitParams init_params =
1250 CreateParams(Widget::InitParams::TYPE_WINDOW);
1251 init_params.show_state = ui::SHOW_STATE_NORMAL;
1252 gfx::Rect initial_bounds(0, 0, 300, 400);
1253 init_params.bounds = initial_bounds;
1254 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1255 init_params.native_widget = new DesktopNativeWidgetAura(&widget);
1256 widget.Init(init_params);
1257 NonClientView* non_client_view = widget.non_client_view();
1258 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1259 non_client_view->SetFrameView(frame_view);
1262 EXPECT_FALSE(widget.GetNativeView()->IsVisible());
1264 EXPECT_TRUE(widget.GetNativeView()->IsVisible());
1267 // The following code verifies we can correctly destroy a Widget from a mouse
1268 // enter/exit. We could test move/drag/enter/exit but in general we don't run
1269 // nested message loops from such events, nor has the code ever really dealt
1270 // with this situation.
1272 // Class that closes the widget (which ends up deleting it immediately) when the
1273 // appropriate event is received.
1274 class CloseWidgetView : public View {
1276 explicit CloseWidgetView(ui::EventType event_type)
1277 : event_type_(event_type) {
1281 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
1282 if (!CloseWidget(event))
1283 View::OnMousePressed(event);
1286 virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE {
1287 if (!CloseWidget(event))
1288 View::OnMouseDragged(event);
1291 virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE {
1292 if (!CloseWidget(event))
1293 View::OnMouseReleased(event);
1295 virtual void OnMouseMoved(const ui::MouseEvent& event) OVERRIDE {
1296 if (!CloseWidget(event))
1297 View::OnMouseMoved(event);
1299 virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE {
1300 if (!CloseWidget(event))
1301 View::OnMouseEntered(event);
1305 bool CloseWidget(const ui::LocatedEvent& event) {
1306 if (event.type() == event_type_) {
1307 // Go through NativeWidgetPrivate to simulate what happens if the OS
1308 // deletes the NativeWindow out from under us.
1309 GetWidget()->native_widget_private()->CloseNow();
1315 const ui::EventType event_type_;
1317 DISALLOW_COPY_AND_ASSIGN(CloseWidgetView);
1320 // Generates two moves (first generates enter, second real move), a press, drag
1321 // and release stopping at |last_event_type|.
1322 void GenerateMouseEvents(Widget* widget, ui::EventType last_event_type) {
1323 const gfx::Rect screen_bounds(widget->GetWindowBoundsInScreen());
1324 ui::MouseEvent move_event(ui::ET_MOUSE_MOVED, screen_bounds.CenterPoint(),
1325 screen_bounds.CenterPoint(), 0, 0);
1326 aura::WindowEventDispatcher* dispatcher =
1327 widget->GetNativeWindow()->GetDispatcher();
1328 ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&move_event);
1329 if (last_event_type == ui::ET_MOUSE_ENTERED || details.dispatcher_destroyed)
1331 details = dispatcher->OnEventFromSource(&move_event);
1332 if (last_event_type == ui::ET_MOUSE_MOVED || details.dispatcher_destroyed)
1335 ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, screen_bounds.CenterPoint(),
1336 screen_bounds.CenterPoint(), 0, 0);
1337 details = dispatcher->OnEventFromSource(&press_event);
1338 if (last_event_type == ui::ET_MOUSE_PRESSED || details.dispatcher_destroyed)
1341 gfx::Point end_point(screen_bounds.CenterPoint());
1342 end_point.Offset(1, 1);
1343 ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, end_point, end_point, 0, 0);
1344 details = dispatcher->OnEventFromSource(&drag_event);
1345 if (last_event_type == ui::ET_MOUSE_DRAGGED || details.dispatcher_destroyed)
1348 ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, end_point, end_point, 0,
1350 details = dispatcher->OnEventFromSource(&release_event);
1351 if (details.dispatcher_destroyed)
1355 // Creates a widget and invokes GenerateMouseEvents() with |last_event_type|.
1356 void RunCloseWidgetDuringDispatchTest(WidgetTest* test,
1357 ui::EventType last_event_type) {
1358 // |widget| is deleted by CloseWidgetView.
1359 Widget* widget = new Widget;
1360 Widget::InitParams params =
1361 test->CreateParams(Widget::InitParams::TYPE_POPUP);
1362 params.native_widget = new DesktopNativeWidgetAura(widget);
1363 params.bounds = gfx::Rect(0, 0, 50, 100);
1364 widget->Init(params);
1365 widget->SetContentsView(new CloseWidgetView(last_event_type));
1367 GenerateMouseEvents(widget, last_event_type);
1370 // Verifies deleting the widget from a mouse pressed event doesn't crash.
1371 TEST_F(WidgetTest, CloseWidgetDuringMousePress) {
1372 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_PRESSED);
1375 // Verifies deleting the widget from a mouse released event doesn't crash.
1376 TEST_F(WidgetTest, CloseWidgetDuringMouseReleased) {
1377 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_RELEASED);
1380 #endif // !defined(OS_CHROMEOS)
1382 // Tests that wheel events generated from scroll events are targetted to the
1383 // views under the cursor when the focused view does not processed them.
1384 TEST_F(WidgetTest, WheelEventsFromScrollEventTarget) {
1385 EventCountView* cursor_view = new EventCountView;
1386 cursor_view->SetBounds(60, 0, 50, 40);
1388 Widget* widget = CreateTopLevelPlatformWidget();
1389 widget->GetRootView()->AddChildView(cursor_view);
1391 // Generate a scroll event on the cursor view.
1392 ui::ScrollEvent scroll(ui::ET_SCROLL,
1394 ui::EventTimeForNow(),
1399 widget->OnScrollEvent(&scroll);
1401 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_SCROLL));
1402 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1404 cursor_view->ResetCounts();
1406 ui::ScrollEvent scroll2(ui::ET_SCROLL,
1408 ui::EventTimeForNow(),
1413 widget->OnScrollEvent(&scroll2);
1415 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_SCROLL));
1416 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1421 #endif // defined(USE_AURA)
1423 // Tests that if a scroll-begin gesture is not handled, then subsequent scroll
1424 // events are not dispatched to any view.
1425 TEST_F(WidgetTest, GestureScrollEventDispatching) {
1426 EventCountView* noscroll_view = new EventCountView;
1427 EventCountView* scroll_view = new ScrollableEventCountView;
1429 noscroll_view->SetBounds(0, 0, 50, 40);
1430 scroll_view->SetBounds(60, 0, 40, 40);
1432 Widget* widget = CreateTopLevelPlatformWidget();
1433 widget->GetRootView()->AddChildView(noscroll_view);
1434 widget->GetRootView()->AddChildView(scroll_view);
1437 ui::GestureEvent begin(ui::ET_GESTURE_SCROLL_BEGIN,
1438 5, 5, 0, base::TimeDelta(),
1439 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0),
1441 widget->OnGestureEvent(&begin);
1442 ui::GestureEvent update(ui::ET_GESTURE_SCROLL_UPDATE,
1443 25, 15, 0, base::TimeDelta(),
1444 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10),
1446 widget->OnGestureEvent(&update);
1447 ui::GestureEvent end(ui::ET_GESTURE_SCROLL_END,
1448 25, 15, 0, base::TimeDelta(),
1449 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END, 0, 0),
1451 widget->OnGestureEvent(&end);
1453 EXPECT_EQ(1, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1454 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1455 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1459 ui::GestureEvent begin(ui::ET_GESTURE_SCROLL_BEGIN,
1460 65, 5, 0, base::TimeDelta(),
1461 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0),
1463 widget->OnGestureEvent(&begin);
1464 ui::GestureEvent update(ui::ET_GESTURE_SCROLL_UPDATE,
1465 85, 15, 0, base::TimeDelta(),
1466 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10),
1468 widget->OnGestureEvent(&update);
1469 ui::GestureEvent end(ui::ET_GESTURE_SCROLL_END,
1470 85, 15, 0, base::TimeDelta(),
1471 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END, 0, 0),
1473 widget->OnGestureEvent(&end);
1475 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1476 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1477 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1483 // Tests that event-handlers installed on the RootView get triggered correctly.
1484 TEST_F(WidgetTest, EventHandlersOnRootView) {
1485 Widget* widget = CreateTopLevelNativeWidget();
1486 View* root_view = widget->GetRootView();
1488 EventCountView* view = new EventCountView;
1489 view->SetBounds(0, 0, 20, 20);
1490 root_view->AddChildView(view);
1492 EventCountHandler h1;
1493 root_view->AddPreTargetHandler(&h1);
1495 EventCountHandler h2;
1496 root_view->AddPostTargetHandler(&h2);
1498 widget->SetBounds(gfx::Rect(0, 0, 100, 100));
1501 ui::TouchEvent pressed(ui::ET_TOUCH_PRESSED,
1504 ui::EventTimeForNow(),
1505 1.0, 0.0, 1.0, 0.0);
1506 widget->OnTouchEvent(&pressed);
1507 EXPECT_EQ(1, h1.GetEventCount(ui::ET_TOUCH_PRESSED));
1508 EXPECT_EQ(1, view->GetEventCount(ui::ET_TOUCH_PRESSED));
1509 EXPECT_EQ(1, h2.GetEventCount(ui::ET_TOUCH_PRESSED));
1511 ui::GestureEvent begin(ui::ET_GESTURE_BEGIN,
1512 5, 5, 0, ui::EventTimeForNow(),
1513 ui::GestureEventDetails(ui::ET_GESTURE_BEGIN, 0, 0), 1);
1514 ui::GestureEvent end(ui::ET_GESTURE_END,
1515 5, 5, 0, ui::EventTimeForNow(),
1516 ui::GestureEventDetails(ui::ET_GESTURE_END, 0, 0), 1);
1517 widget->OnGestureEvent(&begin);
1518 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_BEGIN));
1519 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_BEGIN));
1520 EXPECT_EQ(1, h2.GetEventCount(ui::ET_GESTURE_BEGIN));
1522 ui::TouchEvent released(ui::ET_TOUCH_RELEASED,
1525 ui::EventTimeForNow(),
1526 1.0, 0.0, 1.0, 0.0);
1527 widget->OnTouchEvent(&released);
1528 EXPECT_EQ(1, h1.GetEventCount(ui::ET_TOUCH_RELEASED));
1529 EXPECT_EQ(1, view->GetEventCount(ui::ET_TOUCH_RELEASED));
1530 EXPECT_EQ(1, h2.GetEventCount(ui::ET_TOUCH_RELEASED));
1532 widget->OnGestureEvent(&end);
1533 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_END));
1534 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_END));
1535 EXPECT_EQ(1, h2.GetEventCount(ui::ET_GESTURE_END));
1537 ui::ScrollEvent scroll(ui::ET_SCROLL,
1539 ui::EventTimeForNow(),
1544 widget->OnScrollEvent(&scroll);
1545 EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL));
1546 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1547 EXPECT_EQ(1, h2.GetEventCount(ui::ET_SCROLL));
1552 TEST_F(WidgetTest, SynthesizeMouseMoveEvent) {
1553 Widget* widget = CreateTopLevelNativeWidget();
1554 View* root_view = widget->GetRootView();
1556 EventCountView* v1 = new EventCountView();
1557 v1->SetBounds(0, 0, 10, 10);
1558 root_view->AddChildView(v1);
1559 EventCountView* v2 = new EventCountView();
1560 v2->SetBounds(0, 10, 10, 10);
1561 root_view->AddChildView(v2);
1563 gfx::Point cursor_location(5, 5);
1564 ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
1565 ui::EF_NONE, ui::EF_NONE);
1566 widget->OnMouseEvent(&move);
1568 EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
1569 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1572 v2->SetBounds(0, 0, 10, 10);
1573 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1575 widget->SynthesizeMouseMoveEvent();
1576 EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1579 // Used by SingleWindowClosing to count number of times WindowClosing() has
1581 class ClosingDelegate : public WidgetDelegate {
1583 ClosingDelegate() : count_(0), widget_(NULL) {}
1585 int count() const { return count_; }
1587 void set_widget(views::Widget* widget) { widget_ = widget; }
1589 // WidgetDelegate overrides:
1590 virtual Widget* GetWidget() OVERRIDE { return widget_; }
1591 virtual const Widget* GetWidget() const OVERRIDE { return widget_; }
1592 virtual void WindowClosing() OVERRIDE {
1598 views::Widget* widget_;
1600 DISALLOW_COPY_AND_ASSIGN(ClosingDelegate);
1603 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget
1605 TEST_F(WidgetTest, SingleWindowClosing) {
1606 scoped_ptr<ClosingDelegate> delegate(new ClosingDelegate());
1607 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1608 Widget::InitParams init_params =
1609 CreateParams(Widget::InitParams::TYPE_WINDOW);
1610 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1611 init_params.delegate = delegate.get();
1612 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1613 init_params.native_widget = new DesktopNativeWidgetAura(widget);
1615 widget->Init(init_params);
1616 EXPECT_EQ(0, delegate->count());
1618 EXPECT_EQ(1, delegate->count());
1621 class WidgetWindowTitleTest : public WidgetTest {
1623 void RunTest(bool desktop_native_widget) {
1624 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1625 Widget::InitParams init_params =
1626 CreateParams(Widget::InitParams::TYPE_WINDOW);
1627 widget->Init(init_params);
1629 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1630 if (desktop_native_widget)
1631 init_params.native_widget = new DesktopNativeWidgetAura(widget);
1633 DCHECK(!desktop_native_widget)
1634 << "DesktopNativeWidget does not exist on non-Aura or on ChromeOS.";
1637 internal::NativeWidgetPrivate* native_widget =
1638 widget->native_widget_private();
1640 base::string16 empty;
1641 base::string16 s1(base::UTF8ToUTF16("Title1"));
1642 base::string16 s2(base::UTF8ToUTF16("Title2"));
1643 base::string16 s3(base::UTF8ToUTF16("TitleLong"));
1645 // The widget starts with no title, setting empty should not change
1647 EXPECT_FALSE(native_widget->SetWindowTitle(empty));
1648 // Setting the title to something non-empty should cause a change.
1649 EXPECT_TRUE(native_widget->SetWindowTitle(s1));
1650 // Setting the title to something else with the same length should cause a
1652 EXPECT_TRUE(native_widget->SetWindowTitle(s2));
1653 // Setting the title to something else with a different length should cause
1655 EXPECT_TRUE(native_widget->SetWindowTitle(s3));
1656 // Setting the title to the same thing twice should not cause a change.
1657 EXPECT_FALSE(native_widget->SetWindowTitle(s3));
1663 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_NativeWidget) {
1664 // Use the default NativeWidget.
1665 bool desktop_native_widget = false;
1666 RunTest(desktop_native_widget);
1669 // DesktopNativeWidget does not exist on non-Aura or on ChromeOS.
1670 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1671 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_DesktopNativeWidget) {
1672 // Override to use a DesktopNativeWidget.
1673 bool desktop_native_widget = true;
1674 RunTest(desktop_native_widget);
1676 #endif // USE_AURA && !OS_CHROMEOS
1678 // Used by SetTopLevelCorrectly to track calls to OnBeforeWidgetInit().
1679 class VerifyTopLevelDelegate : public TestViewsDelegate {
1681 VerifyTopLevelDelegate()
1682 : on_before_init_called_(false),
1683 is_top_level_(false) {
1686 bool on_before_init_called() const { return on_before_init_called_; }
1687 bool is_top_level() const { return is_top_level_; }
1689 virtual void OnBeforeWidgetInit(
1690 Widget::InitParams* params,
1691 internal::NativeWidgetDelegate* delegate) OVERRIDE {
1692 on_before_init_called_ = true;
1693 is_top_level_ = params->top_level;
1697 bool on_before_init_called_;
1700 DISALLOW_COPY_AND_ASSIGN(VerifyTopLevelDelegate);
1703 // Verifies |top_level| is correctly passed to
1704 // ViewsDelegate::OnBeforeWidgetInit().
1705 TEST_F(WidgetTest, SetTopLevelCorrectly) {
1706 set_views_delegate(NULL);
1707 VerifyTopLevelDelegate* delegate = new VerifyTopLevelDelegate;
1708 set_views_delegate(delegate); // ViewsTestBase takes ownership.
1709 scoped_ptr<Widget> widget(new Widget);
1710 Widget::InitParams params =
1711 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1712 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1713 widget->Init(params);
1714 EXPECT_TRUE(delegate->on_before_init_called());
1715 EXPECT_TRUE(delegate->is_top_level());
1718 // A scumbag View that deletes its owning widget OnMousePressed.
1719 class WidgetDeleterView : public View {
1721 WidgetDeleterView() : View() {}
1723 // Overridden from View.
1724 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
1730 DISALLOW_COPY_AND_ASSIGN(WidgetDeleterView);
1733 TEST_F(WidgetTest, TestWidgetDeletedInOnMousePressed) {
1734 Widget* widget = new Widget;
1735 Widget::InitParams params =
1736 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1737 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1738 widget->Init(params);
1740 widget->SetContentsView(new WidgetDeleterView);
1742 widget->SetSize(gfx::Size(100, 100));
1745 gfx::Point click_location(45, 15);
1746 ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
1747 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
1748 widget->OnMouseEvent(&press);
1750 // Yay we did not crash!
1753 // See description of RunGetNativeThemeFromDestructor() for details.
1754 class GetNativeThemeFromDestructorView : public WidgetDelegateView {
1756 GetNativeThemeFromDestructorView() {}
1757 virtual ~GetNativeThemeFromDestructorView() {
1758 VerifyNativeTheme();
1761 virtual View* GetContentsView() OVERRIDE {
1766 void VerifyNativeTheme() {
1767 ASSERT_TRUE(GetNativeTheme() != NULL);
1770 DISALLOW_COPY_AND_ASSIGN(GetNativeThemeFromDestructorView);
1773 // Verifies GetNativeTheme() from the destructor of a WidgetDelegateView doesn't
1774 // crash. |is_first_run| is true if this is the first call. A return value of
1775 // true indicates this should be run again with a value of false.
1776 // First run uses DesktopNativeWidgetAura (if possible). Second run doesn't.
1777 bool RunGetNativeThemeFromDestructor(const Widget::InitParams& in_params,
1778 bool is_first_run) {
1779 bool needs_second_run = false;
1780 // Destroyed by CloseNow() below.
1781 Widget* widget = new Widget;
1782 Widget::InitParams params(in_params);
1783 // Deletes itself when the Widget is destroyed.
1784 params.delegate = new GetNativeThemeFromDestructorView;
1785 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1787 params.native_widget = new DesktopNativeWidgetAura(widget);
1788 needs_second_run = true;
1791 widget->Init(params);
1793 return needs_second_run;
1796 // See description of RunGetNativeThemeFromDestructor() for details.
1797 TEST_F(WidgetTest, GetNativeThemeFromDestructor) {
1798 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1799 if (RunGetNativeThemeFromDestructor(params, true))
1800 RunGetNativeThemeFromDestructor(params, false);
1803 // Used by HideCloseDestroy. Allows setting a boolean when the widget is
1805 class CloseDestroysWidget : public Widget {
1807 explicit CloseDestroysWidget(bool* destroyed)
1808 : destroyed_(destroyed) {
1811 virtual ~CloseDestroysWidget() {
1814 base::MessageLoop::current()->QuitNow();
1818 void Detach() { destroyed_ = NULL; }
1821 // If non-null set to true from destructor.
1824 DISALLOW_COPY_AND_ASSIGN(CloseDestroysWidget);
1827 // Verifies Close() results in destroying.
1828 TEST_F(WidgetTest, CloseDestroys) {
1829 bool destroyed = false;
1830 CloseDestroysWidget* widget = new CloseDestroysWidget(&destroyed);
1831 Widget::InitParams params =
1832 CreateParams(views::Widget::InitParams::TYPE_MENU);
1833 params.opacity = Widget::InitParams::OPAQUE_WINDOW;
1834 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1835 params.native_widget = new DesktopNativeWidgetAura(widget);
1837 widget->Init(params);
1841 // Run the message loop as Close() asynchronously deletes.
1842 RunPendingMessages();
1843 EXPECT_TRUE(destroyed);
1844 // Close() should destroy the widget. If not we'll cleanup to avoid leaks.
1851 // A view that consumes mouse-pressed event and gesture-tap-down events.
1852 class RootViewTestView : public View {
1854 RootViewTestView(): View() {}
1857 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
1861 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
1862 if (event->type() == ui::ET_GESTURE_TAP_DOWN)
1863 event->SetHandled();
1867 // Checks if RootView::*_handler_ fields are unset when widget is hidden.
1868 // Fails on chromium.webkit Windows bot, see crbug.com/264872.
1870 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1871 DISABLED_TestRootViewHandlersWhenHidden
1873 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1874 TestRootViewHandlersWhenHidden
1876 TEST_F(WidgetTest, MAYBE_DisableTestRootViewHandlersWhenHidden) {
1877 Widget* widget = CreateTopLevelNativeWidget();
1878 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
1879 View* view = new RootViewTestView();
1880 view->SetBounds(0, 0, 300, 300);
1881 internal::RootView* root_view =
1882 static_cast<internal::RootView*>(widget->GetRootView());
1883 root_view->AddChildView(view);
1885 // Check RootView::mouse_pressed_handler_.
1887 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
1888 gfx::Point click_location(45, 15);
1889 ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
1890 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
1891 widget->OnMouseEvent(&press);
1892 EXPECT_EQ(view, GetMousePressedHandler(root_view));
1894 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
1896 // Check RootView::mouse_move_handler_.
1898 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
1899 gfx::Point move_location(45, 15);
1900 ui::MouseEvent move(ui::ET_MOUSE_MOVED, move_location, move_location, 0, 0);
1901 widget->OnMouseEvent(&move);
1902 EXPECT_EQ(view, GetMouseMoveHandler(root_view));
1904 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
1906 // Check RootView::gesture_handler_.
1908 EXPECT_EQ(NULL, GetGestureHandler(root_view));
1909 ui::GestureEvent tap_down(
1910 ui::ET_GESTURE_TAP_DOWN,
1915 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN, 0, 0),
1917 widget->OnGestureEvent(&tap_down);
1918 EXPECT_EQ(view, GetGestureHandler(root_view));
1920 EXPECT_EQ(NULL, GetGestureHandler(root_view));
1925 // Test the result of Widget::GetAllChildWidgets().
1926 TEST_F(WidgetTest, GetAllChildWidgets) {
1927 // Create the following widget hierarchy:
1935 Widget* toplevel = CreateTopLevelPlatformWidget();
1936 Widget* w1 = CreateChildPlatformWidget(toplevel->GetNativeView());
1937 Widget* w11 = CreateChildPlatformWidget(w1->GetNativeView());
1938 Widget* w2 = CreateChildPlatformWidget(toplevel->GetNativeView());
1939 Widget* w21 = CreateChildPlatformWidget(w2->GetNativeView());
1940 Widget* w22 = CreateChildPlatformWidget(w2->GetNativeView());
1942 std::set<Widget*> expected;
1943 expected.insert(toplevel);
1944 expected.insert(w1);
1945 expected.insert(w11);
1946 expected.insert(w2);
1947 expected.insert(w21);
1948 expected.insert(w22);
1950 std::set<Widget*> widgets;
1951 Widget::GetAllChildWidgets(toplevel->GetNativeView(), &widgets);
1953 EXPECT_EQ(expected.size(), widgets.size());
1954 EXPECT_TRUE(std::equal(expected.begin(), expected.end(), widgets.begin()));
1957 // Used by DestroyChildWidgetsInOrder. On destruction adds the supplied name to
1959 class DestroyedTrackingView : public View {
1961 DestroyedTrackingView(const std::string& name,
1962 std::vector<std::string>* add_to)
1967 virtual ~DestroyedTrackingView() {
1968 add_to_->push_back(name_);
1972 const std::string name_;
1973 std::vector<std::string>* add_to_;
1975 DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingView);
1978 class WidgetChildDestructionTest : public WidgetTest {
1980 WidgetChildDestructionTest() {}
1982 // Creates a top level and a child, destroys the child and verifies the views
1983 // of the child are destroyed before the views of the parent.
1984 void RunDestroyChildWidgetsTest(bool top_level_has_desktop_native_widget_aura,
1985 bool child_has_desktop_native_widget_aura) {
1986 // When a View is destroyed its name is added here.
1987 std::vector<std::string> destroyed;
1989 Widget* top_level = new Widget;
1990 Widget::InitParams params =
1991 CreateParams(views::Widget::InitParams::TYPE_WINDOW);
1992 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1993 if (top_level_has_desktop_native_widget_aura)
1994 params.native_widget = new DesktopNativeWidgetAura(top_level);
1996 top_level->Init(params);
1997 top_level->GetRootView()->AddChildView(
1998 new DestroyedTrackingView("parent", &destroyed));
2001 Widget* child = new Widget;
2002 Widget::InitParams child_params =
2003 CreateParams(views::Widget::InitParams::TYPE_POPUP);
2004 child_params.parent = top_level->GetNativeView();
2005 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
2006 if (child_has_desktop_native_widget_aura)
2007 child_params.native_widget = new DesktopNativeWidgetAura(child);
2009 child->Init(child_params);
2010 child->GetRootView()->AddChildView(
2011 new DestroyedTrackingView("child", &destroyed));
2014 // Should trigger destruction of the child too.
2015 top_level->native_widget_private()->CloseNow();
2017 // Child should be destroyed first.
2018 ASSERT_EQ(2u, destroyed.size());
2019 EXPECT_EQ("child", destroyed[0]);
2020 EXPECT_EQ("parent", destroyed[1]);
2024 DISALLOW_COPY_AND_ASSIGN(WidgetChildDestructionTest);
2027 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
2028 // See description of RunDestroyChildWidgetsTest(). Parent uses
2029 // DesktopNativeWidgetAura.
2030 TEST_F(WidgetChildDestructionTest,
2031 DestroyChildWidgetsInOrderWithDesktopNativeWidget) {
2032 RunDestroyChildWidgetsTest(true, false);
2035 // See description of RunDestroyChildWidgetsTest(). Both parent and child use
2036 // DesktopNativeWidgetAura.
2037 TEST_F(WidgetChildDestructionTest,
2038 DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth) {
2039 RunDestroyChildWidgetsTest(true, true);
2043 // See description of RunDestroyChildWidgetsTest().
2044 TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) {
2045 RunDestroyChildWidgetsTest(false, false);
2048 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
2049 // Provides functionality to create a window modal dialog.
2050 class ModalDialogDelegate : public DialogDelegateView {
2052 ModalDialogDelegate() {}
2053 virtual ~ModalDialogDelegate() {}
2055 // WidgetDelegate overrides.
2056 virtual ui::ModalType GetModalType() const OVERRIDE {
2057 return ui::MODAL_TYPE_WINDOW;
2061 DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate);
2064 // This test verifies that whether mouse events when a modal dialog is
2065 // displayed are eaten or recieved by the dialog.
2066 TEST_F(WidgetTest, WindowMouseModalityTest) {
2067 // Create a top level widget.
2068 Widget top_level_widget;
2069 Widget::InitParams init_params =
2070 CreateParams(Widget::InitParams::TYPE_WINDOW);
2071 init_params.show_state = ui::SHOW_STATE_NORMAL;
2072 gfx::Rect initial_bounds(0, 0, 500, 500);
2073 init_params.bounds = initial_bounds;
2074 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2075 init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget);
2076 top_level_widget.Init(init_params);
2077 top_level_widget.Show();
2078 EXPECT_TRUE(top_level_widget.IsVisible());
2080 // Create a view and validate that a mouse moves makes it to the view.
2081 EventCountView* widget_view = new EventCountView();
2082 widget_view->SetBounds(0, 0, 10, 10);
2083 top_level_widget.GetRootView()->AddChildView(widget_view);
2085 gfx::Point cursor_location_main(5, 5);
2086 ui::MouseEvent move_main(ui::ET_MOUSE_MOVED,
2087 cursor_location_main,
2088 cursor_location_main,
2091 ui::EventDispatchDetails details = top_level_widget.GetNativeView()->
2092 GetDispatcher()->OnEventFromSource(&move_main);
2093 ASSERT_FALSE(details.dispatcher_destroyed);
2095 EXPECT_EQ(1, widget_view->GetEventCount(ui::ET_MOUSE_ENTERED));
2096 widget_view->ResetCounts();
2098 // Create a modal dialog and validate that a mouse down message makes it to
2099 // the main view within the dialog.
2101 // This instance will be destroyed when the dialog is destroyed.
2102 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
2104 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
2105 dialog_delegate, NULL, top_level_widget.GetNativeWindow());
2106 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
2107 EventCountView* dialog_widget_view = new EventCountView();
2108 dialog_widget_view->SetBounds(0, 0, 50, 50);
2109 modal_dialog_widget->GetRootView()->AddChildView(dialog_widget_view);
2110 modal_dialog_widget->Show();
2111 EXPECT_TRUE(modal_dialog_widget->IsVisible());
2113 gfx::Point cursor_location_dialog(100, 100);
2114 ui::MouseEvent mouse_down_dialog(ui::ET_MOUSE_PRESSED,
2115 cursor_location_dialog,
2116 cursor_location_dialog,
2119 details = top_level_widget.GetNativeView()->GetDispatcher()->
2120 OnEventFromSource(&mouse_down_dialog);
2121 ASSERT_FALSE(details.dispatcher_destroyed);
2122 EXPECT_EQ(1, dialog_widget_view->GetEventCount(ui::ET_MOUSE_PRESSED));
2124 // Send a mouse move message to the main window. It should not be received by
2125 // the main window as the modal dialog is still active.
2126 gfx::Point cursor_location_main2(6, 6);
2127 ui::MouseEvent mouse_down_main(ui::ET_MOUSE_MOVED,
2128 cursor_location_main2,
2129 cursor_location_main2,
2132 details = top_level_widget.GetNativeView()->GetDispatcher()->
2133 OnEventFromSource(&mouse_down_main);
2134 ASSERT_FALSE(details.dispatcher_destroyed);
2135 EXPECT_EQ(0, widget_view->GetEventCount(ui::ET_MOUSE_MOVED));
2137 modal_dialog_widget->CloseNow();
2138 top_level_widget.CloseNow();
2141 #if defined(USE_AURA)
2142 // Verifies nativeview visbility matches that of Widget visibility when
2143 // SetFullscreen is invoked.
2144 TEST_F(WidgetTest, FullscreenStatePropagated) {
2145 Widget::InitParams init_params =
2146 CreateParams(Widget::InitParams::TYPE_WINDOW);
2147 init_params.show_state = ui::SHOW_STATE_NORMAL;
2148 init_params.bounds = gfx::Rect(0, 0, 500, 500);
2149 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2152 Widget top_level_widget;
2153 top_level_widget.Init(init_params);
2154 top_level_widget.SetFullscreen(true);
2155 EXPECT_EQ(top_level_widget.IsVisible(),
2156 top_level_widget.GetNativeView()->IsVisible());
2157 top_level_widget.CloseNow();
2160 #if !defined(OS_CHROMEOS)
2162 Widget top_level_widget;
2163 init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget);
2164 top_level_widget.Init(init_params);
2165 top_level_widget.SetFullscreen(true);
2166 EXPECT_EQ(top_level_widget.IsVisible(),
2167 top_level_widget.GetNativeView()->IsVisible());
2168 top_level_widget.CloseNow();
2176 // Provides functionality to test widget activation via an activation flag
2177 // which can be set by an accessor.
2178 class ModalWindowTestWidgetDelegate : public WidgetDelegate {
2180 ModalWindowTestWidgetDelegate()
2182 can_activate_(true) {}
2184 virtual ~ModalWindowTestWidgetDelegate() {}
2186 // Overridden from WidgetDelegate:
2187 virtual void DeleteDelegate() OVERRIDE {
2190 virtual Widget* GetWidget() OVERRIDE {
2193 virtual const Widget* GetWidget() const OVERRIDE {
2196 virtual bool CanActivate() const OVERRIDE {
2197 return can_activate_;
2199 virtual bool ShouldAdvanceFocusToTopLevelWidget() const OVERRIDE {
2203 void set_can_activate(bool can_activate) {
2204 can_activate_ = can_activate;
2207 void set_widget(Widget* widget) {
2215 DISALLOW_COPY_AND_ASSIGN(ModalWindowTestWidgetDelegate);
2218 // Tests whether we can activate the top level widget when a modal dialog is
2220 TEST_F(WidgetTest, WindowModalityActivationTest) {
2221 // Destroyed when the top level widget created below is destroyed.
2222 ModalWindowTestWidgetDelegate* widget_delegate =
2223 new ModalWindowTestWidgetDelegate;
2224 // Create a top level widget.
2225 Widget top_level_widget;
2226 Widget::InitParams init_params =
2227 CreateParams(Widget::InitParams::TYPE_WINDOW);
2228 init_params.show_state = ui::SHOW_STATE_NORMAL;
2229 gfx::Rect initial_bounds(0, 0, 500, 500);
2230 init_params.bounds = initial_bounds;
2231 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2232 init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget);
2233 init_params.delegate = widget_delegate;
2234 top_level_widget.Init(init_params);
2235 widget_delegate->set_widget(&top_level_widget);
2236 top_level_widget.Show();
2237 EXPECT_TRUE(top_level_widget.IsVisible());
2239 HWND win32_window = views::HWNDForWidget(&top_level_widget);
2240 EXPECT_TRUE(::IsWindow(win32_window));
2242 // This instance will be destroyed when the dialog is destroyed.
2243 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
2245 // We should be able to activate the window even if the WidgetDelegate
2246 // says no, when a modal dialog is active.
2247 widget_delegate->set_can_activate(false);
2249 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
2250 dialog_delegate, NULL, top_level_widget.GetNativeWindow());
2251 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
2252 modal_dialog_widget->Show();
2253 EXPECT_TRUE(modal_dialog_widget->IsVisible());
2255 LRESULT activate_result = ::SendMessage(
2258 reinterpret_cast<WPARAM>(win32_window),
2259 MAKELPARAM(WM_LBUTTONDOWN, HTCLIENT));
2260 EXPECT_EQ(activate_result, MA_ACTIVATE);
2262 modal_dialog_widget->CloseNow();
2263 top_level_widget.CloseNow();
2268 TEST_F(WidgetTest, ShowCreatesActiveWindow) {
2269 Widget* widget = CreateTopLevelPlatformWidget();
2272 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2277 TEST_F(WidgetTest, ShowInactive) {
2278 Widget* widget = CreateTopLevelPlatformWidget();
2280 widget->ShowInactive();
2281 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_INACTIVE);
2286 TEST_F(WidgetTest, ShowInactiveAfterShow) {
2287 Widget* widget = CreateTopLevelPlatformWidget();
2290 widget->ShowInactive();
2291 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2296 TEST_F(WidgetTest, ShowAfterShowInactive) {
2297 Widget* widget = CreateTopLevelPlatformWidget();
2299 widget->ShowInactive();
2301 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2306 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
2307 TEST_F(WidgetTest, InactiveWidgetDoesNotGrabActivation) {
2308 Widget* widget = CreateTopLevelPlatformWidget();
2310 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2313 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2314 params.can_activate = false;
2315 params.native_widget = new DesktopNativeWidgetAura(&widget2);
2316 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2317 widget2.Init(params);
2320 EXPECT_EQ(GetWidgetShowState(&widget2), ui::SHOW_STATE_INACTIVE);
2321 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2330 class FullscreenAwareFrame : public views::NonClientFrameView {
2332 explicit FullscreenAwareFrame(views::Widget* widget)
2333 : widget_(widget), fullscreen_layout_called_(false) {}
2334 virtual ~FullscreenAwareFrame() {}
2336 // views::NonClientFrameView overrides:
2337 virtual gfx::Rect GetBoundsForClientView() const OVERRIDE {
2340 virtual gfx::Rect GetWindowBoundsForClientBounds(
2341 const gfx::Rect& client_bounds) const OVERRIDE {
2344 virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE {
2347 virtual void GetWindowMask(const gfx::Size& size,
2348 gfx::Path* window_mask) OVERRIDE {}
2349 virtual void ResetWindowControls() OVERRIDE {}
2350 virtual void UpdateWindowIcon() OVERRIDE {}
2351 virtual void UpdateWindowTitle() OVERRIDE {}
2353 // views::View overrides:
2354 virtual void Layout() OVERRIDE {
2355 if (widget_->IsFullscreen())
2356 fullscreen_layout_called_ = true;
2359 bool fullscreen_layout_called() const { return fullscreen_layout_called_; }
2362 views::Widget* widget_;
2363 bool fullscreen_layout_called_;
2365 DISALLOW_COPY_AND_ASSIGN(FullscreenAwareFrame);
2370 // Tests that frame Layout is called when a widget goes fullscreen without
2371 // changing its size or title.
2372 TEST_F(WidgetTest, FullscreenFrameLayout) {
2373 Widget* widget = CreateTopLevelPlatformWidget();
2374 FullscreenAwareFrame* frame = new FullscreenAwareFrame(widget);
2375 widget->non_client_view()->SetFrameView(frame); // Owns |frame|.
2378 RunPendingMessages();
2380 EXPECT_FALSE(frame->fullscreen_layout_called());
2381 widget->SetFullscreen(true);
2383 RunPendingMessages();
2384 EXPECT_TRUE(frame->fullscreen_layout_called());
2389 #if !defined(OS_CHROMEOS)
2392 // Trivial WidgetObserverTest that invokes Widget::IsActive() from
2393 // OnWindowDestroying.
2394 class IsActiveFromDestroyObserver : public WidgetObserver {
2396 IsActiveFromDestroyObserver() {}
2397 virtual ~IsActiveFromDestroyObserver() {}
2398 virtual void OnWidgetDestroying(Widget* widget) OVERRIDE {
2403 DISALLOW_COPY_AND_ASSIGN(IsActiveFromDestroyObserver);
2408 // Verifies Widget::IsActive() invoked from
2409 // WidgetObserver::OnWidgetDestroying() in a child widget doesn't crash.
2410 TEST_F(WidgetTest, IsActiveFromDestroy) {
2411 // Create two widgets, one a child of the other.
2412 IsActiveFromDestroyObserver observer;
2413 Widget parent_widget;
2414 Widget::InitParams parent_params =
2415 CreateParams(Widget::InitParams::TYPE_POPUP);
2416 parent_params.native_widget = new DesktopNativeWidgetAura(&parent_widget);
2417 parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2418 parent_widget.Init(parent_params);
2419 parent_widget.Show();
2421 Widget child_widget;
2422 Widget::InitParams child_params =
2423 CreateParams(Widget::InitParams::TYPE_POPUP);
2424 child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2425 child_params.context = parent_widget.GetNativeView();
2426 child_widget.Init(child_params);
2427 child_widget.AddObserver(&observer);
2428 child_widget.Show();
2430 parent_widget.CloseNow();
2435 } // namespace views