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();
580 widget->Deactivate();
582 widget->DisableInactiveRendering();
583 widget->SetAlwaysOnTop(true);
584 widget->IsAlwaysOnTop();
588 widget->IsMaximized();
589 widget->IsFullscreen();
590 widget->SetOpacity(0);
591 widget->SetUseDragFrame(true);
592 widget->FlashFrame(true);
594 widget->GetThemeProvider();
595 widget->GetNativeTheme();
596 widget->GetFocusManager();
597 widget->GetInputMethod();
598 widget->SchedulePaintInRect(gfx::Rect(0, 0, 1, 2));
599 widget->IsMouseEventsEnabled();
600 widget->SetNativeWindowProperty("xx", widget);
601 widget->GetNativeWindowProperty("xx");
602 widget->GetFocusTraversable();
604 widget->ReorderNativeViews();
605 widget->SetCapture(widget->GetRootView());
606 widget->ReleaseCapture();
607 widget->HasCapture();
608 widget->GetWorkAreaBoundsInScreen();
609 // These three crash with NativeWidgetWin, so I'm assuming we don't need
610 // them to work for the other NativeWidget impls.
611 // widget->CenterWindow(gfx::Size(50, 60));
612 // widget->GetRestoredBounds();
613 // 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::WindowTreeHostDelegate* rwhd =
1327 widget->GetNativeWindow()->GetDispatcher()->AsWindowTreeHostDelegate();
1328 rwhd->OnHostMouseEvent(&move_event);
1329 if (last_event_type == ui::ET_MOUSE_ENTERED)
1331 rwhd->OnHostMouseEvent(&move_event);
1332 if (last_event_type == ui::ET_MOUSE_MOVED)
1335 ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, screen_bounds.CenterPoint(),
1336 screen_bounds.CenterPoint(), 0, 0);
1337 rwhd->OnHostMouseEvent(&press_event);
1338 if (last_event_type == ui::ET_MOUSE_PRESSED)
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 rwhd->OnHostMouseEvent(&drag_event);
1345 if (last_event_type == ui::ET_MOUSE_DRAGGED)
1348 ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, end_point, end_point, 0,
1350 rwhd->OnHostMouseEvent(&release_event);
1353 // Creates a widget and invokes GenerateMouseEvents() with |last_event_type|.
1354 void RunCloseWidgetDuringDispatchTest(WidgetTest* test,
1355 ui::EventType last_event_type) {
1356 // |widget| is deleted by CloseWidgetView.
1357 Widget* widget = new Widget;
1358 Widget::InitParams params =
1359 test->CreateParams(Widget::InitParams::TYPE_POPUP);
1360 params.native_widget = new DesktopNativeWidgetAura(widget);
1361 params.bounds = gfx::Rect(0, 0, 50, 100);
1362 widget->Init(params);
1363 widget->SetContentsView(new CloseWidgetView(last_event_type));
1365 GenerateMouseEvents(widget, last_event_type);
1368 // Verifies deleting the widget from a mouse pressed event doesn't crash.
1369 TEST_F(WidgetTest, CloseWidgetDuringMousePress) {
1370 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_PRESSED);
1373 // Verifies deleting the widget from a mouse released event doesn't crash.
1374 TEST_F(WidgetTest, CloseWidgetDuringMouseReleased) {
1375 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_RELEASED);
1378 #endif // !defined(OS_CHROMEOS)
1380 // Tests that wheel events generated from scroll events are targetted to the
1381 // views under the cursor when the focused view does not processed them.
1382 TEST_F(WidgetTest, WheelEventsFromScrollEventTarget) {
1383 EventCountView* cursor_view = new EventCountView;
1384 cursor_view->SetBounds(60, 0, 50, 40);
1386 Widget* widget = CreateTopLevelPlatformWidget();
1387 widget->GetRootView()->AddChildView(cursor_view);
1389 // Generate a scroll event on the cursor view.
1390 ui::ScrollEvent scroll(ui::ET_SCROLL,
1392 ui::EventTimeForNow(),
1397 widget->OnScrollEvent(&scroll);
1399 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_SCROLL));
1400 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1402 cursor_view->ResetCounts();
1404 ui::ScrollEvent scroll2(ui::ET_SCROLL,
1406 ui::EventTimeForNow(),
1411 widget->OnScrollEvent(&scroll2);
1413 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_SCROLL));
1414 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1419 #endif // defined(USE_AURA)
1421 // Tests that if a scroll-begin gesture is not handled, then subsequent scroll
1422 // events are not dispatched to any view.
1423 TEST_F(WidgetTest, GestureScrollEventDispatching) {
1424 EventCountView* noscroll_view = new EventCountView;
1425 EventCountView* scroll_view = new ScrollableEventCountView;
1427 noscroll_view->SetBounds(0, 0, 50, 40);
1428 scroll_view->SetBounds(60, 0, 40, 40);
1430 Widget* widget = CreateTopLevelPlatformWidget();
1431 widget->GetRootView()->AddChildView(noscroll_view);
1432 widget->GetRootView()->AddChildView(scroll_view);
1435 ui::GestureEvent begin(ui::ET_GESTURE_SCROLL_BEGIN,
1436 5, 5, 0, base::TimeDelta(),
1437 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0),
1439 widget->OnGestureEvent(&begin);
1440 ui::GestureEvent update(ui::ET_GESTURE_SCROLL_UPDATE,
1441 25, 15, 0, base::TimeDelta(),
1442 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10),
1444 widget->OnGestureEvent(&update);
1445 ui::GestureEvent end(ui::ET_GESTURE_SCROLL_END,
1446 25, 15, 0, base::TimeDelta(),
1447 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END, 0, 0),
1449 widget->OnGestureEvent(&end);
1451 EXPECT_EQ(1, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1452 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1453 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1457 ui::GestureEvent begin(ui::ET_GESTURE_SCROLL_BEGIN,
1458 65, 5, 0, base::TimeDelta(),
1459 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0),
1461 widget->OnGestureEvent(&begin);
1462 ui::GestureEvent update(ui::ET_GESTURE_SCROLL_UPDATE,
1463 85, 15, 0, base::TimeDelta(),
1464 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10),
1466 widget->OnGestureEvent(&update);
1467 ui::GestureEvent end(ui::ET_GESTURE_SCROLL_END,
1468 85, 15, 0, base::TimeDelta(),
1469 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END, 0, 0),
1471 widget->OnGestureEvent(&end);
1473 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1474 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1475 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1481 // Tests that event-handlers installed on the RootView get triggered correctly.
1482 TEST_F(WidgetTest, EventHandlersOnRootView) {
1483 Widget* widget = CreateTopLevelNativeWidget();
1484 View* root_view = widget->GetRootView();
1486 EventCountView* view = new EventCountView;
1487 view->SetBounds(0, 0, 20, 20);
1488 root_view->AddChildView(view);
1490 EventCountHandler h1;
1491 root_view->AddPreTargetHandler(&h1);
1493 EventCountHandler h2;
1494 root_view->AddPostTargetHandler(&h2);
1496 widget->SetBounds(gfx::Rect(0, 0, 100, 100));
1499 ui::TouchEvent pressed(ui::ET_TOUCH_PRESSED,
1502 ui::EventTimeForNow(),
1503 1.0, 0.0, 1.0, 0.0);
1504 widget->OnTouchEvent(&pressed);
1505 EXPECT_EQ(1, h1.GetEventCount(ui::ET_TOUCH_PRESSED));
1506 EXPECT_EQ(1, view->GetEventCount(ui::ET_TOUCH_PRESSED));
1507 EXPECT_EQ(1, h2.GetEventCount(ui::ET_TOUCH_PRESSED));
1509 ui::GestureEvent begin(ui::ET_GESTURE_BEGIN,
1510 5, 5, 0, ui::EventTimeForNow(),
1511 ui::GestureEventDetails(ui::ET_GESTURE_BEGIN, 0, 0), 1);
1512 ui::GestureEvent end(ui::ET_GESTURE_END,
1513 5, 5, 0, ui::EventTimeForNow(),
1514 ui::GestureEventDetails(ui::ET_GESTURE_END, 0, 0), 1);
1515 widget->OnGestureEvent(&begin);
1516 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_BEGIN));
1517 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_BEGIN));
1518 EXPECT_EQ(1, h2.GetEventCount(ui::ET_GESTURE_BEGIN));
1520 ui::TouchEvent released(ui::ET_TOUCH_RELEASED,
1523 ui::EventTimeForNow(),
1524 1.0, 0.0, 1.0, 0.0);
1525 widget->OnTouchEvent(&released);
1526 EXPECT_EQ(1, h1.GetEventCount(ui::ET_TOUCH_RELEASED));
1527 EXPECT_EQ(1, view->GetEventCount(ui::ET_TOUCH_RELEASED));
1528 EXPECT_EQ(1, h2.GetEventCount(ui::ET_TOUCH_RELEASED));
1530 widget->OnGestureEvent(&end);
1531 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_END));
1532 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_END));
1533 EXPECT_EQ(1, h2.GetEventCount(ui::ET_GESTURE_END));
1535 ui::ScrollEvent scroll(ui::ET_SCROLL,
1537 ui::EventTimeForNow(),
1542 widget->OnScrollEvent(&scroll);
1543 EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL));
1544 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1545 EXPECT_EQ(1, h2.GetEventCount(ui::ET_SCROLL));
1550 TEST_F(WidgetTest, SynthesizeMouseMoveEvent) {
1551 Widget* widget = CreateTopLevelNativeWidget();
1552 View* root_view = widget->GetRootView();
1554 EventCountView* v1 = new EventCountView();
1555 v1->SetBounds(0, 0, 10, 10);
1556 root_view->AddChildView(v1);
1557 EventCountView* v2 = new EventCountView();
1558 v2->SetBounds(0, 10, 10, 10);
1559 root_view->AddChildView(v2);
1561 gfx::Point cursor_location(5, 5);
1562 ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
1563 ui::EF_NONE, ui::EF_NONE);
1564 widget->OnMouseEvent(&move);
1566 EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
1567 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1570 v2->SetBounds(0, 0, 10, 10);
1571 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1573 widget->SynthesizeMouseMoveEvent();
1574 EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1577 // Used by SingleWindowClosing to count number of times WindowClosing() has
1579 class ClosingDelegate : public WidgetDelegate {
1581 ClosingDelegate() : count_(0), widget_(NULL) {}
1583 int count() const { return count_; }
1585 void set_widget(views::Widget* widget) { widget_ = widget; }
1587 // WidgetDelegate overrides:
1588 virtual Widget* GetWidget() OVERRIDE { return widget_; }
1589 virtual const Widget* GetWidget() const OVERRIDE { return widget_; }
1590 virtual void WindowClosing() OVERRIDE {
1596 views::Widget* widget_;
1598 DISALLOW_COPY_AND_ASSIGN(ClosingDelegate);
1601 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget
1603 TEST_F(WidgetTest, SingleWindowClosing) {
1604 scoped_ptr<ClosingDelegate> delegate(new ClosingDelegate());
1605 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1606 Widget::InitParams init_params =
1607 CreateParams(Widget::InitParams::TYPE_WINDOW);
1608 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1609 init_params.delegate = delegate.get();
1610 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1611 init_params.native_widget = new DesktopNativeWidgetAura(widget);
1613 widget->Init(init_params);
1614 EXPECT_EQ(0, delegate->count());
1616 EXPECT_EQ(1, delegate->count());
1619 class WidgetWindowTitleTest : public WidgetTest {
1621 void RunTest(bool desktop_native_widget) {
1622 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1623 Widget::InitParams init_params =
1624 CreateParams(Widget::InitParams::TYPE_WINDOW);
1625 widget->Init(init_params);
1627 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1628 if (desktop_native_widget)
1629 init_params.native_widget = new DesktopNativeWidgetAura(widget);
1631 DCHECK(!desktop_native_widget)
1632 << "DesktopNativeWidget does not exist on non-Aura or on ChromeOS.";
1635 internal::NativeWidgetPrivate* native_widget =
1636 widget->native_widget_private();
1638 base::string16 empty;
1639 base::string16 s1(base::UTF8ToUTF16("Title1"));
1640 base::string16 s2(base::UTF8ToUTF16("Title2"));
1641 base::string16 s3(base::UTF8ToUTF16("TitleLong"));
1643 // The widget starts with no title, setting empty should not change
1645 EXPECT_FALSE(native_widget->SetWindowTitle(empty));
1646 // Setting the title to something non-empty should cause a change.
1647 EXPECT_TRUE(native_widget->SetWindowTitle(s1));
1648 // Setting the title to something else with the same length should cause a
1650 EXPECT_TRUE(native_widget->SetWindowTitle(s2));
1651 // Setting the title to something else with a different length should cause
1653 EXPECT_TRUE(native_widget->SetWindowTitle(s3));
1654 // Setting the title to the same thing twice should not cause a change.
1655 EXPECT_FALSE(native_widget->SetWindowTitle(s3));
1661 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_NativeWidget) {
1662 // Use the default NativeWidget.
1663 bool desktop_native_widget = false;
1664 RunTest(desktop_native_widget);
1667 // DesktopNativeWidget does not exist on non-Aura or on ChromeOS.
1668 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1669 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_DesktopNativeWidget) {
1670 // Override to use a DesktopNativeWidget.
1671 bool desktop_native_widget = true;
1672 RunTest(desktop_native_widget);
1674 #endif // USE_AURA && !OS_CHROMEOS
1676 // Used by SetTopLevelCorrectly to track calls to OnBeforeWidgetInit().
1677 class VerifyTopLevelDelegate : public TestViewsDelegate {
1679 VerifyTopLevelDelegate()
1680 : on_before_init_called_(false),
1681 is_top_level_(false) {
1684 bool on_before_init_called() const { return on_before_init_called_; }
1685 bool is_top_level() const { return is_top_level_; }
1687 virtual void OnBeforeWidgetInit(
1688 Widget::InitParams* params,
1689 internal::NativeWidgetDelegate* delegate) OVERRIDE {
1690 on_before_init_called_ = true;
1691 is_top_level_ = params->top_level;
1695 bool on_before_init_called_;
1698 DISALLOW_COPY_AND_ASSIGN(VerifyTopLevelDelegate);
1701 // Verifies |top_level| is correctly passed to
1702 // ViewsDelegate::OnBeforeWidgetInit().
1703 TEST_F(WidgetTest, SetTopLevelCorrectly) {
1704 set_views_delegate(NULL);
1705 VerifyTopLevelDelegate* delegate = new VerifyTopLevelDelegate;
1706 set_views_delegate(delegate); // ViewsTestBase takes ownership.
1707 scoped_ptr<Widget> widget(new Widget);
1708 Widget::InitParams params =
1709 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1710 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1711 widget->Init(params);
1712 EXPECT_TRUE(delegate->on_before_init_called());
1713 EXPECT_TRUE(delegate->is_top_level());
1716 // A scumbag View that deletes its owning widget OnMousePressed.
1717 class WidgetDeleterView : public View {
1719 WidgetDeleterView() : View() {}
1721 // Overridden from View.
1722 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
1728 DISALLOW_COPY_AND_ASSIGN(WidgetDeleterView);
1731 TEST_F(WidgetTest, TestWidgetDeletedInOnMousePressed) {
1732 Widget* widget = new Widget;
1733 Widget::InitParams params =
1734 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1735 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1736 widget->Init(params);
1738 widget->SetContentsView(new WidgetDeleterView);
1740 widget->SetSize(gfx::Size(100, 100));
1743 gfx::Point click_location(45, 15);
1744 ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
1745 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
1746 widget->OnMouseEvent(&press);
1748 // Yay we did not crash!
1751 // See description of RunGetNativeThemeFromDestructor() for details.
1752 class GetNativeThemeFromDestructorView : public WidgetDelegateView {
1754 GetNativeThemeFromDestructorView() {}
1755 virtual ~GetNativeThemeFromDestructorView() {
1756 VerifyNativeTheme();
1759 virtual View* GetContentsView() OVERRIDE {
1764 void VerifyNativeTheme() {
1765 ASSERT_TRUE(GetNativeTheme() != NULL);
1768 DISALLOW_COPY_AND_ASSIGN(GetNativeThemeFromDestructorView);
1771 // Verifies GetNativeTheme() from the destructor of a WidgetDelegateView doesn't
1772 // crash. |is_first_run| is true if this is the first call. A return value of
1773 // true indicates this should be run again with a value of false.
1774 // First run uses DesktopNativeWidgetAura (if possible). Second run doesn't.
1775 bool RunGetNativeThemeFromDestructor(const Widget::InitParams& in_params,
1776 bool is_first_run) {
1777 bool needs_second_run = false;
1778 // Destroyed by CloseNow() below.
1779 Widget* widget = new Widget;
1780 Widget::InitParams params(in_params);
1781 // Deletes itself when the Widget is destroyed.
1782 params.delegate = new GetNativeThemeFromDestructorView;
1783 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1785 params.native_widget = new DesktopNativeWidgetAura(widget);
1786 needs_second_run = true;
1789 widget->Init(params);
1791 return needs_second_run;
1794 // See description of RunGetNativeThemeFromDestructor() for details.
1795 TEST_F(WidgetTest, GetNativeThemeFromDestructor) {
1796 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1797 if (RunGetNativeThemeFromDestructor(params, true))
1798 RunGetNativeThemeFromDestructor(params, false);
1801 // Used by HideCloseDestroy. Allows setting a boolean when the widget is
1803 class CloseDestroysWidget : public Widget {
1805 explicit CloseDestroysWidget(bool* destroyed)
1806 : destroyed_(destroyed) {
1809 virtual ~CloseDestroysWidget() {
1812 base::MessageLoop::current()->QuitNow();
1816 void Detach() { destroyed_ = NULL; }
1819 // If non-null set to true from destructor.
1822 DISALLOW_COPY_AND_ASSIGN(CloseDestroysWidget);
1825 // Verifies Close() results in destroying.
1826 TEST_F(WidgetTest, CloseDestroys) {
1827 bool destroyed = false;
1828 CloseDestroysWidget* widget = new CloseDestroysWidget(&destroyed);
1829 Widget::InitParams params =
1830 CreateParams(views::Widget::InitParams::TYPE_MENU);
1831 params.opacity = Widget::InitParams::OPAQUE_WINDOW;
1832 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1833 params.native_widget = new DesktopNativeWidgetAura(widget);
1835 widget->Init(params);
1839 // Run the message loop as Close() asynchronously deletes.
1840 RunPendingMessages();
1841 EXPECT_TRUE(destroyed);
1842 // Close() should destroy the widget. If not we'll cleanup to avoid leaks.
1849 // A view that consumes mouse-pressed event and gesture-tap-down events.
1850 class RootViewTestView : public View {
1852 RootViewTestView(): View() {}
1855 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
1859 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
1860 if (event->type() == ui::ET_GESTURE_TAP_DOWN)
1861 event->SetHandled();
1865 // Checks if RootView::*_handler_ fields are unset when widget is hidden.
1866 // Fails on chromium.webkit Windows bot, see crbug.com/264872.
1868 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1869 DISABLED_TestRootViewHandlersWhenHidden
1871 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1872 TestRootViewHandlersWhenHidden
1874 TEST_F(WidgetTest, MAYBE_DisableTestRootViewHandlersWhenHidden) {
1875 Widget* widget = CreateTopLevelNativeWidget();
1876 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
1877 View* view = new RootViewTestView();
1878 view->SetBounds(0, 0, 300, 300);
1879 internal::RootView* root_view =
1880 static_cast<internal::RootView*>(widget->GetRootView());
1881 root_view->AddChildView(view);
1883 // Check RootView::mouse_pressed_handler_.
1885 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
1886 gfx::Point click_location(45, 15);
1887 ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
1888 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
1889 widget->OnMouseEvent(&press);
1890 EXPECT_EQ(view, GetMousePressedHandler(root_view));
1892 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
1894 // Check RootView::mouse_move_handler_.
1896 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
1897 gfx::Point move_location(45, 15);
1898 ui::MouseEvent move(ui::ET_MOUSE_MOVED, move_location, move_location, 0, 0);
1899 widget->OnMouseEvent(&move);
1900 EXPECT_EQ(view, GetMouseMoveHandler(root_view));
1902 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
1904 // Check RootView::gesture_handler_.
1906 EXPECT_EQ(NULL, GetGestureHandler(root_view));
1907 ui::GestureEvent tap_down(
1908 ui::ET_GESTURE_TAP_DOWN,
1913 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN, 0, 0),
1915 widget->OnGestureEvent(&tap_down);
1916 EXPECT_EQ(view, GetGestureHandler(root_view));
1918 EXPECT_EQ(NULL, GetGestureHandler(root_view));
1923 // Test the result of Widget::GetAllChildWidgets().
1924 TEST_F(WidgetTest, GetAllChildWidgets) {
1925 // Create the following widget hierarchy:
1933 Widget* toplevel = CreateTopLevelPlatformWidget();
1934 Widget* w1 = CreateChildPlatformWidget(toplevel->GetNativeView());
1935 Widget* w11 = CreateChildPlatformWidget(w1->GetNativeView());
1936 Widget* w2 = CreateChildPlatformWidget(toplevel->GetNativeView());
1937 Widget* w21 = CreateChildPlatformWidget(w2->GetNativeView());
1938 Widget* w22 = CreateChildPlatformWidget(w2->GetNativeView());
1940 std::set<Widget*> expected;
1941 expected.insert(toplevel);
1942 expected.insert(w1);
1943 expected.insert(w11);
1944 expected.insert(w2);
1945 expected.insert(w21);
1946 expected.insert(w22);
1948 std::set<Widget*> widgets;
1949 Widget::GetAllChildWidgets(toplevel->GetNativeView(), &widgets);
1951 EXPECT_EQ(expected.size(), widgets.size());
1952 EXPECT_TRUE(std::equal(expected.begin(), expected.end(), widgets.begin()));
1955 // Used by DestroyChildWidgetsInOrder. On destruction adds the supplied name to
1957 class DestroyedTrackingView : public View {
1959 DestroyedTrackingView(const std::string& name,
1960 std::vector<std::string>* add_to)
1965 virtual ~DestroyedTrackingView() {
1966 add_to_->push_back(name_);
1970 const std::string name_;
1971 std::vector<std::string>* add_to_;
1973 DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingView);
1976 class WidgetChildDestructionTest : public WidgetTest {
1978 WidgetChildDestructionTest() {}
1980 // Creates a top level and a child, destroys the child and verifies the views
1981 // of the child are destroyed before the views of the parent.
1982 void RunDestroyChildWidgetsTest(bool top_level_has_desktop_native_widget_aura,
1983 bool child_has_desktop_native_widget_aura) {
1984 // When a View is destroyed its name is added here.
1985 std::vector<std::string> destroyed;
1987 Widget* top_level = new Widget;
1988 Widget::InitParams params =
1989 CreateParams(views::Widget::InitParams::TYPE_WINDOW);
1990 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1991 if (top_level_has_desktop_native_widget_aura)
1992 params.native_widget = new DesktopNativeWidgetAura(top_level);
1994 top_level->Init(params);
1995 top_level->GetRootView()->AddChildView(
1996 new DestroyedTrackingView("parent", &destroyed));
1999 Widget* child = new Widget;
2000 Widget::InitParams child_params =
2001 CreateParams(views::Widget::InitParams::TYPE_POPUP);
2002 child_params.parent = top_level->GetNativeView();
2003 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
2004 if (child_has_desktop_native_widget_aura)
2005 child_params.native_widget = new DesktopNativeWidgetAura(child);
2007 child->Init(child_params);
2008 child->GetRootView()->AddChildView(
2009 new DestroyedTrackingView("child", &destroyed));
2012 // Should trigger destruction of the child too.
2013 top_level->native_widget_private()->CloseNow();
2015 // Child should be destroyed first.
2016 ASSERT_EQ(2u, destroyed.size());
2017 EXPECT_EQ("child", destroyed[0]);
2018 EXPECT_EQ("parent", destroyed[1]);
2022 DISALLOW_COPY_AND_ASSIGN(WidgetChildDestructionTest);
2025 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
2026 // See description of RunDestroyChildWidgetsTest(). Parent uses
2027 // DesktopNativeWidgetAura.
2028 TEST_F(WidgetChildDestructionTest,
2029 DestroyChildWidgetsInOrderWithDesktopNativeWidget) {
2030 RunDestroyChildWidgetsTest(true, false);
2033 // See description of RunDestroyChildWidgetsTest(). Both parent and child use
2034 // DesktopNativeWidgetAura.
2035 TEST_F(WidgetChildDestructionTest,
2036 DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth) {
2037 RunDestroyChildWidgetsTest(true, true);
2041 // See description of RunDestroyChildWidgetsTest().
2042 TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) {
2043 RunDestroyChildWidgetsTest(false, false);
2046 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
2047 // Provides functionality to create a window modal dialog.
2048 class ModalDialogDelegate : public DialogDelegateView {
2050 ModalDialogDelegate() {}
2051 virtual ~ModalDialogDelegate() {}
2053 // WidgetDelegate overrides.
2054 virtual ui::ModalType GetModalType() const OVERRIDE {
2055 return ui::MODAL_TYPE_WINDOW;
2059 DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate);
2062 // This test verifies that whether mouse events when a modal dialog is
2063 // displayed are eaten or recieved by the dialog.
2064 TEST_F(WidgetTest, WindowMouseModalityTest) {
2065 // Create a top level widget.
2066 Widget top_level_widget;
2067 Widget::InitParams init_params =
2068 CreateParams(Widget::InitParams::TYPE_WINDOW);
2069 init_params.show_state = ui::SHOW_STATE_NORMAL;
2070 gfx::Rect initial_bounds(0, 0, 500, 500);
2071 init_params.bounds = initial_bounds;
2072 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2073 init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget);
2074 top_level_widget.Init(init_params);
2075 top_level_widget.Show();
2076 EXPECT_TRUE(top_level_widget.IsVisible());
2078 // Create a view and validate that a mouse moves makes it to the view.
2079 EventCountView* widget_view = new EventCountView();
2080 widget_view->SetBounds(0, 0, 10, 10);
2081 top_level_widget.GetRootView()->AddChildView(widget_view);
2083 gfx::Point cursor_location_main(5, 5);
2084 ui::MouseEvent move_main(ui::ET_MOUSE_MOVED,
2085 cursor_location_main,
2086 cursor_location_main,
2089 top_level_widget.GetNativeView()->GetDispatcher()->
2090 AsWindowTreeHostDelegate()->OnHostMouseEvent(&move_main);
2092 EXPECT_EQ(1, widget_view->GetEventCount(ui::ET_MOUSE_ENTERED));
2093 widget_view->ResetCounts();
2095 // Create a modal dialog and validate that a mouse down message makes it to
2096 // the main view within the dialog.
2098 // This instance will be destroyed when the dialog is destroyed.
2099 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
2101 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
2102 dialog_delegate, NULL, top_level_widget.GetNativeWindow());
2103 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
2104 EventCountView* dialog_widget_view = new EventCountView();
2105 dialog_widget_view->SetBounds(0, 0, 50, 50);
2106 modal_dialog_widget->GetRootView()->AddChildView(dialog_widget_view);
2107 modal_dialog_widget->Show();
2108 EXPECT_TRUE(modal_dialog_widget->IsVisible());
2110 gfx::Point cursor_location_dialog(100, 100);
2111 ui::MouseEvent mouse_down_dialog(ui::ET_MOUSE_PRESSED,
2112 cursor_location_dialog,
2113 cursor_location_dialog,
2116 top_level_widget.GetNativeView()->GetDispatcher()->
2117 AsWindowTreeHostDelegate()->OnHostMouseEvent(&mouse_down_dialog);
2118 EXPECT_EQ(1, dialog_widget_view->GetEventCount(ui::ET_MOUSE_PRESSED));
2120 // Send a mouse move message to the main window. It should not be received by
2121 // the main window as the modal dialog is still active.
2122 gfx::Point cursor_location_main2(6, 6);
2123 ui::MouseEvent mouse_down_main(ui::ET_MOUSE_MOVED,
2124 cursor_location_main2,
2125 cursor_location_main2,
2128 top_level_widget.GetNativeView()->GetDispatcher()->
2129 AsWindowTreeHostDelegate()->OnHostMouseEvent(&mouse_down_main);
2130 EXPECT_EQ(0, widget_view->GetEventCount(ui::ET_MOUSE_MOVED));
2132 modal_dialog_widget->CloseNow();
2133 top_level_widget.CloseNow();
2136 #if defined(USE_AURA)
2137 // Verifies nativeview visbility matches that of Widget visibility when
2138 // SetFullscreen is invoked.
2139 TEST_F(WidgetTest, FullscreenStatePropagated) {
2140 Widget::InitParams init_params =
2141 CreateParams(Widget::InitParams::TYPE_WINDOW);
2142 init_params.show_state = ui::SHOW_STATE_NORMAL;
2143 init_params.bounds = gfx::Rect(0, 0, 500, 500);
2144 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2147 Widget top_level_widget;
2148 top_level_widget.Init(init_params);
2149 top_level_widget.SetFullscreen(true);
2150 EXPECT_EQ(top_level_widget.IsVisible(),
2151 top_level_widget.GetNativeView()->IsVisible());
2152 top_level_widget.CloseNow();
2155 #if !defined(OS_CHROMEOS)
2157 Widget top_level_widget;
2158 init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget);
2159 top_level_widget.Init(init_params);
2160 top_level_widget.SetFullscreen(true);
2161 EXPECT_EQ(top_level_widget.IsVisible(),
2162 top_level_widget.GetNativeView()->IsVisible());
2163 top_level_widget.CloseNow();
2171 // Provides functionality to test widget activation via an activation flag
2172 // which can be set by an accessor.
2173 class ModalWindowTestWidgetDelegate : public WidgetDelegate {
2175 ModalWindowTestWidgetDelegate()
2177 can_activate_(true) {}
2179 virtual ~ModalWindowTestWidgetDelegate() {}
2181 // Overridden from WidgetDelegate:
2182 virtual void DeleteDelegate() OVERRIDE {
2185 virtual Widget* GetWidget() OVERRIDE {
2188 virtual const Widget* GetWidget() const OVERRIDE {
2191 virtual bool CanActivate() const OVERRIDE {
2192 return can_activate_;
2194 virtual bool ShouldAdvanceFocusToTopLevelWidget() const OVERRIDE {
2198 void set_can_activate(bool can_activate) {
2199 can_activate_ = can_activate;
2202 void set_widget(Widget* widget) {
2210 DISALLOW_COPY_AND_ASSIGN(ModalWindowTestWidgetDelegate);
2213 // Tests whether we can activate the top level widget when a modal dialog is
2215 TEST_F(WidgetTest, WindowModalityActivationTest) {
2216 // Destroyed when the top level widget created below is destroyed.
2217 ModalWindowTestWidgetDelegate* widget_delegate =
2218 new ModalWindowTestWidgetDelegate;
2219 // Create a top level widget.
2220 Widget top_level_widget;
2221 Widget::InitParams init_params =
2222 CreateParams(Widget::InitParams::TYPE_WINDOW);
2223 init_params.show_state = ui::SHOW_STATE_NORMAL;
2224 gfx::Rect initial_bounds(0, 0, 500, 500);
2225 init_params.bounds = initial_bounds;
2226 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2227 init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget);
2228 init_params.delegate = widget_delegate;
2229 top_level_widget.Init(init_params);
2230 widget_delegate->set_widget(&top_level_widget);
2231 top_level_widget.Show();
2232 EXPECT_TRUE(top_level_widget.IsVisible());
2234 HWND win32_window = views::HWNDForWidget(&top_level_widget);
2235 EXPECT_TRUE(::IsWindow(win32_window));
2237 // This instance will be destroyed when the dialog is destroyed.
2238 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
2240 // We should be able to activate the window even if the WidgetDelegate
2241 // says no, when a modal dialog is active.
2242 widget_delegate->set_can_activate(false);
2244 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
2245 dialog_delegate, NULL, top_level_widget.GetNativeWindow());
2246 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
2247 modal_dialog_widget->Show();
2248 EXPECT_TRUE(modal_dialog_widget->IsVisible());
2250 LRESULT activate_result = ::SendMessage(
2253 reinterpret_cast<WPARAM>(win32_window),
2254 MAKELPARAM(WM_LBUTTONDOWN, HTCLIENT));
2255 EXPECT_EQ(activate_result, MA_ACTIVATE);
2257 modal_dialog_widget->CloseNow();
2258 top_level_widget.CloseNow();
2263 TEST_F(WidgetTest, ShowCreatesActiveWindow) {
2264 Widget* widget = CreateTopLevelPlatformWidget();
2267 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2272 TEST_F(WidgetTest, ShowInactive) {
2273 Widget* widget = CreateTopLevelPlatformWidget();
2275 widget->ShowInactive();
2276 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_INACTIVE);
2281 TEST_F(WidgetTest, ShowInactiveAfterShow) {
2282 Widget* widget = CreateTopLevelPlatformWidget();
2285 widget->ShowInactive();
2286 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2291 TEST_F(WidgetTest, ShowAfterShowInactive) {
2292 Widget* widget = CreateTopLevelPlatformWidget();
2294 widget->ShowInactive();
2296 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2301 #if defined(OS_WIN) && defined(USE_AURA)
2302 TEST_F(WidgetTest, InactiveWidgetDoesNotGrabActivation) {
2303 Widget* widget = CreateTopLevelPlatformWidget();
2305 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2308 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2309 params.can_activate = false;
2310 params.native_widget = new DesktopNativeWidgetAura(&widget2);
2311 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2312 widget2.Init(params);
2315 EXPECT_EQ(GetWidgetShowState(&widget2), ui::SHOW_STATE_INACTIVE);
2316 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2325 class FullscreenAwareFrame : public views::NonClientFrameView {
2327 explicit FullscreenAwareFrame(views::Widget* widget)
2328 : widget_(widget), fullscreen_layout_called_(false) {}
2329 virtual ~FullscreenAwareFrame() {}
2331 // views::NonClientFrameView overrides:
2332 virtual gfx::Rect GetBoundsForClientView() const OVERRIDE {
2335 virtual gfx::Rect GetWindowBoundsForClientBounds(
2336 const gfx::Rect& client_bounds) const OVERRIDE {
2339 virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE {
2342 virtual void GetWindowMask(const gfx::Size& size,
2343 gfx::Path* window_mask) OVERRIDE {}
2344 virtual void ResetWindowControls() OVERRIDE {}
2345 virtual void UpdateWindowIcon() OVERRIDE {}
2346 virtual void UpdateWindowTitle() OVERRIDE {}
2348 // views::View overrides:
2349 virtual void Layout() OVERRIDE {
2350 if (widget_->IsFullscreen())
2351 fullscreen_layout_called_ = true;
2354 bool fullscreen_layout_called() const { return fullscreen_layout_called_; }
2357 views::Widget* widget_;
2358 bool fullscreen_layout_called_;
2360 DISALLOW_COPY_AND_ASSIGN(FullscreenAwareFrame);
2365 // Tests that frame Layout is called when a widget goes fullscreen without
2366 // changing its size or title.
2367 TEST_F(WidgetTest, FullscreenFrameLayout) {
2368 Widget* widget = CreateTopLevelPlatformWidget();
2369 FullscreenAwareFrame* frame = new FullscreenAwareFrame(widget);
2370 widget->non_client_view()->SetFrameView(frame); // Owns |frame|.
2373 RunPendingMessages();
2375 EXPECT_FALSE(frame->fullscreen_layout_called());
2376 widget->SetFullscreen(true);
2378 RunPendingMessages();
2379 EXPECT_TRUE(frame->fullscreen_layout_called());
2385 } // namespace views