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/aura/test/event_generator.h"
16 #include "ui/aura/window.h"
17 #include "ui/base/hit_test.h"
18 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
19 #include "ui/compositor/scoped_layer_animation_settings.h"
20 #include "ui/events/event_processor.h"
21 #include "ui/events/event_utils.h"
22 #include "ui/gfx/native_widget_types.h"
23 #include "ui/gfx/point.h"
24 #include "ui/views/bubble/bubble_delegate.h"
25 #include "ui/views/controls/textfield/textfield.h"
26 #include "ui/views/test/test_views_delegate.h"
27 #include "ui/views/test/widget_test.h"
28 #include "ui/views/views_delegate.h"
29 #include "ui/views/widget/native_widget_delegate.h"
30 #include "ui/views/widget/root_view.h"
31 #include "ui/views/widget/widget_deletion_observer.h"
32 #include "ui/views/window/dialog_delegate.h"
33 #include "ui/views/window/native_frame_view.h"
36 #include "ui/views/win/hwnd_util.h"
42 // A view that keeps track of the events it receives, but consumes no events.
43 class EventCountView : public View {
46 virtual ~EventCountView() {}
48 int GetEventCount(ui::EventType type) {
49 return event_count_[type];
57 // Overridden from ui::EventHandler:
58 virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
61 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
64 virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE {
67 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
72 void RecordEvent(const ui::Event& event) {
73 ++event_count_[event.type()];
76 std::map<ui::EventType, int> event_count_;
78 DISALLOW_COPY_AND_ASSIGN(EventCountView);
81 // A view that keeps track of the events it receives, and consumes all scroll
82 // gesture events and ui::ET_SCROLL events.
83 class ScrollableEventCountView : public EventCountView {
85 ScrollableEventCountView() {}
86 virtual ~ScrollableEventCountView() {}
89 // Overridden from ui::EventHandler:
90 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
91 EventCountView::OnGestureEvent(event);
92 switch (event->type()) {
93 case ui::ET_GESTURE_SCROLL_BEGIN:
94 case ui::ET_GESTURE_SCROLL_UPDATE:
95 case ui::ET_GESTURE_SCROLL_END:
96 case ui::ET_SCROLL_FLING_START:
104 virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE {
105 EventCountView::OnScrollEvent(event);
106 if (event->type() == ui::ET_SCROLL)
110 DISALLOW_COPY_AND_ASSIGN(ScrollableEventCountView);
113 // A view that implements GetMinimumSize.
114 class MinimumSizeFrameView : public NativeFrameView {
116 explicit MinimumSizeFrameView(Widget* frame): NativeFrameView(frame) {}
117 virtual ~MinimumSizeFrameView() {}
120 // Overridden from View:
121 virtual gfx::Size GetMinimumSize() const OVERRIDE {
122 return gfx::Size(300, 400);
125 DISALLOW_COPY_AND_ASSIGN(MinimumSizeFrameView);
128 // An event handler that simply keeps a count of the different types of events
130 class EventCountHandler : public ui::EventHandler {
132 EventCountHandler() {}
133 virtual ~EventCountHandler() {}
135 int GetEventCount(ui::EventType type) {
136 return event_count_[type];
140 event_count_.clear();
144 // Overridden from ui::EventHandler:
145 virtual void OnEvent(ui::Event* event) OVERRIDE {
147 ui::EventHandler::OnEvent(event);
151 void RecordEvent(const ui::Event& event) {
152 ++event_count_[event.type()];
155 std::map<ui::EventType, int> event_count_;
157 DISALLOW_COPY_AND_ASSIGN(EventCountHandler);
160 // Class that closes the widget (which ends up deleting it immediately) when the
161 // appropriate event is received.
162 class CloseWidgetView : public View {
164 explicit CloseWidgetView(ui::EventType event_type)
165 : event_type_(event_type) {
168 // ui::EventHandler override:
169 virtual void OnEvent(ui::Event* event) OVERRIDE {
170 if (event->type() == event_type_) {
171 // Go through NativeWidgetPrivate to simulate what happens if the OS
172 // deletes the NativeWindow out from under us.
173 GetWidget()->native_widget_private()->CloseNow();
175 View::OnEvent(event);
176 if (!event->IsTouchEvent())
182 const ui::EventType event_type_;
184 DISALLOW_COPY_AND_ASSIGN(CloseWidgetView);
187 ui::WindowShowState GetWidgetShowState(const Widget* widget) {
188 // Use IsMaximized/IsMinimized/IsFullScreen instead of GetWindowPlacement
189 // because the former is implemented on all platforms but the latter is not.
190 return widget->IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN :
191 widget->IsMaximized() ? ui::SHOW_STATE_MAXIMIZED :
192 widget->IsMinimized() ? ui::SHOW_STATE_MINIMIZED :
193 widget->IsActive() ? ui::SHOW_STATE_NORMAL :
194 ui::SHOW_STATE_INACTIVE;
197 TEST_F(WidgetTest, WidgetInitParams) {
198 // Widgets are not transparent by default.
199 Widget::InitParams init1;
200 EXPECT_EQ(Widget::InitParams::INFER_OPACITY, init1.opacity);
203 ////////////////////////////////////////////////////////////////////////////////
204 // Widget::GetTopLevelWidget tests.
206 TEST_F(WidgetTest, GetTopLevelWidget_Native) {
207 // Create a hierarchy of native widgets.
208 Widget* toplevel = CreateTopLevelPlatformWidget();
209 gfx::NativeView parent = toplevel->GetNativeView();
210 Widget* child = CreateChildPlatformWidget(parent);
212 EXPECT_EQ(toplevel, toplevel->GetTopLevelWidget());
213 EXPECT_EQ(toplevel, child->GetTopLevelWidget());
215 toplevel->CloseNow();
216 // |child| should be automatically destroyed with |toplevel|.
219 // Test if a focus manager and an inputmethod work without CHECK failure
220 // when window activation changes.
221 TEST_F(WidgetTest, ChangeActivation) {
222 Widget* top1 = CreateTopLevelPlatformWidget();
223 // CreateInputMethod before activated
224 top1->GetInputMethod();
226 RunPendingMessages();
228 Widget* top2 = CreateTopLevelPlatformWidget();
230 RunPendingMessages();
233 RunPendingMessages();
235 // Create InputMethod after deactivated.
236 top2->GetInputMethod();
238 RunPendingMessages();
241 RunPendingMessages();
247 // Tests visibility of child widgets.
248 TEST_F(WidgetTest, Visibility) {
249 Widget* toplevel = CreateTopLevelPlatformWidget();
250 gfx::NativeView parent = toplevel->GetNativeView();
251 Widget* child = CreateChildPlatformWidget(parent);
253 EXPECT_FALSE(toplevel->IsVisible());
254 EXPECT_FALSE(child->IsVisible());
258 EXPECT_FALSE(toplevel->IsVisible());
259 EXPECT_FALSE(child->IsVisible());
263 EXPECT_TRUE(toplevel->IsVisible());
264 EXPECT_TRUE(child->IsVisible());
266 toplevel->CloseNow();
267 // |child| should be automatically destroyed with |toplevel|.
270 ////////////////////////////////////////////////////////////////////////////////
271 // Widget ownership tests.
273 // Tests various permutations of Widget ownership specified in the
274 // InitParams::Ownership param.
276 // A WidgetTest that supplies a toplevel widget for NativeWidget to parent to.
277 class WidgetOwnershipTest : public WidgetTest {
279 WidgetOwnershipTest() {}
280 virtual ~WidgetOwnershipTest() {}
282 virtual void SetUp() {
284 desktop_widget_ = CreateTopLevelPlatformWidget();
287 virtual void TearDown() {
288 desktop_widget_->CloseNow();
289 WidgetTest::TearDown();
293 Widget* desktop_widget_;
295 DISALLOW_COPY_AND_ASSIGN(WidgetOwnershipTest);
298 // A bag of state to monitor destructions.
299 struct OwnershipTestState {
300 OwnershipTestState() : widget_deleted(false), native_widget_deleted(false) {}
303 bool native_widget_deleted;
306 // A platform NativeWidget subclass that updates a bag of state when it is
308 class OwnershipTestNativeWidget : public PlatformNativeWidget {
310 OwnershipTestNativeWidget(internal::NativeWidgetDelegate* delegate,
311 OwnershipTestState* state)
312 : PlatformNativeWidget(delegate),
315 virtual ~OwnershipTestNativeWidget() {
316 state_->native_widget_deleted = true;
320 OwnershipTestState* state_;
322 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidget);
325 // A views NativeWidget subclass that updates a bag of state when it is
327 class OwnershipTestNativeWidgetAura : public NativeWidgetCapture {
329 OwnershipTestNativeWidgetAura(internal::NativeWidgetDelegate* delegate,
330 OwnershipTestState* state)
331 : NativeWidgetCapture(delegate),
334 virtual ~OwnershipTestNativeWidgetAura() {
335 state_->native_widget_deleted = true;
339 OwnershipTestState* state_;
341 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetAura);
344 // A Widget subclass that updates a bag of state when it is destroyed.
345 class OwnershipTestWidget : public Widget {
347 explicit OwnershipTestWidget(OwnershipTestState* state) : state_(state) {}
348 virtual ~OwnershipTestWidget() {
349 state_->widget_deleted = true;
353 OwnershipTestState* state_;
355 DISALLOW_COPY_AND_ASSIGN(OwnershipTestWidget);
358 // Widget owns its NativeWidget, part 1: NativeWidget is a platform-native
360 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsPlatformNativeWidget) {
361 OwnershipTestState state;
363 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
364 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
365 params.native_widget =
366 new OwnershipTestNativeWidgetAura(widget.get(), &state);
367 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
368 widget->Init(params);
370 // Now delete the Widget, which should delete the NativeWidget.
373 EXPECT_TRUE(state.widget_deleted);
374 EXPECT_TRUE(state.native_widget_deleted);
376 // TODO(beng): write test for this ownership scenario and the NativeWidget
377 // being deleted out from under the Widget.
380 // Widget owns its NativeWidget, part 2: NativeWidget is a NativeWidget.
381 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsViewsNativeWidget) {
382 OwnershipTestState state;
384 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
385 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
386 params.native_widget =
387 new OwnershipTestNativeWidgetAura(widget.get(), &state);
388 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
389 widget->Init(params);
391 // Now delete the Widget, which should delete the NativeWidget.
394 EXPECT_TRUE(state.widget_deleted);
395 EXPECT_TRUE(state.native_widget_deleted);
397 // TODO(beng): write test for this ownership scenario and the NativeWidget
398 // being deleted out from under the Widget.
401 // Widget owns its NativeWidget, part 3: NativeWidget is a NativeWidget,
402 // destroy the parent view.
403 TEST_F(WidgetOwnershipTest,
404 Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView) {
405 OwnershipTestState state;
407 Widget* toplevel = CreateTopLevelPlatformWidget();
409 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
410 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
411 params.native_widget =
412 new OwnershipTestNativeWidgetAura(widget.get(), &state);
413 params.parent = toplevel->GetNativeView();
414 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
415 widget->Init(params);
417 // Now close the toplevel, which deletes the view hierarchy.
418 toplevel->CloseNow();
420 RunPendingMessages();
422 // This shouldn't delete the widget because it shouldn't be deleted
423 // from the native side.
424 EXPECT_FALSE(state.widget_deleted);
425 EXPECT_FALSE(state.native_widget_deleted);
427 // Now delete it explicitly.
430 EXPECT_TRUE(state.widget_deleted);
431 EXPECT_TRUE(state.native_widget_deleted);
434 // NativeWidget owns its Widget, part 1: NativeWidget is a platform-native
436 TEST_F(WidgetOwnershipTest, Ownership_PlatformNativeWidgetOwnsWidget) {
437 OwnershipTestState state;
439 Widget* widget = new OwnershipTestWidget(&state);
440 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
441 params.native_widget =
442 new OwnershipTestNativeWidgetAura(widget, &state);
443 widget->Init(params);
445 // Now destroy the native widget.
448 EXPECT_TRUE(state.widget_deleted);
449 EXPECT_TRUE(state.native_widget_deleted);
452 // NativeWidget owns its Widget, part 2: NativeWidget is a NativeWidget.
453 TEST_F(WidgetOwnershipTest, Ownership_ViewsNativeWidgetOwnsWidget) {
454 OwnershipTestState state;
456 Widget* toplevel = CreateTopLevelPlatformWidget();
458 Widget* widget = new OwnershipTestWidget(&state);
459 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
460 params.native_widget =
461 new OwnershipTestNativeWidgetAura(widget, &state);
462 params.parent = toplevel->GetNativeView();
463 widget->Init(params);
465 // Now destroy the native widget. This is achieved by closing the toplevel.
466 toplevel->CloseNow();
468 // The NativeWidget won't be deleted until after a return to the message loop
469 // so we have to run pending messages before testing the destruction status.
470 RunPendingMessages();
472 EXPECT_TRUE(state.widget_deleted);
473 EXPECT_TRUE(state.native_widget_deleted);
476 // NativeWidget owns its Widget, part 3: NativeWidget is a platform-native
477 // widget, destroyed out from under it by the OS.
478 TEST_F(WidgetOwnershipTest,
479 Ownership_PlatformNativeWidgetOwnsWidget_NativeDestroy) {
480 OwnershipTestState state;
482 Widget* widget = new OwnershipTestWidget(&state);
483 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
484 params.native_widget =
485 new OwnershipTestNativeWidgetAura(widget, &state);
486 widget->Init(params);
488 // Now simulate a destroy of the platform native widget from the OS:
489 SimulateNativeDestroy(widget);
491 EXPECT_TRUE(state.widget_deleted);
492 EXPECT_TRUE(state.native_widget_deleted);
495 // NativeWidget owns its Widget, part 4: NativeWidget is a NativeWidget,
496 // destroyed by the view hierarchy that contains it.
497 TEST_F(WidgetOwnershipTest,
498 Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy) {
499 OwnershipTestState state;
501 Widget* toplevel = CreateTopLevelPlatformWidget();
503 Widget* widget = new OwnershipTestWidget(&state);
504 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
505 params.native_widget =
506 new OwnershipTestNativeWidgetAura(widget, &state);
507 params.parent = toplevel->GetNativeView();
508 widget->Init(params);
510 // Destroy the widget (achieved by closing the toplevel).
511 toplevel->CloseNow();
513 // The NativeWidget won't be deleted until after a return to the message loop
514 // so we have to run pending messages before testing the destruction status.
515 RunPendingMessages();
517 EXPECT_TRUE(state.widget_deleted);
518 EXPECT_TRUE(state.native_widget_deleted);
521 // NativeWidget owns its Widget, part 5: NativeWidget is a NativeWidget,
522 // we close it directly.
523 TEST_F(WidgetOwnershipTest,
524 Ownership_ViewsNativeWidgetOwnsWidget_Close) {
525 OwnershipTestState state;
527 Widget* toplevel = CreateTopLevelPlatformWidget();
529 Widget* widget = new OwnershipTestWidget(&state);
530 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
531 params.native_widget =
532 new OwnershipTestNativeWidgetAura(widget, &state);
533 params.parent = toplevel->GetNativeView();
534 widget->Init(params);
536 // Destroy the widget.
538 toplevel->CloseNow();
540 // The NativeWidget won't be deleted until after a return to the message loop
541 // so we have to run pending messages before testing the destruction status.
542 RunPendingMessages();
544 EXPECT_TRUE(state.widget_deleted);
545 EXPECT_TRUE(state.native_widget_deleted);
548 // Widget owns its NativeWidget and has a WidgetDelegateView as its contents.
549 TEST_F(WidgetOwnershipTest,
550 Ownership_WidgetOwnsNativeWidgetWithWithWidgetDelegateView) {
551 OwnershipTestState state;
553 WidgetDelegateView* delegate_view = new WidgetDelegateView;
555 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
556 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
557 params.native_widget =
558 new OwnershipTestNativeWidgetAura(widget.get(), &state);
559 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
560 params.delegate = delegate_view;
561 widget->Init(params);
562 widget->SetContentsView(delegate_view);
564 // Now delete the Widget. There should be no crash or use-after-free.
567 EXPECT_TRUE(state.widget_deleted);
568 EXPECT_TRUE(state.native_widget_deleted);
571 ////////////////////////////////////////////////////////////////////////////////
572 // Test to verify using various Widget methods doesn't crash when the underlying
573 // NativeView is destroyed.
575 class WidgetWithDestroyedNativeViewTest : public ViewsTestBase {
577 WidgetWithDestroyedNativeViewTest() {}
578 virtual ~WidgetWithDestroyedNativeViewTest() {}
580 void InvokeWidgetMethods(Widget* widget) {
581 widget->GetNativeView();
582 widget->GetNativeWindow();
583 ui::Accelerator accelerator;
584 widget->GetAccelerator(0, &accelerator);
585 widget->GetTopLevelWidget();
586 widget->GetWindowBoundsInScreen();
587 widget->GetClientAreaBoundsInScreen();
588 widget->SetBounds(gfx::Rect(0, 0, 100, 80));
589 widget->SetSize(gfx::Size(10, 11));
590 widget->SetBoundsConstrained(gfx::Rect(0, 0, 120, 140));
591 widget->SetVisibilityChangedAnimationsEnabled(false);
592 widget->StackAtTop();
597 widget->Deactivate();
599 widget->DisableInactiveRendering();
600 widget->SetAlwaysOnTop(true);
601 widget->IsAlwaysOnTop();
605 widget->IsMaximized();
606 widget->IsFullscreen();
607 widget->SetOpacity(0);
608 widget->SetUseDragFrame(true);
609 widget->FlashFrame(true);
611 widget->GetThemeProvider();
612 widget->GetNativeTheme();
613 widget->GetFocusManager();
614 widget->GetInputMethod();
615 widget->SchedulePaintInRect(gfx::Rect(0, 0, 1, 2));
616 widget->IsMouseEventsEnabled();
617 widget->SetNativeWindowProperty("xx", widget);
618 widget->GetNativeWindowProperty("xx");
619 widget->GetFocusTraversable();
621 widget->ReorderNativeViews();
622 widget->SetCapture(widget->GetRootView());
623 widget->ReleaseCapture();
624 widget->HasCapture();
625 widget->GetWorkAreaBoundsInScreen();
626 widget->IsTranslucentWindowOpacitySupported();
630 DISALLOW_COPY_AND_ASSIGN(WidgetWithDestroyedNativeViewTest);
633 TEST_F(WidgetWithDestroyedNativeViewTest, Test) {
636 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
637 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
641 widget.native_widget_private()->CloseNow();
642 InvokeWidgetMethods(&widget);
644 #if !defined(OS_CHROMEOS)
647 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
648 params.native_widget = new PlatformDesktopNativeWidget(&widget);
649 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
653 widget.native_widget_private()->CloseNow();
654 InvokeWidgetMethods(&widget);
659 ////////////////////////////////////////////////////////////////////////////////
660 // Widget observer tests.
663 class WidgetObserverTest : public WidgetTest, public WidgetObserver {
667 widget_closed_(NULL),
668 widget_activated_(NULL),
670 widget_hidden_(NULL),
671 widget_bounds_changed_(NULL) {
674 virtual ~WidgetObserverTest() {}
676 // Overridden from WidgetObserver:
677 virtual void OnWidgetDestroying(Widget* widget) OVERRIDE {
678 if (active_ == widget)
680 widget_closed_ = widget;
683 virtual void OnWidgetActivationChanged(Widget* widget,
684 bool active) OVERRIDE {
686 if (widget_activated_)
687 widget_activated_->Deactivate();
688 widget_activated_ = widget;
691 if (widget_activated_ == widget)
692 widget_activated_ = NULL;
693 widget_deactivated_ = widget;
697 virtual void OnWidgetVisibilityChanged(Widget* widget,
698 bool visible) OVERRIDE {
700 widget_shown_ = widget;
702 widget_hidden_ = widget;
705 virtual void OnWidgetBoundsChanged(Widget* widget,
706 const gfx::Rect& new_bounds) OVERRIDE {
707 widget_bounds_changed_ = widget;
712 widget_closed_ = NULL;
713 widget_activated_ = NULL;
714 widget_deactivated_ = NULL;
715 widget_shown_ = NULL;
716 widget_hidden_ = NULL;
717 widget_bounds_changed_ = NULL;
720 Widget* NewWidget() {
721 Widget* widget = CreateTopLevelNativeWidget();
722 widget->AddObserver(this);
726 const Widget* active() const { return active_; }
727 const Widget* widget_closed() const { return widget_closed_; }
728 const Widget* widget_activated() const { return widget_activated_; }
729 const Widget* widget_deactivated() const { return widget_deactivated_; }
730 const Widget* widget_shown() const { return widget_shown_; }
731 const Widget* widget_hidden() const { return widget_hidden_; }
732 const Widget* widget_bounds_changed() const { return widget_bounds_changed_; }
737 Widget* widget_closed_;
738 Widget* widget_activated_;
739 Widget* widget_deactivated_;
740 Widget* widget_shown_;
741 Widget* widget_hidden_;
742 Widget* widget_bounds_changed_;
745 TEST_F(WidgetObserverTest, DISABLED_ActivationChange) {
746 Widget* toplevel = CreateTopLevelPlatformWidget();
748 Widget* toplevel1 = NewWidget();
749 Widget* toplevel2 = NewWidget();
756 toplevel1->Activate();
758 RunPendingMessages();
759 EXPECT_EQ(toplevel1, widget_activated());
761 toplevel2->Activate();
762 RunPendingMessages();
763 EXPECT_EQ(toplevel1, widget_deactivated());
764 EXPECT_EQ(toplevel2, widget_activated());
765 EXPECT_EQ(toplevel2, active());
767 toplevel->CloseNow();
770 TEST_F(WidgetObserverTest, DISABLED_VisibilityChange) {
771 Widget* toplevel = CreateTopLevelPlatformWidget();
773 Widget* child1 = NewWidget();
774 Widget* child2 = NewWidget();
783 EXPECT_EQ(child1, widget_hidden());
786 EXPECT_EQ(child2, widget_hidden());
789 EXPECT_EQ(child1, widget_shown());
792 EXPECT_EQ(child2, widget_shown());
794 toplevel->CloseNow();
797 TEST_F(WidgetObserverTest, DestroyBubble) {
798 Widget* anchor = CreateTopLevelPlatformWidget();
801 BubbleDelegateView* bubble_delegate =
802 new BubbleDelegateView(anchor->client_view(), BubbleBorder::NONE);
803 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
804 bubble_widget->Show();
805 bubble_widget->CloseNow();
811 TEST_F(WidgetObserverTest, WidgetBoundsChanged) {
812 Widget* child1 = NewWidget();
813 Widget* child2 = NewWidget();
815 child1->OnNativeWidgetMove();
816 EXPECT_EQ(child1, widget_bounds_changed());
818 child2->OnNativeWidgetMove();
819 EXPECT_EQ(child2, widget_bounds_changed());
821 child1->OnNativeWidgetSizeChanged(gfx::Size());
822 EXPECT_EQ(child1, widget_bounds_changed());
824 child2->OnNativeWidgetSizeChanged(gfx::Size());
825 EXPECT_EQ(child2, widget_bounds_changed());
829 // Aura needs shell to maximize/fullscreen window.
830 // NativeWidgetGtk doesn't implement GetRestoredBounds.
831 TEST_F(WidgetTest, GetRestoredBounds) {
832 Widget* toplevel = CreateTopLevelPlatformWidget();
833 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
834 toplevel->GetRestoredBounds().ToString());
836 toplevel->Maximize();
837 RunPendingMessages();
838 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
839 toplevel->GetRestoredBounds().ToString());
840 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
841 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
844 RunPendingMessages();
845 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
846 toplevel->GetRestoredBounds().ToString());
848 toplevel->SetFullscreen(true);
849 RunPendingMessages();
850 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
851 toplevel->GetRestoredBounds().ToString());
852 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
853 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
857 // Test that window state is not changed after getting out of full screen.
858 TEST_F(WidgetTest, ExitFullscreenRestoreState) {
859 Widget* toplevel = CreateTopLevelPlatformWidget();
862 RunPendingMessages();
864 // This should be a normal state window.
865 EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
867 toplevel->SetFullscreen(true);
868 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
869 toplevel->SetFullscreen(false);
870 EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
872 // And it should still be in normal state after getting out of full screen.
873 EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
875 // Now, make it maximized.
876 toplevel->Maximize();
877 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
879 toplevel->SetFullscreen(true);
880 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
881 toplevel->SetFullscreen(false);
882 EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
884 // And it stays maximized after getting out of full screen.
885 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
889 RunPendingMessages();
892 // The key-event propagation from Widget happens differently on aura and
893 // non-aura systems because of the difference in IME. So this test works only on
895 TEST_F(WidgetTest, KeyboardInputEvent) {
896 Widget* toplevel = CreateTopLevelPlatformWidget();
897 View* container = toplevel->client_view();
899 Textfield* textfield = new Textfield();
900 textfield->SetText(base::ASCIIToUTF16("some text"));
901 container->AddChildView(textfield);
903 textfield->RequestFocus();
905 // The press gets handled. The release doesn't have an effect.
906 ui::KeyEvent backspace_p(ui::ET_KEY_PRESSED, ui::VKEY_DELETE, 0, false);
907 toplevel->OnKeyEvent(&backspace_p);
908 EXPECT_TRUE(backspace_p.stopped_propagation());
909 ui::KeyEvent backspace_r(ui::ET_KEY_RELEASED, ui::VKEY_DELETE, 0, false);
910 toplevel->OnKeyEvent(&backspace_r);
911 EXPECT_FALSE(backspace_r.handled());
916 // Verifies bubbles result in a focus lost when shown.
917 // TODO(msw): this tests relies on focus, it needs to be in
918 // interactive_ui_tests.
919 TEST_F(WidgetTest, DISABLED_FocusChangesOnBubble) {
920 // Create a widget, show and activate it and focus the contents view.
921 View* contents_view = new View;
922 contents_view->SetFocusable(true);
924 Widget::InitParams init_params =
925 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
926 init_params.bounds = gfx::Rect(0, 0, 200, 200);
927 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
928 #if !defined(OS_CHROMEOS)
929 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
931 widget.Init(init_params);
932 widget.SetContentsView(contents_view);
935 contents_view->RequestFocus();
936 EXPECT_TRUE(contents_view->HasFocus());
939 BubbleDelegateView* bubble_delegate_view =
940 new BubbleDelegateView(contents_view, BubbleBorder::TOP_LEFT);
941 bubble_delegate_view->SetFocusable(true);
942 BubbleDelegateView::CreateBubble(bubble_delegate_view)->Show();
943 bubble_delegate_view->RequestFocus();
945 // |contents_view_| should no longer have focus.
946 EXPECT_FALSE(contents_view->HasFocus());
947 EXPECT_TRUE(bubble_delegate_view->HasFocus());
949 bubble_delegate_view->GetWidget()->CloseNow();
951 // Closing the bubble should result in focus going back to the contents view.
952 EXPECT_TRUE(contents_view->HasFocus());
955 class TestBubbleDelegateView : public BubbleDelegateView {
957 TestBubbleDelegateView(View* anchor)
958 : BubbleDelegateView(anchor, BubbleBorder::NONE),
959 reset_controls_called_(false) {}
960 virtual ~TestBubbleDelegateView() {}
962 virtual bool ShouldShowCloseButton() const OVERRIDE {
963 reset_controls_called_ = true;
967 mutable bool reset_controls_called_;
970 TEST_F(WidgetTest, BubbleControlsResetOnInit) {
971 Widget* anchor = CreateTopLevelPlatformWidget();
974 TestBubbleDelegateView* bubble_delegate =
975 new TestBubbleDelegateView(anchor->client_view());
976 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
977 EXPECT_TRUE(bubble_delegate->reset_controls_called_);
978 bubble_widget->Show();
979 bubble_widget->CloseNow();
985 // Desktop native widget Aura tests are for non Chrome OS platforms.
986 #if !defined(OS_CHROMEOS)
987 // Test to ensure that after minimize, view width is set to zero.
988 TEST_F(WidgetTest, TestViewWidthAfterMinimizingWidget) {
991 Widget::InitParams init_params =
992 CreateParams(Widget::InitParams::TYPE_WINDOW);
993 init_params.show_state = ui::SHOW_STATE_NORMAL;
994 gfx::Rect initial_bounds(0, 0, 300, 400);
995 init_params.bounds = initial_bounds;
996 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
997 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
998 widget.Init(init_params);
999 NonClientView* non_client_view = widget.non_client_view();
1000 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1001 non_client_view->SetFrameView(frame_view);
1004 EXPECT_EQ(0, frame_view->width());
1007 // This class validates whether paints are received for a visible Widget.
1008 // To achieve this it overrides the Show and Close methods on the Widget class
1009 // and sets state whether subsequent paints are expected.
1010 class DesktopAuraTestValidPaintWidget : public views::Widget {
1012 DesktopAuraTestValidPaintWidget()
1013 : expect_paint_(true),
1014 received_paint_while_hidden_(false) {
1017 virtual ~DesktopAuraTestValidPaintWidget() {
1020 virtual void Show() OVERRIDE {
1021 expect_paint_ = true;
1022 views::Widget::Show();
1025 virtual void Close() OVERRIDE {
1026 expect_paint_ = false;
1027 views::Widget::Close();
1031 expect_paint_ = false;
1032 views::Widget::Hide();
1035 virtual void OnNativeWidgetPaint(gfx::Canvas* canvas) OVERRIDE {
1036 EXPECT_TRUE(expect_paint_);
1038 received_paint_while_hidden_ = true;
1039 views::Widget::OnNativeWidgetPaint(canvas);
1042 bool received_paint_while_hidden() const {
1043 return received_paint_while_hidden_;
1048 bool received_paint_while_hidden_;
1051 TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterCloseTest) {
1052 View* contents_view = new View;
1053 contents_view->SetFocusable(true);
1054 DesktopAuraTestValidPaintWidget widget;
1055 Widget::InitParams init_params =
1056 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1057 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1058 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1059 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1060 widget.Init(init_params);
1061 widget.SetContentsView(contents_view);
1064 RunPendingMessages();
1065 widget.SchedulePaintInRect(init_params.bounds);
1067 RunPendingMessages();
1068 EXPECT_FALSE(widget.received_paint_while_hidden());
1071 TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterHideTest) {
1072 View* contents_view = new View;
1073 contents_view->SetFocusable(true);
1074 DesktopAuraTestValidPaintWidget widget;
1075 Widget::InitParams init_params =
1076 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1077 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1078 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1079 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1080 widget.Init(init_params);
1081 widget.SetContentsView(contents_view);
1084 RunPendingMessages();
1085 widget.SchedulePaintInRect(init_params.bounds);
1087 RunPendingMessages();
1088 EXPECT_FALSE(widget.received_paint_while_hidden());
1092 // Test to ensure that the aura Window's visiblity state is set to visible if
1093 // the underlying widget is hidden and then shown.
1094 TEST_F(WidgetTest, TestWindowVisibilityAfterHide) {
1097 Widget::InitParams init_params =
1098 CreateParams(Widget::InitParams::TYPE_WINDOW);
1099 init_params.show_state = ui::SHOW_STATE_NORMAL;
1100 gfx::Rect initial_bounds(0, 0, 300, 400);
1101 init_params.bounds = initial_bounds;
1102 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1103 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1104 widget.Init(init_params);
1105 NonClientView* non_client_view = widget.non_client_view();
1106 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1107 non_client_view->SetFrameView(frame_view);
1110 EXPECT_FALSE(IsNativeWindowVisible(widget.GetNativeWindow()));
1112 EXPECT_TRUE(IsNativeWindowVisible(widget.GetNativeWindow()));
1115 // The following code verifies we can correctly destroy a Widget from a mouse
1116 // enter/exit. We could test move/drag/enter/exit but in general we don't run
1117 // nested message loops from such events, nor has the code ever really dealt
1118 // with this situation.
1120 // Generates two moves (first generates enter, second real move), a press, drag
1121 // and release stopping at |last_event_type|.
1122 void GenerateMouseEvents(Widget* widget, ui::EventType last_event_type) {
1123 const gfx::Rect screen_bounds(widget->GetWindowBoundsInScreen());
1124 ui::MouseEvent move_event(ui::ET_MOUSE_MOVED, screen_bounds.CenterPoint(),
1125 screen_bounds.CenterPoint(), 0, 0);
1126 ui::EventProcessor* dispatcher = WidgetTest::GetEventProcessor(widget);
1127 ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&move_event);
1128 if (last_event_type == ui::ET_MOUSE_ENTERED || details.dispatcher_destroyed)
1130 details = dispatcher->OnEventFromSource(&move_event);
1131 if (last_event_type == ui::ET_MOUSE_MOVED || details.dispatcher_destroyed)
1134 ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, screen_bounds.CenterPoint(),
1135 screen_bounds.CenterPoint(), 0, 0);
1136 details = dispatcher->OnEventFromSource(&press_event);
1137 if (last_event_type == ui::ET_MOUSE_PRESSED || details.dispatcher_destroyed)
1140 gfx::Point end_point(screen_bounds.CenterPoint());
1141 end_point.Offset(1, 1);
1142 ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, end_point, end_point, 0, 0);
1143 details = dispatcher->OnEventFromSource(&drag_event);
1144 if (last_event_type == ui::ET_MOUSE_DRAGGED || details.dispatcher_destroyed)
1147 ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, end_point, end_point, 0,
1149 details = dispatcher->OnEventFromSource(&release_event);
1150 if (details.dispatcher_destroyed)
1154 // Creates a widget and invokes GenerateMouseEvents() with |last_event_type|.
1155 void RunCloseWidgetDuringDispatchTest(WidgetTest* test,
1156 ui::EventType last_event_type) {
1157 // |widget| is deleted by CloseWidgetView.
1158 Widget* widget = new Widget;
1159 Widget::InitParams params =
1160 test->CreateParams(Widget::InitParams::TYPE_POPUP);
1161 params.native_widget = new PlatformDesktopNativeWidget(widget);
1162 params.bounds = gfx::Rect(0, 0, 50, 100);
1163 widget->Init(params);
1164 widget->SetContentsView(new CloseWidgetView(last_event_type));
1166 GenerateMouseEvents(widget, last_event_type);
1169 // Verifies deleting the widget from a mouse pressed event doesn't crash.
1170 TEST_F(WidgetTest, CloseWidgetDuringMousePress) {
1171 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_PRESSED);
1174 // Verifies deleting the widget from a mouse released event doesn't crash.
1175 TEST_F(WidgetTest, CloseWidgetDuringMouseReleased) {
1176 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_RELEASED);
1179 #endif // !defined(OS_CHROMEOS)
1181 // Tests that wheel events generated from scroll events are targetted to the
1182 // views under the cursor when the focused view does not processed them.
1183 TEST_F(WidgetTest, WheelEventsFromScrollEventTarget) {
1184 EventCountView* cursor_view = new EventCountView;
1185 cursor_view->SetBounds(60, 0, 50, 40);
1187 Widget* widget = CreateTopLevelPlatformWidget();
1188 widget->GetRootView()->AddChildView(cursor_view);
1190 // Generate a scroll event on the cursor view.
1191 ui::ScrollEvent scroll(ui::ET_SCROLL,
1193 ui::EventTimeForNow(),
1198 widget->OnScrollEvent(&scroll);
1200 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_SCROLL));
1201 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1203 cursor_view->ResetCounts();
1205 ui::ScrollEvent scroll2(ui::ET_SCROLL,
1207 ui::EventTimeForNow(),
1212 widget->OnScrollEvent(&scroll2);
1214 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_SCROLL));
1215 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1220 // Tests that if a scroll-begin gesture is not handled, then subsequent scroll
1221 // events are not dispatched to any view.
1222 TEST_F(WidgetTest, GestureScrollEventDispatching) {
1223 EventCountView* noscroll_view = new EventCountView;
1224 EventCountView* scroll_view = new ScrollableEventCountView;
1226 noscroll_view->SetBounds(0, 0, 50, 40);
1227 scroll_view->SetBounds(60, 0, 40, 40);
1229 Widget* widget = CreateTopLevelPlatformWidget();
1230 widget->GetRootView()->AddChildView(noscroll_view);
1231 widget->GetRootView()->AddChildView(scroll_view);
1234 ui::GestureEvent begin(ui::ET_GESTURE_SCROLL_BEGIN,
1235 5, 5, 0, base::TimeDelta(),
1236 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0),
1238 widget->OnGestureEvent(&begin);
1239 ui::GestureEvent update(ui::ET_GESTURE_SCROLL_UPDATE,
1240 25, 15, 0, base::TimeDelta(),
1241 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10),
1243 widget->OnGestureEvent(&update);
1244 ui::GestureEvent end(ui::ET_GESTURE_SCROLL_END,
1245 25, 15, 0, base::TimeDelta(),
1246 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END, 0, 0),
1248 widget->OnGestureEvent(&end);
1250 EXPECT_EQ(1, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1251 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1252 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1256 ui::GestureEvent begin(ui::ET_GESTURE_SCROLL_BEGIN,
1257 65, 5, 0, base::TimeDelta(),
1258 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0),
1260 widget->OnGestureEvent(&begin);
1261 ui::GestureEvent update(ui::ET_GESTURE_SCROLL_UPDATE,
1262 85, 15, 0, base::TimeDelta(),
1263 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10),
1265 widget->OnGestureEvent(&update);
1266 ui::GestureEvent end(ui::ET_GESTURE_SCROLL_END,
1267 85, 15, 0, base::TimeDelta(),
1268 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END, 0, 0),
1270 widget->OnGestureEvent(&end);
1272 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1273 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1274 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1280 // Tests that event-handlers installed on the RootView get triggered correctly.
1281 // TODO(tdanderson): Clean up this test as part of crbug.com/355680.
1282 TEST_F(WidgetTest, EventHandlersOnRootView) {
1283 Widget* widget = CreateTopLevelNativeWidget();
1284 View* root_view = widget->GetRootView();
1286 scoped_ptr<EventCountView> view(new EventCountView());
1287 view->set_owned_by_client();
1288 view->SetBounds(0, 0, 20, 20);
1289 root_view->AddChildView(view.get());
1291 EventCountHandler h1;
1292 root_view->AddPreTargetHandler(&h1);
1294 EventCountHandler h2;
1295 root_view->AddPostTargetHandler(&h2);
1297 widget->SetBounds(gfx::Rect(0, 0, 100, 100));
1300 ui::GestureEvent begin(ui::ET_GESTURE_BEGIN,
1301 5, 5, 0, ui::EventTimeForNow(),
1302 ui::GestureEventDetails(ui::ET_GESTURE_BEGIN, 0, 0), 1);
1303 ui::GestureEvent end(ui::ET_GESTURE_END,
1304 5, 5, 0, ui::EventTimeForNow(),
1305 ui::GestureEventDetails(ui::ET_GESTURE_END, 0, 0), 1);
1306 widget->OnGestureEvent(&begin);
1307 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_BEGIN));
1308 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_BEGIN));
1309 EXPECT_EQ(1, h2.GetEventCount(ui::ET_GESTURE_BEGIN));
1311 widget->OnGestureEvent(&end);
1312 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_END));
1313 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_END));
1314 EXPECT_EQ(1, h2.GetEventCount(ui::ET_GESTURE_END));
1316 ui::ScrollEvent scroll(ui::ET_SCROLL,
1318 ui::EventTimeForNow(),
1323 widget->OnScrollEvent(&scroll);
1324 EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL));
1325 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1326 EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL));
1328 // Unhandled scroll events are turned into wheel events and re-dispatched.
1329 EXPECT_EQ(1, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1330 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSEWHEEL));
1331 EXPECT_EQ(1, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1334 view->ResetCounts();
1337 ui::ScrollEvent fling(ui::ET_SCROLL_FLING_START,
1339 ui::EventTimeForNow(),
1344 widget->OnScrollEvent(&fling);
1345 EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL_FLING_START));
1346 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL_FLING_START));
1347 EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL_FLING_START));
1349 // Unhandled scroll events which are not of type ui::ET_SCROLL should not
1350 // be turned into wheel events and re-dispatched.
1351 EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1352 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
1353 EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1356 view->ResetCounts();
1359 // Replace the child of |root_view| with a ScrollableEventCountView so that
1360 // ui::ET_SCROLL events are marked as handled at the target phase.
1361 root_view->RemoveChildView(view.get());
1362 ScrollableEventCountView* scroll_view = new ScrollableEventCountView;
1363 scroll_view->SetBounds(0, 0, 20, 20);
1364 root_view->AddChildView(scroll_view);
1366 ui::ScrollEvent consumed_scroll(ui::ET_SCROLL,
1368 ui::EventTimeForNow(),
1373 widget->OnScrollEvent(&consumed_scroll);
1375 // The event is handled at the target phase and should not reach the
1376 // post-target handler.
1377 EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL));
1378 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_SCROLL));
1379 EXPECT_EQ(0, h2.GetEventCount(ui::ET_SCROLL));
1381 // Handled scroll events are not turned into wheel events and re-dispatched.
1382 EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1383 EXPECT_EQ(0, scroll_view->GetEventCount(ui::ET_MOUSEWHEEL));
1384 EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1389 TEST_F(WidgetTest, SynthesizeMouseMoveEvent) {
1390 Widget* widget = CreateTopLevelNativeWidget();
1391 View* root_view = widget->GetRootView();
1393 EventCountView* v1 = new EventCountView();
1394 v1->SetBounds(0, 0, 10, 10);
1395 root_view->AddChildView(v1);
1396 EventCountView* v2 = new EventCountView();
1397 v2->SetBounds(0, 10, 10, 10);
1398 root_view->AddChildView(v2);
1400 gfx::Point cursor_location(5, 5);
1401 ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
1402 ui::EF_NONE, ui::EF_NONE);
1403 widget->OnMouseEvent(&move);
1405 EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
1406 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1409 v2->SetBounds(0, 0, 10, 10);
1410 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1412 widget->SynthesizeMouseMoveEvent();
1413 EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1416 // Used by SingleWindowClosing to count number of times WindowClosing() has
1418 class ClosingDelegate : public WidgetDelegate {
1420 ClosingDelegate() : count_(0), widget_(NULL) {}
1422 int count() const { return count_; }
1424 void set_widget(views::Widget* widget) { widget_ = widget; }
1426 // WidgetDelegate overrides:
1427 virtual Widget* GetWidget() OVERRIDE { return widget_; }
1428 virtual const Widget* GetWidget() const OVERRIDE { return widget_; }
1429 virtual void WindowClosing() OVERRIDE {
1435 views::Widget* widget_;
1437 DISALLOW_COPY_AND_ASSIGN(ClosingDelegate);
1440 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget
1442 TEST_F(WidgetTest, SingleWindowClosing) {
1443 scoped_ptr<ClosingDelegate> delegate(new ClosingDelegate());
1444 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1445 Widget::InitParams init_params =
1446 CreateParams(Widget::InitParams::TYPE_WINDOW);
1447 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1448 init_params.delegate = delegate.get();
1449 #if !defined(OS_CHROMEOS)
1450 init_params.native_widget = new PlatformDesktopNativeWidget(widget);
1452 widget->Init(init_params);
1453 EXPECT_EQ(0, delegate->count());
1455 EXPECT_EQ(1, delegate->count());
1458 class WidgetWindowTitleTest : public WidgetTest {
1460 void RunTest(bool desktop_native_widget) {
1461 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1462 Widget::InitParams init_params =
1463 CreateParams(Widget::InitParams::TYPE_WINDOW);
1464 widget->Init(init_params);
1466 #if !defined(OS_CHROMEOS)
1467 if (desktop_native_widget)
1468 init_params.native_widget = new PlatformDesktopNativeWidget(widget);
1470 DCHECK(!desktop_native_widget)
1471 << "DesktopNativeWidget does not exist on non-Aura or on ChromeOS.";
1474 internal::NativeWidgetPrivate* native_widget =
1475 widget->native_widget_private();
1477 base::string16 empty;
1478 base::string16 s1(base::UTF8ToUTF16("Title1"));
1479 base::string16 s2(base::UTF8ToUTF16("Title2"));
1480 base::string16 s3(base::UTF8ToUTF16("TitleLong"));
1482 // The widget starts with no title, setting empty should not change
1484 EXPECT_FALSE(native_widget->SetWindowTitle(empty));
1485 // Setting the title to something non-empty should cause a change.
1486 EXPECT_TRUE(native_widget->SetWindowTitle(s1));
1487 // Setting the title to something else with the same length should cause a
1489 EXPECT_TRUE(native_widget->SetWindowTitle(s2));
1490 // Setting the title to something else with a different length should cause
1492 EXPECT_TRUE(native_widget->SetWindowTitle(s3));
1493 // Setting the title to the same thing twice should not cause a change.
1494 EXPECT_FALSE(native_widget->SetWindowTitle(s3));
1500 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_NativeWidget) {
1501 // Use the default NativeWidget.
1502 bool desktop_native_widget = false;
1503 RunTest(desktop_native_widget);
1506 // DesktopNativeWidget does not exist on non-Aura or on ChromeOS.
1507 #if !defined(OS_CHROMEOS)
1508 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_DesktopNativeWidget) {
1509 // Override to use a DesktopNativeWidget.
1510 bool desktop_native_widget = true;
1511 RunTest(desktop_native_widget);
1513 #endif // !OS_CHROMEOS
1515 TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) {
1516 Widget* widget = new Widget;
1517 Widget::InitParams params =
1518 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1519 widget->Init(params);
1521 widget->SetContentsView(new CloseWidgetView(ui::ET_MOUSE_PRESSED));
1523 widget->SetSize(gfx::Size(100, 100));
1526 aura::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1528 WidgetDeletionObserver deletion_observer(widget);
1529 generator.ClickLeftButton();
1530 EXPECT_FALSE(deletion_observer.IsWidgetAlive());
1532 // Yay we did not crash!
1535 TEST_F(WidgetTest, WidgetDeleted_InDispatchGestureEvent) {
1536 Widget* widget = new Widget;
1537 Widget::InitParams params =
1538 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1539 widget->Init(params);
1541 widget->SetContentsView(new CloseWidgetView(ui::ET_GESTURE_TAP_DOWN));
1543 widget->SetSize(gfx::Size(100, 100));
1546 aura::test::EventGenerator generator(GetContext());
1548 WidgetDeletionObserver deletion_observer(widget);
1549 generator.GestureTapAt(widget->GetWindowBoundsInScreen().CenterPoint());
1550 EXPECT_FALSE(deletion_observer.IsWidgetAlive());
1552 // Yay we did not crash!
1555 // See description of RunGetNativeThemeFromDestructor() for details.
1556 class GetNativeThemeFromDestructorView : public WidgetDelegateView {
1558 GetNativeThemeFromDestructorView() {}
1559 virtual ~GetNativeThemeFromDestructorView() {
1560 VerifyNativeTheme();
1563 virtual View* GetContentsView() OVERRIDE {
1568 void VerifyNativeTheme() {
1569 ASSERT_TRUE(GetNativeTheme() != NULL);
1572 DISALLOW_COPY_AND_ASSIGN(GetNativeThemeFromDestructorView);
1575 // Verifies GetNativeTheme() from the destructor of a WidgetDelegateView doesn't
1576 // crash. |is_first_run| is true if this is the first call. A return value of
1577 // true indicates this should be run again with a value of false.
1578 // First run uses DesktopNativeWidgetAura (if possible). Second run doesn't.
1579 bool RunGetNativeThemeFromDestructor(const Widget::InitParams& in_params,
1580 bool is_first_run) {
1581 bool needs_second_run = false;
1582 // Destroyed by CloseNow() below.
1583 Widget* widget = new Widget;
1584 Widget::InitParams params(in_params);
1585 // Deletes itself when the Widget is destroyed.
1586 params.delegate = new GetNativeThemeFromDestructorView;
1587 #if !defined(OS_CHROMEOS)
1589 params.native_widget = new PlatformDesktopNativeWidget(widget);
1590 needs_second_run = true;
1593 widget->Init(params);
1595 return needs_second_run;
1598 // See description of RunGetNativeThemeFromDestructor() for details.
1599 TEST_F(WidgetTest, GetNativeThemeFromDestructor) {
1600 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1601 if (RunGetNativeThemeFromDestructor(params, true))
1602 RunGetNativeThemeFromDestructor(params, false);
1605 // Used by HideCloseDestroy. Allows setting a boolean when the widget is
1607 class CloseDestroysWidget : public Widget {
1609 explicit CloseDestroysWidget(bool* destroyed)
1610 : destroyed_(destroyed) {
1613 virtual ~CloseDestroysWidget() {
1616 base::MessageLoop::current()->QuitNow();
1620 void Detach() { destroyed_ = NULL; }
1623 // If non-null set to true from destructor.
1626 DISALLOW_COPY_AND_ASSIGN(CloseDestroysWidget);
1629 // Verifies Close() results in destroying.
1630 TEST_F(WidgetTest, CloseDestroys) {
1631 bool destroyed = false;
1632 CloseDestroysWidget* widget = new CloseDestroysWidget(&destroyed);
1633 Widget::InitParams params =
1634 CreateParams(views::Widget::InitParams::TYPE_MENU);
1635 params.opacity = Widget::InitParams::OPAQUE_WINDOW;
1636 #if !defined(OS_CHROMEOS)
1637 params.native_widget = new PlatformDesktopNativeWidget(widget);
1639 widget->Init(params);
1643 // Run the message loop as Close() asynchronously deletes.
1644 RunPendingMessages();
1645 EXPECT_TRUE(destroyed);
1646 // Close() should destroy the widget. If not we'll cleanup to avoid leaks.
1653 // Tests that killing a widget while animating it does not crash.
1654 TEST_F(WidgetTest, CloseWidgetWhileAnimating) {
1655 scoped_ptr<Widget> widget(new Widget);
1656 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1657 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1658 widget->Init(params);
1660 // Normal animations for tests have ZERO_DURATION, make sure we are actually
1661 // animating the movement.
1662 ui::ScopedAnimationDurationScaleMode animation_scale_mode(
1663 ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
1664 ui::ScopedLayerAnimationSettings animation_settings(
1665 widget->GetLayer()->GetAnimator());
1667 // Animate the bounds change.
1668 widget->SetBounds(gfx::Rect(0, 0, 200, 200));
1671 // A view that consumes mouse-pressed event and gesture-tap-down events.
1672 class RootViewTestView : public View {
1674 RootViewTestView(): View() {}
1677 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
1681 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
1682 if (event->type() == ui::ET_GESTURE_TAP_DOWN)
1683 event->SetHandled();
1687 // Checks if RootView::*_handler_ fields are unset when widget is hidden.
1688 // Fails on chromium.webkit Windows bot, see crbug.com/264872.
1690 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1691 DISABLED_TestRootViewHandlersWhenHidden
1693 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1694 TestRootViewHandlersWhenHidden
1696 TEST_F(WidgetTest, MAYBE_DisableTestRootViewHandlersWhenHidden) {
1697 Widget* widget = CreateTopLevelNativeWidget();
1698 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
1699 View* view = new RootViewTestView();
1700 view->SetBounds(0, 0, 300, 300);
1701 internal::RootView* root_view =
1702 static_cast<internal::RootView*>(widget->GetRootView());
1703 root_view->AddChildView(view);
1705 // Check RootView::mouse_pressed_handler_.
1707 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
1708 gfx::Point click_location(45, 15);
1709 ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
1710 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
1711 widget->OnMouseEvent(&press);
1712 EXPECT_EQ(view, GetMousePressedHandler(root_view));
1714 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
1716 // Check RootView::mouse_move_handler_.
1718 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
1719 gfx::Point move_location(45, 15);
1720 ui::MouseEvent move(ui::ET_MOUSE_MOVED, move_location, move_location, 0, 0);
1721 widget->OnMouseEvent(&move);
1722 EXPECT_EQ(view, GetMouseMoveHandler(root_view));
1724 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
1726 // Check RootView::gesture_handler_.
1728 EXPECT_EQ(NULL, GetGestureHandler(root_view));
1729 ui::GestureEvent tap_down(
1730 ui::ET_GESTURE_TAP_DOWN,
1735 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN, 0, 0),
1737 widget->OnGestureEvent(&tap_down);
1738 EXPECT_EQ(view, GetGestureHandler(root_view));
1740 EXPECT_EQ(NULL, GetGestureHandler(root_view));
1745 class GestureEndConsumerView : public View {
1747 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
1748 if (event->type() == ui::ET_GESTURE_END)
1749 event->SetHandled();
1753 TEST_F(WidgetTest, GestureHandlerNotSetOnGestureEnd) {
1754 Widget* widget = CreateTopLevelNativeWidget();
1755 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
1756 View* view = new GestureEndConsumerView();
1757 view->SetBounds(0, 0, 300, 300);
1758 internal::RootView* root_view =
1759 static_cast<internal::RootView*>(widget->GetRootView());
1760 root_view->AddChildView(view);
1763 EXPECT_EQ(NULL, GetGestureHandler(root_view));
1764 ui::GestureEvent end(ui::ET_GESTURE_END, 15, 15, 0, base::TimeDelta(),
1765 ui::GestureEventDetails(ui::ET_GESTURE_END, 0, 0), 1);
1766 widget->OnGestureEvent(&end);
1767 EXPECT_EQ(NULL, GetGestureHandler(root_view));
1772 // Test the result of Widget::GetAllChildWidgets().
1773 TEST_F(WidgetTest, GetAllChildWidgets) {
1774 // Create the following widget hierarchy:
1782 Widget* toplevel = CreateTopLevelPlatformWidget();
1783 Widget* w1 = CreateChildPlatformWidget(toplevel->GetNativeView());
1784 Widget* w11 = CreateChildPlatformWidget(w1->GetNativeView());
1785 Widget* w2 = CreateChildPlatformWidget(toplevel->GetNativeView());
1786 Widget* w21 = CreateChildPlatformWidget(w2->GetNativeView());
1787 Widget* w22 = CreateChildPlatformWidget(w2->GetNativeView());
1789 std::set<Widget*> expected;
1790 expected.insert(toplevel);
1791 expected.insert(w1);
1792 expected.insert(w11);
1793 expected.insert(w2);
1794 expected.insert(w21);
1795 expected.insert(w22);
1797 std::set<Widget*> widgets;
1798 Widget::GetAllChildWidgets(toplevel->GetNativeView(), &widgets);
1800 EXPECT_EQ(expected.size(), widgets.size());
1801 EXPECT_TRUE(std::equal(expected.begin(), expected.end(), widgets.begin()));
1804 // Used by DestroyChildWidgetsInOrder. On destruction adds the supplied name to
1806 class DestroyedTrackingView : public View {
1808 DestroyedTrackingView(const std::string& name,
1809 std::vector<std::string>* add_to)
1814 virtual ~DestroyedTrackingView() {
1815 add_to_->push_back(name_);
1819 const std::string name_;
1820 std::vector<std::string>* add_to_;
1822 DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingView);
1825 class WidgetChildDestructionTest : public WidgetTest {
1827 WidgetChildDestructionTest() {}
1829 // Creates a top level and a child, destroys the child and verifies the views
1830 // of the child are destroyed before the views of the parent.
1831 void RunDestroyChildWidgetsTest(bool top_level_has_desktop_native_widget_aura,
1832 bool child_has_desktop_native_widget_aura) {
1833 // When a View is destroyed its name is added here.
1834 std::vector<std::string> destroyed;
1836 Widget* top_level = new Widget;
1837 Widget::InitParams params =
1838 CreateParams(views::Widget::InitParams::TYPE_WINDOW);
1839 #if !defined(OS_CHROMEOS)
1840 if (top_level_has_desktop_native_widget_aura)
1841 params.native_widget = new PlatformDesktopNativeWidget(top_level);
1843 top_level->Init(params);
1844 top_level->GetRootView()->AddChildView(
1845 new DestroyedTrackingView("parent", &destroyed));
1848 Widget* child = new Widget;
1849 Widget::InitParams child_params =
1850 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1851 child_params.parent = top_level->GetNativeView();
1852 #if !defined(OS_CHROMEOS)
1853 if (child_has_desktop_native_widget_aura)
1854 child_params.native_widget = new PlatformDesktopNativeWidget(child);
1856 child->Init(child_params);
1857 child->GetRootView()->AddChildView(
1858 new DestroyedTrackingView("child", &destroyed));
1861 // Should trigger destruction of the child too.
1862 top_level->native_widget_private()->CloseNow();
1864 // Child should be destroyed first.
1865 ASSERT_EQ(2u, destroyed.size());
1866 EXPECT_EQ("child", destroyed[0]);
1867 EXPECT_EQ("parent", destroyed[1]);
1871 DISALLOW_COPY_AND_ASSIGN(WidgetChildDestructionTest);
1874 #if !defined(OS_CHROMEOS)
1875 // See description of RunDestroyChildWidgetsTest(). Parent uses
1876 // DesktopNativeWidgetAura.
1877 TEST_F(WidgetChildDestructionTest,
1878 DestroyChildWidgetsInOrderWithDesktopNativeWidget) {
1879 RunDestroyChildWidgetsTest(true, false);
1882 // See description of RunDestroyChildWidgetsTest(). Both parent and child use
1883 // DesktopNativeWidgetAura.
1884 TEST_F(WidgetChildDestructionTest,
1885 DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth) {
1886 RunDestroyChildWidgetsTest(true, true);
1888 #endif // !defined(OS_CHROMEOS)
1890 // See description of RunDestroyChildWidgetsTest().
1891 TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) {
1892 RunDestroyChildWidgetsTest(false, false);
1895 #if !defined(OS_CHROMEOS)
1896 // Provides functionality to create a window modal dialog.
1897 class ModalDialogDelegate : public DialogDelegateView {
1899 ModalDialogDelegate() {}
1900 virtual ~ModalDialogDelegate() {}
1902 // WidgetDelegate overrides.
1903 virtual ui::ModalType GetModalType() const OVERRIDE {
1904 return ui::MODAL_TYPE_WINDOW;
1908 DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate);
1911 // This test verifies that whether mouse events when a modal dialog is
1912 // displayed are eaten or recieved by the dialog.
1913 TEST_F(WidgetTest, WindowMouseModalityTest) {
1914 // Create a top level widget.
1915 Widget top_level_widget;
1916 Widget::InitParams init_params =
1917 CreateParams(Widget::InitParams::TYPE_WINDOW);
1918 init_params.show_state = ui::SHOW_STATE_NORMAL;
1919 gfx::Rect initial_bounds(0, 0, 500, 500);
1920 init_params.bounds = initial_bounds;
1921 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1922 init_params.native_widget =
1923 new PlatformDesktopNativeWidget(&top_level_widget);
1924 top_level_widget.Init(init_params);
1925 top_level_widget.Show();
1926 EXPECT_TRUE(top_level_widget.IsVisible());
1928 // Create a view and validate that a mouse moves makes it to the view.
1929 EventCountView* widget_view = new EventCountView();
1930 widget_view->SetBounds(0, 0, 10, 10);
1931 top_level_widget.GetRootView()->AddChildView(widget_view);
1933 gfx::Point cursor_location_main(5, 5);
1934 ui::MouseEvent move_main(ui::ET_MOUSE_MOVED,
1935 cursor_location_main,
1936 cursor_location_main,
1939 ui::EventDispatchDetails details =
1940 GetEventProcessor(&top_level_widget)->OnEventFromSource(&move_main);
1941 ASSERT_FALSE(details.dispatcher_destroyed);
1943 EXPECT_EQ(1, widget_view->GetEventCount(ui::ET_MOUSE_ENTERED));
1944 widget_view->ResetCounts();
1946 // Create a modal dialog and validate that a mouse down message makes it to
1947 // the main view within the dialog.
1949 // This instance will be destroyed when the dialog is destroyed.
1950 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
1952 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
1953 dialog_delegate, NULL, top_level_widget.GetNativeView());
1954 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
1955 EventCountView* dialog_widget_view = new EventCountView();
1956 dialog_widget_view->SetBounds(0, 0, 50, 50);
1957 modal_dialog_widget->GetRootView()->AddChildView(dialog_widget_view);
1958 modal_dialog_widget->Show();
1959 EXPECT_TRUE(modal_dialog_widget->IsVisible());
1961 gfx::Point cursor_location_dialog(100, 100);
1962 ui::MouseEvent mouse_down_dialog(ui::ET_MOUSE_PRESSED,
1963 cursor_location_dialog,
1964 cursor_location_dialog,
1967 details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
1968 &mouse_down_dialog);
1969 ASSERT_FALSE(details.dispatcher_destroyed);
1970 EXPECT_EQ(1, dialog_widget_view->GetEventCount(ui::ET_MOUSE_PRESSED));
1972 // Send a mouse move message to the main window. It should not be received by
1973 // the main window as the modal dialog is still active.
1974 gfx::Point cursor_location_main2(6, 6);
1975 ui::MouseEvent mouse_down_main(ui::ET_MOUSE_MOVED,
1976 cursor_location_main2,
1977 cursor_location_main2,
1980 details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
1982 ASSERT_FALSE(details.dispatcher_destroyed);
1983 EXPECT_EQ(0, widget_view->GetEventCount(ui::ET_MOUSE_MOVED));
1985 modal_dialog_widget->CloseNow();
1986 top_level_widget.CloseNow();
1989 // Verifies nativeview visbility matches that of Widget visibility when
1990 // SetFullscreen is invoked.
1991 TEST_F(WidgetTest, FullscreenStatePropagated) {
1992 Widget::InitParams init_params =
1993 CreateParams(Widget::InitParams::TYPE_WINDOW);
1994 init_params.show_state = ui::SHOW_STATE_NORMAL;
1995 init_params.bounds = gfx::Rect(0, 0, 500, 500);
1996 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1999 Widget top_level_widget;
2000 top_level_widget.Init(init_params);
2001 top_level_widget.SetFullscreen(true);
2002 EXPECT_EQ(top_level_widget.IsVisible(),
2003 IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
2004 top_level_widget.CloseNow();
2007 #if !defined(OS_CHROMEOS)
2009 Widget top_level_widget;
2010 init_params.native_widget =
2011 new PlatformDesktopNativeWidget(&top_level_widget);
2012 top_level_widget.Init(init_params);
2013 top_level_widget.SetFullscreen(true);
2014 EXPECT_EQ(top_level_widget.IsVisible(),
2015 IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
2016 top_level_widget.CloseNow();
2023 // Provides functionality to test widget activation via an activation flag
2024 // which can be set by an accessor.
2025 class ModalWindowTestWidgetDelegate : public WidgetDelegate {
2027 ModalWindowTestWidgetDelegate()
2029 can_activate_(true) {}
2031 virtual ~ModalWindowTestWidgetDelegate() {}
2033 // Overridden from WidgetDelegate:
2034 virtual void DeleteDelegate() OVERRIDE {
2037 virtual Widget* GetWidget() OVERRIDE {
2040 virtual const Widget* GetWidget() const OVERRIDE {
2043 virtual bool CanActivate() const OVERRIDE {
2044 return can_activate_;
2046 virtual bool ShouldAdvanceFocusToTopLevelWidget() const OVERRIDE {
2050 void set_can_activate(bool can_activate) {
2051 can_activate_ = can_activate;
2054 void set_widget(Widget* widget) {
2062 DISALLOW_COPY_AND_ASSIGN(ModalWindowTestWidgetDelegate);
2065 // Tests whether we can activate the top level widget when a modal dialog is
2067 TEST_F(WidgetTest, WindowModalityActivationTest) {
2068 // Destroyed when the top level widget created below is destroyed.
2069 ModalWindowTestWidgetDelegate* widget_delegate =
2070 new ModalWindowTestWidgetDelegate;
2071 // Create a top level widget.
2072 Widget top_level_widget;
2073 Widget::InitParams init_params =
2074 CreateParams(Widget::InitParams::TYPE_WINDOW);
2075 init_params.show_state = ui::SHOW_STATE_NORMAL;
2076 gfx::Rect initial_bounds(0, 0, 500, 500);
2077 init_params.bounds = initial_bounds;
2078 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2079 init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget);
2080 init_params.delegate = widget_delegate;
2081 top_level_widget.Init(init_params);
2082 widget_delegate->set_widget(&top_level_widget);
2083 top_level_widget.Show();
2084 EXPECT_TRUE(top_level_widget.IsVisible());
2086 HWND win32_window = views::HWNDForWidget(&top_level_widget);
2087 EXPECT_TRUE(::IsWindow(win32_window));
2089 // This instance will be destroyed when the dialog is destroyed.
2090 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
2092 // We should be able to activate the window even if the WidgetDelegate
2093 // says no, when a modal dialog is active.
2094 widget_delegate->set_can_activate(false);
2096 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
2097 dialog_delegate, NULL, top_level_widget.GetNativeWindow());
2098 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
2099 modal_dialog_widget->Show();
2100 EXPECT_TRUE(modal_dialog_widget->IsVisible());
2102 LRESULT activate_result = ::SendMessage(
2105 reinterpret_cast<WPARAM>(win32_window),
2106 MAKELPARAM(WM_LBUTTONDOWN, HTCLIENT));
2107 EXPECT_EQ(activate_result, MA_ACTIVATE);
2109 modal_dialog_widget->CloseNow();
2110 top_level_widget.CloseNow();
2112 #endif // defined(OS_WIN)
2113 #endif // !defined(OS_CHROMEOS)
2115 TEST_F(WidgetTest, ShowCreatesActiveWindow) {
2116 Widget* widget = CreateTopLevelPlatformWidget();
2119 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2124 TEST_F(WidgetTest, ShowInactive) {
2125 Widget* widget = CreateTopLevelPlatformWidget();
2127 widget->ShowInactive();
2128 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_INACTIVE);
2133 TEST_F(WidgetTest, ShowInactiveAfterShow) {
2134 Widget* widget = CreateTopLevelPlatformWidget();
2137 widget->ShowInactive();
2138 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2143 TEST_F(WidgetTest, ShowAfterShowInactive) {
2144 Widget* widget = CreateTopLevelPlatformWidget();
2146 widget->ShowInactive();
2148 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2153 #if !defined(OS_CHROMEOS)
2154 TEST_F(WidgetTest, InactiveWidgetDoesNotGrabActivation) {
2155 Widget* widget = CreateTopLevelPlatformWidget();
2157 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2160 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2161 params.native_widget = new PlatformDesktopNativeWidget(&widget2);
2162 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2163 widget2.Init(params);
2166 EXPECT_EQ(GetWidgetShowState(&widget2), ui::SHOW_STATE_INACTIVE);
2167 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2172 #endif // !defined(OS_CHROMEOS)
2176 class FullscreenAwareFrame : public views::NonClientFrameView {
2178 explicit FullscreenAwareFrame(views::Widget* widget)
2179 : widget_(widget), fullscreen_layout_called_(false) {}
2180 virtual ~FullscreenAwareFrame() {}
2182 // views::NonClientFrameView overrides:
2183 virtual gfx::Rect GetBoundsForClientView() const OVERRIDE {
2186 virtual gfx::Rect GetWindowBoundsForClientBounds(
2187 const gfx::Rect& client_bounds) const OVERRIDE {
2190 virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE {
2193 virtual void GetWindowMask(const gfx::Size& size,
2194 gfx::Path* window_mask) OVERRIDE {}
2195 virtual void ResetWindowControls() OVERRIDE {}
2196 virtual void UpdateWindowIcon() OVERRIDE {}
2197 virtual void UpdateWindowTitle() OVERRIDE {}
2199 // views::View overrides:
2200 virtual void Layout() OVERRIDE {
2201 if (widget_->IsFullscreen())
2202 fullscreen_layout_called_ = true;
2205 bool fullscreen_layout_called() const { return fullscreen_layout_called_; }
2208 views::Widget* widget_;
2209 bool fullscreen_layout_called_;
2211 DISALLOW_COPY_AND_ASSIGN(FullscreenAwareFrame);
2216 // Tests that frame Layout is called when a widget goes fullscreen without
2217 // changing its size or title.
2218 TEST_F(WidgetTest, FullscreenFrameLayout) {
2219 Widget* widget = CreateTopLevelPlatformWidget();
2220 FullscreenAwareFrame* frame = new FullscreenAwareFrame(widget);
2221 widget->non_client_view()->SetFrameView(frame); // Owns |frame|.
2224 RunPendingMessages();
2226 EXPECT_FALSE(frame->fullscreen_layout_called());
2227 widget->SetFullscreen(true);
2229 RunPendingMessages();
2230 EXPECT_TRUE(frame->fullscreen_layout_called());
2235 #if !defined(OS_CHROMEOS)
2238 // Trivial WidgetObserverTest that invokes Widget::IsActive() from
2239 // OnWindowDestroying.
2240 class IsActiveFromDestroyObserver : public WidgetObserver {
2242 IsActiveFromDestroyObserver() {}
2243 virtual ~IsActiveFromDestroyObserver() {}
2244 virtual void OnWidgetDestroying(Widget* widget) OVERRIDE {
2249 DISALLOW_COPY_AND_ASSIGN(IsActiveFromDestroyObserver);
2254 // Verifies Widget::IsActive() invoked from
2255 // WidgetObserver::OnWidgetDestroying() in a child widget doesn't crash.
2256 TEST_F(WidgetTest, IsActiveFromDestroy) {
2257 // Create two widgets, one a child of the other.
2258 IsActiveFromDestroyObserver observer;
2259 Widget parent_widget;
2260 Widget::InitParams parent_params =
2261 CreateParams(Widget::InitParams::TYPE_POPUP);
2262 parent_params.native_widget = new PlatformDesktopNativeWidget(&parent_widget);
2263 parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2264 parent_widget.Init(parent_params);
2265 parent_widget.Show();
2267 Widget child_widget;
2268 Widget::InitParams child_params =
2269 CreateParams(Widget::InitParams::TYPE_POPUP);
2270 child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2271 child_params.context = parent_widget.GetNativeView();
2272 child_widget.Init(child_params);
2273 child_widget.AddObserver(&observer);
2274 child_widget.Show();
2276 parent_widget.CloseNow();
2278 #endif // !defined(OS_CHROMEOS)
2281 } // namespace views