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