Fix build break
[chromium-blink-merge.git] / ui / views / widget / widget_unittest.cc
blobe4376caec0fa2cfa39bc9acbb4af12293133ae38
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 "base/basictypes.h"
6 #include "base/memory/scoped_ptr.h"
7 #include "base/message_loop.h"
8 #include "base/utf_string_conversions.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "ui/base/events/event_utils.h"
11 #include "ui/gfx/native_widget_types.h"
12 #include "ui/gfx/point.h"
13 #include "ui/views/bubble/bubble_delegate.h"
14 #include "ui/views/controls/textfield/textfield.h"
15 #include "ui/views/test/test_views_delegate.h"
16 #include "ui/views/test/views_test_base.h"
17 #include "ui/views/views_delegate.h"
18 #include "ui/views/widget/native_widget_delegate.h"
19 #include "ui/views/window/native_frame_view.h"
21 #if defined(USE_AURA)
22 #include "ui/aura/client/aura_constants.h"
23 #include "ui/aura/test/test_window_delegate.h"
24 #include "ui/aura/window.h"
25 #include "ui/views/widget/native_widget_aura.h"
26 #if !defined(OS_CHROMEOS)
27 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
28 #endif
29 #elif defined(OS_WIN)
30 #include "ui/views/widget/native_widget_win.h"
31 #endif
33 namespace views {
34 namespace {
36 // A generic typedef to pick up relevant NativeWidget implementations.
37 #if defined(USE_AURA)
38 typedef NativeWidgetAura NativeWidgetPlatform;
39 #elif defined(OS_WIN)
40 typedef NativeWidgetWin NativeWidgetPlatform;
41 #endif
43 // A widget that assumes mouse capture always works. It won't on Aura in
44 // testing, so we mock it.
45 #if defined(USE_AURA)
46 class NativeWidgetCapture : public NativeWidgetPlatform {
47 public:
48 explicit NativeWidgetCapture(internal::NativeWidgetDelegate* delegate)
49 : NativeWidgetPlatform(delegate),
50 mouse_capture_(false) {}
51 virtual ~NativeWidgetCapture() {}
53 virtual void SetCapture() OVERRIDE {
54 mouse_capture_ = true;
56 virtual void ReleaseCapture() OVERRIDE {
57 if (mouse_capture_)
58 delegate()->OnMouseCaptureLost();
59 mouse_capture_ = false;
61 virtual bool HasCapture() const OVERRIDE {
62 return mouse_capture_;
65 private:
66 bool mouse_capture_;
68 DISALLOW_COPY_AND_ASSIGN(NativeWidgetCapture);
70 #endif
72 // A typedef that inserts our mock-capture NativeWidget implementation for
73 // relevant platforms.
74 #if defined(USE_AURA)
75 typedef NativeWidgetCapture NativeWidgetPlatformForTest;
76 #elif defined(OS_WIN)
77 typedef NativeWidgetWin NativeWidgetPlatformForTest;
78 #endif
80 // A view that always processes all mouse events.
81 class MouseView : public View {
82 public:
83 MouseView()
84 : View(),
85 entered_(0),
86 exited_(0),
87 pressed_(0) {
89 virtual ~MouseView() {}
91 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
92 pressed_++;
93 return true;
96 virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE {
97 entered_++;
100 virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE {
101 exited_++;
104 // Return the number of OnMouseEntered calls and reset the counter.
105 int EnteredCalls() {
106 int i = entered_;
107 entered_ = 0;
108 return i;
111 // Return the number of OnMouseExited calls and reset the counter.
112 int ExitedCalls() {
113 int i = exited_;
114 exited_ = 0;
115 return i;
118 int pressed() const { return pressed_; }
120 private:
121 int entered_;
122 int exited_;
124 int pressed_;
126 DISALLOW_COPY_AND_ASSIGN(MouseView);
129 // A view that keeps track of the events it receives, but consumes no events.
130 class EventCountView : public View {
131 public:
132 EventCountView() {}
133 virtual ~EventCountView() {}
135 int GetEventCount(ui::EventType type) {
136 return event_count_[type];
139 void ResetCounts() {
140 event_count_.clear();
143 protected:
144 // Overridden from ui::EventHandler:
145 virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
146 RecordEvent(*event);
148 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
149 RecordEvent(*event);
151 virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE {
152 RecordEvent(*event);
154 virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE {
155 RecordEvent(*event);
157 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
158 RecordEvent(*event);
161 private:
162 void RecordEvent(const ui::Event& event) {
163 ++event_count_[event.type()];
166 std::map<ui::EventType, int> event_count_;
168 DISALLOW_COPY_AND_ASSIGN(EventCountView);
171 // A view that keeps track of the events it receives, and consumes all scroll
172 // gesture events.
173 class ScrollableEventCountView : public EventCountView {
174 public:
175 ScrollableEventCountView() {}
176 virtual ~ScrollableEventCountView() {}
178 private:
179 // Overridden from ui::EventHandler:
180 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
181 EventCountView::OnGestureEvent(event);
182 switch (event->type()) {
183 case ui::ET_GESTURE_SCROLL_BEGIN:
184 case ui::ET_GESTURE_SCROLL_UPDATE:
185 case ui::ET_GESTURE_SCROLL_END:
186 case ui::ET_SCROLL_FLING_START:
187 event->SetHandled();
188 break;
189 default:
190 break;
194 DISALLOW_COPY_AND_ASSIGN(ScrollableEventCountView);
197 // A view that does a capture on gesture-begin events.
198 class GestureCaptureView : public View {
199 public:
200 GestureCaptureView() {}
201 virtual ~GestureCaptureView() {}
203 private:
204 // Overridden from View:
205 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
206 if (event->type() == ui::ET_GESTURE_BEGIN) {
207 GetWidget()->SetCapture(this);
208 event->StopPropagation();
212 DISALLOW_COPY_AND_ASSIGN(GestureCaptureView);
215 // A view that implements GetMinimumSize.
216 class MinimumSizeFrameView : public NativeFrameView {
217 public:
218 explicit MinimumSizeFrameView(Widget* frame): NativeFrameView(frame) {}
219 virtual ~MinimumSizeFrameView() {}
221 private:
222 // Overridden from View:
223 virtual gfx::Size GetMinimumSize() OVERRIDE {
224 return gfx::Size(300, 400);
227 DISALLOW_COPY_AND_ASSIGN(MinimumSizeFrameView);
230 // An event handler that simply keeps a count of the different types of events
231 // it receives.
232 class EventCountHandler : public ui::EventHandler {
233 public:
234 EventCountHandler() {}
235 virtual ~EventCountHandler() {}
237 int GetEventCount(ui::EventType type) {
238 return event_count_[type];
241 void ResetCounts() {
242 event_count_.clear();
245 protected:
246 // Overridden from ui::EventHandler:
247 virtual void OnEvent(ui::Event* event) OVERRIDE {
248 RecordEvent(*event);
249 ui::EventHandler::OnEvent(event);
252 private:
253 void RecordEvent(const ui::Event& event) {
254 ++event_count_[event.type()];
257 std::map<ui::EventType, int> event_count_;
259 DISALLOW_COPY_AND_ASSIGN(EventCountHandler);
262 class WidgetTest : public ViewsTestBase {
263 public:
264 WidgetTest() {}
265 virtual ~WidgetTest() {}
267 NativeWidget* CreatePlatformNativeWidget(
268 internal::NativeWidgetDelegate* delegate) {
269 return new NativeWidgetPlatformForTest(delegate);
272 Widget* CreateTopLevelPlatformWidget() {
273 Widget* toplevel = new Widget;
274 Widget::InitParams toplevel_params =
275 CreateParams(Widget::InitParams::TYPE_WINDOW);
276 toplevel_params.native_widget = CreatePlatformNativeWidget(toplevel);
277 toplevel->Init(toplevel_params);
278 return toplevel;
281 Widget* CreateTopLevelFramelessPlatformWidget() {
282 Widget* toplevel = new Widget;
283 Widget::InitParams toplevel_params =
284 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
285 toplevel_params.native_widget = CreatePlatformNativeWidget(toplevel);
286 toplevel->Init(toplevel_params);
287 return toplevel;
290 Widget* CreateChildPlatformWidget(gfx::NativeView parent_native_view) {
291 Widget* child = new Widget;
292 Widget::InitParams child_params =
293 CreateParams(Widget::InitParams::TYPE_CONTROL);
294 child_params.native_widget = CreatePlatformNativeWidget(child);
295 child_params.parent = parent_native_view;
296 child->Init(child_params);
297 child->SetContentsView(new View);
298 return child;
301 #if defined(OS_WIN) && !defined(USE_AURA)
302 // On Windows, it is possible for us to have a child window that is
303 // TYPE_POPUP.
304 Widget* CreateChildPopupPlatformWidget(gfx::NativeView parent_native_view) {
305 Widget* child = new Widget;
306 Widget::InitParams child_params =
307 CreateParams(Widget::InitParams::TYPE_POPUP);
308 child_params.child = true;
309 child_params.native_widget = CreatePlatformNativeWidget(child);
310 child_params.parent = parent_native_view;
311 child->Init(child_params);
312 child->SetContentsView(new View);
313 return child;
315 #endif
317 Widget* CreateTopLevelNativeWidget() {
318 Widget* toplevel = new Widget;
319 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
320 toplevel->Init(params);
321 return toplevel;
324 Widget* CreateChildNativeWidgetWithParent(Widget* parent) {
325 Widget* child = new Widget;
326 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_CONTROL);
327 params.parent = parent->GetNativeView();
328 child->Init(params);
329 child->SetContentsView(new View);
330 return child;
333 Widget* CreateChildNativeWidget() {
334 return CreateChildNativeWidgetWithParent(NULL);
338 bool WidgetHasMouseCapture(const Widget* widget) {
339 return static_cast<const internal::NativeWidgetPrivate*>(widget->
340 native_widget())->HasCapture();
343 ui::WindowShowState GetWidgetShowState(const Widget* widget) {
344 // Use IsMaximized/IsMinimized/IsFullScreen instead of GetWindowPlacement
345 // because the former is implemented on all platforms but the latter is not.
346 return widget->IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN :
347 widget->IsMaximized() ? ui::SHOW_STATE_MAXIMIZED :
348 widget->IsMinimized() ? ui::SHOW_STATE_MINIMIZED :
349 ui::SHOW_STATE_NORMAL;
352 TEST_F(WidgetTest, WidgetInitParams) {
353 ASSERT_FALSE(views_delegate().UseTransparentWindows());
355 // Widgets are not transparent by default.
356 Widget::InitParams init1;
357 EXPECT_FALSE(init1.transparent);
359 // Non-window widgets are not transparent either.
360 Widget::InitParams init2(Widget::InitParams::TYPE_MENU);
361 EXPECT_FALSE(init2.transparent);
363 // A ViewsDelegate can set windows transparent by default.
364 views_delegate().SetUseTransparentWindows(true);
365 Widget::InitParams init3;
366 EXPECT_TRUE(init3.transparent);
368 // Non-window widgets stay opaque.
369 Widget::InitParams init4(Widget::InitParams::TYPE_MENU);
370 EXPECT_FALSE(init4.transparent);
373 ////////////////////////////////////////////////////////////////////////////////
374 // Widget::GetTopLevelWidget tests.
376 TEST_F(WidgetTest, GetTopLevelWidget_Native) {
377 // Create a hierarchy of native widgets.
378 Widget* toplevel = CreateTopLevelPlatformWidget();
379 gfx::NativeView parent = toplevel->GetNativeView();
380 Widget* child = CreateChildPlatformWidget(parent);
382 EXPECT_EQ(toplevel, toplevel->GetTopLevelWidget());
383 EXPECT_EQ(toplevel, child->GetTopLevelWidget());
385 toplevel->CloseNow();
386 // |child| should be automatically destroyed with |toplevel|.
389 // Tests some grab/ungrab events.
390 TEST_F(WidgetTest, DISABLED_GrabUngrab) {
391 Widget* toplevel = CreateTopLevelPlatformWidget();
392 Widget* child1 = CreateChildNativeWidgetWithParent(toplevel);
393 Widget* child2 = CreateChildNativeWidgetWithParent(toplevel);
395 toplevel->SetBounds(gfx::Rect(0, 0, 500, 500));
397 child1->SetBounds(gfx::Rect(10, 10, 300, 300));
398 View* view = new MouseView();
399 view->SetBounds(0, 0, 300, 300);
400 child1->GetRootView()->AddChildView(view);
402 child2->SetBounds(gfx::Rect(200, 10, 200, 200));
403 view = new MouseView();
404 view->SetBounds(0, 0, 200, 200);
405 child2->GetRootView()->AddChildView(view);
407 toplevel->Show();
408 RunPendingMessages();
410 // Click on child1
411 gfx::Point p1(45, 45);
412 ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, p1, p1,
413 ui::EF_LEFT_MOUSE_BUTTON);
414 toplevel->OnMouseEvent(&pressed);
416 EXPECT_TRUE(WidgetHasMouseCapture(toplevel));
417 EXPECT_TRUE(WidgetHasMouseCapture(child1));
418 EXPECT_FALSE(WidgetHasMouseCapture(child2));
420 ui::MouseEvent released(ui::ET_MOUSE_RELEASED, p1, p1,
421 ui::EF_LEFT_MOUSE_BUTTON);
422 toplevel->OnMouseEvent(&released);
424 EXPECT_FALSE(WidgetHasMouseCapture(toplevel));
425 EXPECT_FALSE(WidgetHasMouseCapture(child1));
426 EXPECT_FALSE(WidgetHasMouseCapture(child2));
428 RunPendingMessages();
430 // Click on child2
431 gfx::Point p2(315, 45);
432 ui::MouseEvent pressed2(ui::ET_MOUSE_PRESSED, p2, p2,
433 ui::EF_LEFT_MOUSE_BUTTON);
434 toplevel->OnMouseEvent(&pressed2);
435 EXPECT_TRUE(pressed2.handled());
436 EXPECT_TRUE(WidgetHasMouseCapture(toplevel));
437 EXPECT_TRUE(WidgetHasMouseCapture(child2));
438 EXPECT_FALSE(WidgetHasMouseCapture(child1));
440 ui::MouseEvent released2(ui::ET_MOUSE_RELEASED, p2, p2,
441 ui::EF_LEFT_MOUSE_BUTTON);
442 toplevel->OnMouseEvent(&released2);
443 EXPECT_FALSE(WidgetHasMouseCapture(toplevel));
444 EXPECT_FALSE(WidgetHasMouseCapture(child1));
445 EXPECT_FALSE(WidgetHasMouseCapture(child2));
447 toplevel->CloseNow();
450 // Tests mouse move outside of the window into the "resize controller" and back
451 // will still generate an OnMouseEntered and OnMouseExited event..
452 TEST_F(WidgetTest, CheckResizeControllerEvents) {
453 Widget* toplevel = CreateTopLevelPlatformWidget();
455 toplevel->SetBounds(gfx::Rect(0, 0, 100, 100));
457 MouseView* view = new MouseView();
458 view->SetBounds(90, 90, 10, 10);
459 toplevel->GetRootView()->AddChildView(view);
461 toplevel->Show();
462 RunPendingMessages();
464 // Move to an outside position.
465 gfx::Point p1(200, 200);
466 ui::MouseEvent moved_out(ui::ET_MOUSE_MOVED, p1, p1, ui::EF_NONE);
467 toplevel->OnMouseEvent(&moved_out);
468 EXPECT_EQ(0, view->EnteredCalls());
469 EXPECT_EQ(0, view->ExitedCalls());
471 // Move onto the active view.
472 gfx::Point p2(95, 95);
473 ui::MouseEvent moved_over(ui::ET_MOUSE_MOVED, p2, p2, ui::EF_NONE);
474 toplevel->OnMouseEvent(&moved_over);
475 EXPECT_EQ(1, view->EnteredCalls());
476 EXPECT_EQ(0, view->ExitedCalls());
478 // Move onto the outer resizing border.
479 gfx::Point p3(102, 95);
480 ui::MouseEvent moved_resizer(ui::ET_MOUSE_MOVED, p3, p3, ui::EF_NONE);
481 toplevel->OnMouseEvent(&moved_resizer);
482 EXPECT_EQ(0, view->EnteredCalls());
483 EXPECT_EQ(1, view->ExitedCalls());
485 // Move onto the view again.
486 toplevel->OnMouseEvent(&moved_over);
487 EXPECT_EQ(1, view->EnteredCalls());
488 EXPECT_EQ(0, view->ExitedCalls());
490 RunPendingMessages();
492 toplevel->CloseNow();
495 // Test if a focus manager and an inputmethod work without CHECK failure
496 // when window activation changes.
497 TEST_F(WidgetTest, ChangeActivation) {
498 Widget* top1 = CreateTopLevelPlatformWidget();
499 // CreateInputMethod before activated
500 top1->GetInputMethod();
501 top1->Show();
502 RunPendingMessages();
504 Widget* top2 = CreateTopLevelPlatformWidget();
505 top2->Show();
506 RunPendingMessages();
508 top1->Activate();
509 RunPendingMessages();
511 // Create InputMethod after deactivated.
512 top2->GetInputMethod();
513 top2->Activate();
514 RunPendingMessages();
516 top1->Activate();
517 RunPendingMessages();
519 top1->CloseNow();
520 top2->CloseNow();
523 // Tests visibility of child widgets.
524 TEST_F(WidgetTest, Visibility) {
525 Widget* toplevel = CreateTopLevelPlatformWidget();
526 gfx::NativeView parent = toplevel->GetNativeView();
527 Widget* child = CreateChildPlatformWidget(parent);
529 EXPECT_FALSE(toplevel->IsVisible());
530 EXPECT_FALSE(child->IsVisible());
532 child->Show();
534 EXPECT_FALSE(toplevel->IsVisible());
535 EXPECT_FALSE(child->IsVisible());
537 toplevel->Show();
539 EXPECT_TRUE(toplevel->IsVisible());
540 EXPECT_TRUE(child->IsVisible());
542 toplevel->CloseNow();
543 // |child| should be automatically destroyed with |toplevel|.
546 #if defined(OS_WIN) && !defined(USE_AURA)
547 // On Windows, it is possible to have child window that are TYPE_POPUP. Unlike
548 // regular child windows, these should be created as hidden and must be shown
549 // explicitly.
550 TEST_F(WidgetTest, Visibility_ChildPopup) {
551 Widget* toplevel = CreateTopLevelPlatformWidget();
552 Widget* child_popup = CreateChildPopupPlatformWidget(
553 toplevel->GetNativeView());
555 EXPECT_FALSE(toplevel->IsVisible());
556 EXPECT_FALSE(child_popup->IsVisible());
558 toplevel->Show();
560 EXPECT_TRUE(toplevel->IsVisible());
561 EXPECT_FALSE(child_popup->IsVisible());
563 child_popup->Show();
565 EXPECT_TRUE(child_popup->IsVisible());
567 toplevel->CloseNow();
568 // |child_popup| should be automatically destroyed with |toplevel|.
570 #endif
572 ////////////////////////////////////////////////////////////////////////////////
573 // Widget ownership tests.
575 // Tests various permutations of Widget ownership specified in the
576 // InitParams::Ownership param.
578 // A WidgetTest that supplies a toplevel widget for NativeWidget to parent to.
579 class WidgetOwnershipTest : public WidgetTest {
580 public:
581 WidgetOwnershipTest() {}
582 virtual ~WidgetOwnershipTest() {}
584 virtual void SetUp() {
585 WidgetTest::SetUp();
586 desktop_widget_ = CreateTopLevelPlatformWidget();
589 virtual void TearDown() {
590 desktop_widget_->CloseNow();
591 WidgetTest::TearDown();
594 private:
595 Widget* desktop_widget_;
597 DISALLOW_COPY_AND_ASSIGN(WidgetOwnershipTest);
600 // A bag of state to monitor destructions.
601 struct OwnershipTestState {
602 OwnershipTestState() : widget_deleted(false), native_widget_deleted(false) {}
604 bool widget_deleted;
605 bool native_widget_deleted;
608 // A platform NativeWidget subclass that updates a bag of state when it is
609 // destroyed.
610 class OwnershipTestNativeWidget : public NativeWidgetPlatform {
611 public:
612 OwnershipTestNativeWidget(internal::NativeWidgetDelegate* delegate,
613 OwnershipTestState* state)
614 : NativeWidgetPlatform(delegate),
615 state_(state) {
617 virtual ~OwnershipTestNativeWidget() {
618 state_->native_widget_deleted = true;
621 private:
622 OwnershipTestState* state_;
624 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidget);
627 // A views NativeWidget subclass that updates a bag of state when it is
628 // destroyed.
629 class OwnershipTestNativeWidgetPlatform : public NativeWidgetPlatformForTest {
630 public:
631 OwnershipTestNativeWidgetPlatform(internal::NativeWidgetDelegate* delegate,
632 OwnershipTestState* state)
633 : NativeWidgetPlatformForTest(delegate),
634 state_(state) {
636 virtual ~OwnershipTestNativeWidgetPlatform() {
637 state_->native_widget_deleted = true;
640 private:
641 OwnershipTestState* state_;
643 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetPlatform);
646 // A Widget subclass that updates a bag of state when it is destroyed.
647 class OwnershipTestWidget : public Widget {
648 public:
649 explicit OwnershipTestWidget(OwnershipTestState* state) : state_(state) {}
650 virtual ~OwnershipTestWidget() {
651 state_->widget_deleted = true;
654 private:
655 OwnershipTestState* state_;
657 DISALLOW_COPY_AND_ASSIGN(OwnershipTestWidget);
660 // Widget owns its NativeWidget, part 1: NativeWidget is a platform-native
661 // widget.
662 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsPlatformNativeWidget) {
663 OwnershipTestState state;
665 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
666 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
667 params.native_widget =
668 new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
669 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
670 widget->Init(params);
672 // Now delete the Widget, which should delete the NativeWidget.
673 widget.reset();
675 EXPECT_TRUE(state.widget_deleted);
676 EXPECT_TRUE(state.native_widget_deleted);
678 // TODO(beng): write test for this ownership scenario and the NativeWidget
679 // being deleted out from under the Widget.
682 // Widget owns its NativeWidget, part 2: NativeWidget is a NativeWidget.
683 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsViewsNativeWidget) {
684 OwnershipTestState state;
686 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
687 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
688 params.native_widget =
689 new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
690 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
691 widget->Init(params);
693 // Now delete the Widget, which should delete the NativeWidget.
694 widget.reset();
696 EXPECT_TRUE(state.widget_deleted);
697 EXPECT_TRUE(state.native_widget_deleted);
699 // TODO(beng): write test for this ownership scenario and the NativeWidget
700 // being deleted out from under the Widget.
703 // Widget owns its NativeWidget, part 3: NativeWidget is a NativeWidget,
704 // destroy the parent view.
705 TEST_F(WidgetOwnershipTest,
706 Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView) {
707 OwnershipTestState state;
709 Widget* toplevel = CreateTopLevelPlatformWidget();
711 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
712 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
713 params.native_widget =
714 new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
715 params.parent = toplevel->GetNativeView();
716 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
717 widget->Init(params);
719 // Now close the toplevel, which deletes the view hierarchy.
720 toplevel->CloseNow();
722 RunPendingMessages();
724 // This shouldn't delete the widget because it shouldn't be deleted
725 // from the native side.
726 EXPECT_FALSE(state.widget_deleted);
727 EXPECT_FALSE(state.native_widget_deleted);
729 // Now delete it explicitly.
730 widget.reset();
732 EXPECT_TRUE(state.widget_deleted);
733 EXPECT_TRUE(state.native_widget_deleted);
736 // NativeWidget owns its Widget, part 1: NativeWidget is a platform-native
737 // widget.
738 TEST_F(WidgetOwnershipTest, Ownership_PlatformNativeWidgetOwnsWidget) {
739 OwnershipTestState state;
741 Widget* widget = new OwnershipTestWidget(&state);
742 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
743 params.native_widget =
744 new OwnershipTestNativeWidgetPlatform(widget, &state);
745 widget->Init(params);
747 // Now destroy the native widget.
748 widget->CloseNow();
750 EXPECT_TRUE(state.widget_deleted);
751 EXPECT_TRUE(state.native_widget_deleted);
754 // NativeWidget owns its Widget, part 2: NativeWidget is a NativeWidget.
755 TEST_F(WidgetOwnershipTest, Ownership_ViewsNativeWidgetOwnsWidget) {
756 OwnershipTestState state;
758 Widget* toplevel = CreateTopLevelPlatformWidget();
760 Widget* widget = new OwnershipTestWidget(&state);
761 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
762 params.native_widget =
763 new OwnershipTestNativeWidgetPlatform(widget, &state);
764 params.parent = toplevel->GetNativeView();
765 widget->Init(params);
767 // Now destroy the native widget. This is achieved by closing the toplevel.
768 toplevel->CloseNow();
770 // The NativeWidget won't be deleted until after a return to the message loop
771 // so we have to run pending messages before testing the destruction status.
772 RunPendingMessages();
774 EXPECT_TRUE(state.widget_deleted);
775 EXPECT_TRUE(state.native_widget_deleted);
778 // NativeWidget owns its Widget, part 3: NativeWidget is a platform-native
779 // widget, destroyed out from under it by the OS.
780 TEST_F(WidgetOwnershipTest,
781 Ownership_PlatformNativeWidgetOwnsWidget_NativeDestroy) {
782 OwnershipTestState state;
784 Widget* widget = new OwnershipTestWidget(&state);
785 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
786 params.native_widget =
787 new OwnershipTestNativeWidgetPlatform(widget, &state);
788 widget->Init(params);
790 // Now simulate a destroy of the platform native widget from the OS:
791 #if defined(USE_AURA)
792 delete widget->GetNativeView();
793 #elif defined(OS_WIN)
794 DestroyWindow(widget->GetNativeView());
795 #endif
797 EXPECT_TRUE(state.widget_deleted);
798 EXPECT_TRUE(state.native_widget_deleted);
801 // NativeWidget owns its Widget, part 4: NativeWidget is a NativeWidget,
802 // destroyed by the view hierarchy that contains it.
803 TEST_F(WidgetOwnershipTest,
804 Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy) {
805 OwnershipTestState state;
807 Widget* toplevel = CreateTopLevelPlatformWidget();
809 Widget* widget = new OwnershipTestWidget(&state);
810 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
811 params.native_widget =
812 new OwnershipTestNativeWidgetPlatform(widget, &state);
813 params.parent = toplevel->GetNativeView();
814 widget->Init(params);
816 // Destroy the widget (achieved by closing the toplevel).
817 toplevel->CloseNow();
819 // The NativeWidget won't be deleted until after a return to the message loop
820 // so we have to run pending messages before testing the destruction status.
821 RunPendingMessages();
823 EXPECT_TRUE(state.widget_deleted);
824 EXPECT_TRUE(state.native_widget_deleted);
827 // NativeWidget owns its Widget, part 5: NativeWidget is a NativeWidget,
828 // we close it directly.
829 TEST_F(WidgetOwnershipTest,
830 Ownership_ViewsNativeWidgetOwnsWidget_Close) {
831 OwnershipTestState state;
833 Widget* toplevel = CreateTopLevelPlatformWidget();
835 Widget* widget = new OwnershipTestWidget(&state);
836 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
837 params.native_widget =
838 new OwnershipTestNativeWidgetPlatform(widget, &state);
839 params.parent = toplevel->GetNativeView();
840 widget->Init(params);
842 // Destroy the widget.
843 widget->Close();
844 toplevel->CloseNow();
846 // The NativeWidget won't be deleted until after a return to the message loop
847 // so we have to run pending messages before testing the destruction status.
848 RunPendingMessages();
850 EXPECT_TRUE(state.widget_deleted);
851 EXPECT_TRUE(state.native_widget_deleted);
854 // Widget owns its NativeWidget and has a WidgetDelegateView as its contents.
855 TEST_F(WidgetOwnershipTest,
856 Ownership_WidgetOwnsNativeWidgetWithWithWidgetDelegateView) {
857 OwnershipTestState state;
859 WidgetDelegateView* delegate_view = new WidgetDelegateView;
861 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
862 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
863 params.native_widget =
864 new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
865 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
866 params.delegate = delegate_view;
867 widget->Init(params);
868 widget->SetContentsView(delegate_view);
870 // Now delete the Widget. There should be no crash or use-after-free.
871 widget.reset();
873 EXPECT_TRUE(state.widget_deleted);
874 EXPECT_TRUE(state.native_widget_deleted);
877 ////////////////////////////////////////////////////////////////////////////////
878 // Widget observer tests.
881 class WidgetObserverTest : public WidgetTest, public WidgetObserver {
882 public:
883 WidgetObserverTest()
884 : active_(NULL),
885 widget_closed_(NULL),
886 widget_activated_(NULL),
887 widget_shown_(NULL),
888 widget_hidden_(NULL),
889 widget_bounds_changed_(NULL) {
892 virtual ~WidgetObserverTest() {}
894 // Overridden from WidgetObserver:
895 virtual void OnWidgetDestroying(Widget* widget) OVERRIDE {
896 if (active_ == widget)
897 active_ = NULL;
898 widget_closed_ = widget;
901 virtual void OnWidgetActivationChanged(Widget* widget,
902 bool active) OVERRIDE {
903 if (active) {
904 if (widget_activated_)
905 widget_activated_->Deactivate();
906 widget_activated_ = widget;
907 active_ = widget;
908 } else {
909 if (widget_activated_ == widget)
910 widget_activated_ = NULL;
911 widget_deactivated_ = widget;
915 virtual void OnWidgetVisibilityChanged(Widget* widget,
916 bool visible) OVERRIDE {
917 if (visible)
918 widget_shown_ = widget;
919 else
920 widget_hidden_ = widget;
923 virtual void OnWidgetBoundsChanged(Widget* widget,
924 const gfx::Rect& new_bounds) OVERRIDE {
925 widget_bounds_changed_ = widget;
928 void reset() {
929 active_ = NULL;
930 widget_closed_ = NULL;
931 widget_activated_ = NULL;
932 widget_deactivated_ = NULL;
933 widget_shown_ = NULL;
934 widget_hidden_ = NULL;
935 widget_bounds_changed_ = NULL;
938 Widget* NewWidget() {
939 Widget* widget = CreateTopLevelNativeWidget();
940 widget->AddObserver(this);
941 return widget;
944 const Widget* active() const { return active_; }
945 const Widget* widget_closed() const { return widget_closed_; }
946 const Widget* widget_activated() const { return widget_activated_; }
947 const Widget* widget_deactivated() const { return widget_deactivated_; }
948 const Widget* widget_shown() const { return widget_shown_; }
949 const Widget* widget_hidden() const { return widget_hidden_; }
950 const Widget* widget_bounds_changed() const { return widget_bounds_changed_; }
952 private:
953 Widget* active_;
955 Widget* widget_closed_;
956 Widget* widget_activated_;
957 Widget* widget_deactivated_;
958 Widget* widget_shown_;
959 Widget* widget_hidden_;
960 Widget* widget_bounds_changed_;
963 TEST_F(WidgetObserverTest, DISABLED_ActivationChange) {
964 Widget* toplevel = CreateTopLevelPlatformWidget();
966 Widget* toplevel1 = NewWidget();
967 Widget* toplevel2 = NewWidget();
969 toplevel1->Show();
970 toplevel2->Show();
972 reset();
974 toplevel1->Activate();
976 RunPendingMessages();
977 EXPECT_EQ(toplevel1, widget_activated());
979 toplevel2->Activate();
980 RunPendingMessages();
981 EXPECT_EQ(toplevel1, widget_deactivated());
982 EXPECT_EQ(toplevel2, widget_activated());
983 EXPECT_EQ(toplevel2, active());
985 toplevel->CloseNow();
988 TEST_F(WidgetObserverTest, DISABLED_VisibilityChange) {
989 Widget* toplevel = CreateTopLevelPlatformWidget();
991 Widget* child1 = NewWidget();
992 Widget* child2 = NewWidget();
994 toplevel->Show();
995 child1->Show();
996 child2->Show();
998 reset();
1000 child1->Hide();
1001 EXPECT_EQ(child1, widget_hidden());
1003 child2->Hide();
1004 EXPECT_EQ(child2, widget_hidden());
1006 child1->Show();
1007 EXPECT_EQ(child1, widget_shown());
1009 child2->Show();
1010 EXPECT_EQ(child2, widget_shown());
1012 toplevel->CloseNow();
1015 TEST_F(WidgetObserverTest, DestroyBubble) {
1016 Widget* anchor = CreateTopLevelPlatformWidget();
1017 anchor->Show();
1019 BubbleDelegateView* bubble_delegate =
1020 new BubbleDelegateView(anchor->client_view(), BubbleBorder::NONE);
1021 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
1022 bubble_widget->Show();
1023 bubble_widget->CloseNow();
1025 anchor->Hide();
1026 anchor->CloseNow();
1029 TEST_F(WidgetObserverTest, WidgetBoundsChanged) {
1030 Widget* child1 = NewWidget();
1031 Widget* child2 = NewWidget();
1033 child1->OnNativeWidgetMove();
1034 EXPECT_EQ(child1, widget_bounds_changed());
1036 child2->OnNativeWidgetMove();
1037 EXPECT_EQ(child2, widget_bounds_changed());
1039 child1->OnNativeWidgetSizeChanged(gfx::Size());
1040 EXPECT_EQ(child1, widget_bounds_changed());
1042 child2->OnNativeWidgetSizeChanged(gfx::Size());
1043 EXPECT_EQ(child2, widget_bounds_changed());
1046 #if !defined(USE_AURA) && defined(OS_WIN)
1047 // Aura needs shell to maximize/fullscreen window.
1048 // NativeWidgetGtk doesn't implement GetRestoredBounds.
1049 TEST_F(WidgetTest, GetRestoredBounds) {
1050 Widget* toplevel = CreateTopLevelPlatformWidget();
1051 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
1052 toplevel->GetRestoredBounds().ToString());
1053 toplevel->Show();
1054 toplevel->Maximize();
1055 RunPendingMessages();
1056 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
1057 toplevel->GetRestoredBounds().ToString());
1058 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
1059 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
1061 toplevel->Restore();
1062 RunPendingMessages();
1063 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
1064 toplevel->GetRestoredBounds().ToString());
1066 toplevel->SetFullscreen(true);
1067 RunPendingMessages();
1068 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
1069 toplevel->GetRestoredBounds().ToString());
1070 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
1071 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
1073 #endif
1075 // Test that window state is not changed after getting out of full screen.
1076 TEST_F(WidgetTest, ExitFullscreenRestoreState) {
1077 Widget* toplevel = CreateTopLevelPlatformWidget();
1079 toplevel->Show();
1080 RunPendingMessages();
1082 // This should be a normal state window.
1083 EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
1085 toplevel->SetFullscreen(true);
1086 while (GetWidgetShowState(toplevel) != ui::SHOW_STATE_FULLSCREEN)
1087 RunPendingMessages();
1088 toplevel->SetFullscreen(false);
1089 while (GetWidgetShowState(toplevel) == ui::SHOW_STATE_FULLSCREEN)
1090 RunPendingMessages();
1092 // And it should still be in normal state after getting out of full screen.
1093 EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
1095 // Now, make it maximized.
1096 toplevel->Maximize();
1097 while (GetWidgetShowState(toplevel) != ui::SHOW_STATE_MAXIMIZED)
1098 RunPendingMessages();
1100 toplevel->SetFullscreen(true);
1101 while (GetWidgetShowState(toplevel) != ui::SHOW_STATE_FULLSCREEN)
1102 RunPendingMessages();
1103 toplevel->SetFullscreen(false);
1104 while (GetWidgetShowState(toplevel) == ui::SHOW_STATE_FULLSCREEN)
1105 RunPendingMessages();
1107 // And it stays maximized after getting out of full screen.
1108 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
1110 // Clean up.
1111 toplevel->Close();
1112 RunPendingMessages();
1115 TEST_F(WidgetTest, ResetCaptureOnGestureEnd) {
1116 Widget* toplevel = CreateTopLevelFramelessPlatformWidget();
1117 View* container = new View;
1118 toplevel->SetContentsView(container);
1120 View* gesture = new GestureCaptureView;
1121 gesture->SetBounds(0, 0, 30, 30);
1122 container->AddChildView(gesture);
1124 MouseView* mouse = new MouseView;
1125 mouse->SetBounds(30, 0, 30, 30);
1126 container->AddChildView(mouse);
1128 toplevel->SetSize(gfx::Size(100, 100));
1129 toplevel->Show();
1131 // Start a gesture on |gesture|.
1132 ui::GestureEvent begin(ui::ET_GESTURE_BEGIN,
1133 15, 15, 0, base::TimeDelta(),
1134 ui::GestureEventDetails(ui::ET_GESTURE_BEGIN, 0, 0), 1);
1135 ui::GestureEvent end(ui::ET_GESTURE_END,
1136 15, 15, 0, base::TimeDelta(),
1137 ui::GestureEventDetails(ui::ET_GESTURE_END, 0, 0), 1);
1138 toplevel->OnGestureEvent(&begin);
1140 // Now try to click on |mouse|. Since |gesture| will have capture, |mouse|
1141 // will not receive the event.
1142 gfx::Point click_location(45, 15);
1144 ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
1145 ui::EF_LEFT_MOUSE_BUTTON);
1146 ui::MouseEvent release(ui::ET_MOUSE_RELEASED, click_location, click_location,
1147 ui::EF_LEFT_MOUSE_BUTTON);
1149 toplevel->OnMouseEvent(&press);
1150 toplevel->OnMouseEvent(&release);
1151 EXPECT_EQ(0, mouse->pressed());
1153 // The end of the gesture should release the capture, and pressing on |mouse|
1154 // should now reach |mouse|.
1155 toplevel->OnGestureEvent(&end);
1156 toplevel->OnMouseEvent(&press);
1157 toplevel->OnMouseEvent(&release);
1158 EXPECT_EQ(1, mouse->pressed());
1160 toplevel->Close();
1161 RunPendingMessages();
1164 #if defined(USE_AURA)
1165 // The key-event propagation from Widget happens differently on aura and
1166 // non-aura systems because of the difference in IME. So this test works only on
1167 // aura.
1168 TEST_F(WidgetTest, KeyboardInputEvent) {
1169 Widget* toplevel = CreateTopLevelPlatformWidget();
1170 View* container = toplevel->client_view();
1172 Textfield* textfield = new Textfield();
1173 textfield->SetText(ASCIIToUTF16("some text"));
1174 container->AddChildView(textfield);
1175 toplevel->Show();
1176 textfield->RequestFocus();
1178 // The press gets handled. The release doesn't have an effect.
1179 ui::KeyEvent backspace_p(ui::ET_KEY_PRESSED, ui::VKEY_DELETE, 0, false);
1180 toplevel->OnKeyEvent(&backspace_p);
1181 EXPECT_TRUE(backspace_p.stopped_propagation());
1182 ui::KeyEvent backspace_r(ui::ET_KEY_RELEASED, ui::VKEY_DELETE, 0, false);
1183 toplevel->OnKeyEvent(&backspace_r);
1184 EXPECT_FALSE(backspace_r.handled());
1186 toplevel->Close();
1189 // Verifies bubbles result in a focus lost when shown.
1190 TEST_F(WidgetTest, FocusChangesOnBubble) {
1191 // Create a widget, show and activate it and focus the contents view.
1192 View* contents_view = new View;
1193 contents_view->set_focusable(true);
1194 Widget widget;
1195 Widget::InitParams init_params =
1196 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1197 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1198 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1199 #if !defined(OS_CHROMEOS)
1200 init_params.native_widget = new DesktopNativeWidgetAura(&widget);
1201 #endif
1202 widget.Init(init_params);
1203 widget.SetContentsView(contents_view);
1204 widget.Show();
1205 widget.Activate();
1206 contents_view->RequestFocus();
1207 EXPECT_TRUE(contents_view->HasFocus());
1209 // Show a bubble.
1210 BubbleDelegateView* bubble_delegate_view =
1211 new BubbleDelegateView(contents_view, BubbleBorder::TOP_LEFT);
1212 bubble_delegate_view->set_focusable(true);
1213 BubbleDelegateView::CreateBubble(bubble_delegate_view)->Show();
1214 bubble_delegate_view->RequestFocus();
1216 // |contents_view_| should no longer have focus.
1217 EXPECT_FALSE(contents_view->HasFocus());
1218 EXPECT_TRUE(bubble_delegate_view->HasFocus());
1220 bubble_delegate_view->GetWidget()->CloseNow();
1222 // Closing the bubble should result in focus going back to the contents view.
1223 EXPECT_TRUE(contents_view->HasFocus());
1226 // Desktop native widget Aura tests are for non Chrome OS platforms.
1227 #if !defined(OS_CHROMEOS)
1228 // Test to ensure that after minimize, view width is set to zero.
1229 TEST_F(WidgetTest, TestViewWidthAfterMinimizingWidget) {
1230 // Create a widget.
1231 Widget widget;
1232 Widget::InitParams init_params =
1233 CreateParams(Widget::InitParams::TYPE_WINDOW);
1234 init_params.show_state = ui::SHOW_STATE_NORMAL;
1235 gfx::Rect initial_bounds(0, 0, 300, 400);
1236 init_params.bounds = initial_bounds;
1237 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1238 init_params.native_widget = new DesktopNativeWidgetAura(&widget);
1239 widget.Init(init_params);
1240 NonClientView* non_client_view = widget.non_client_view();
1241 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1242 non_client_view->SetFrameView(frame_view);
1243 widget.Show();
1244 widget.Minimize();
1245 EXPECT_EQ(0, frame_view->width());
1248 // This class validates whether paints are received for a visible Widget.
1249 // To achieve this it overrides the Show and Close methods on the Widget class
1250 // and sets state whether subsequent paints are expected.
1251 class DesktopAuraTestValidPaintWidget : public views::Widget {
1252 public:
1253 DesktopAuraTestValidPaintWidget()
1254 : expect_paint_(true),
1255 received_paint_while_hidden_(false) {
1258 virtual ~DesktopAuraTestValidPaintWidget() {
1261 virtual void Show() OVERRIDE {
1262 expect_paint_ = true;
1263 views::Widget::Show();
1266 virtual void Close() OVERRIDE {
1267 expect_paint_ = false;
1268 views::Widget::Close();
1271 void Hide() {
1272 expect_paint_ = false;
1273 views::Widget::Hide();
1276 virtual void OnNativeWidgetPaint(gfx::Canvas* canvas) OVERRIDE {
1277 EXPECT_TRUE(expect_paint_);
1278 if (!expect_paint_)
1279 received_paint_while_hidden_ = true;
1280 views::Widget::OnNativeWidgetPaint(canvas);
1283 bool received_paint_while_hidden() const {
1284 return received_paint_while_hidden_;
1287 private:
1288 bool expect_paint_;
1289 bool received_paint_while_hidden_;
1292 TEST_F(WidgetTest, DesktopNativeWidgetAuraNoPaintAfterCloseTest) {
1293 View* contents_view = new View;
1294 contents_view->set_focusable(true);
1295 DesktopAuraTestValidPaintWidget widget;
1296 Widget::InitParams init_params =
1297 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1298 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1299 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1300 init_params.native_widget = new DesktopNativeWidgetAura(&widget);
1301 widget.Init(init_params);
1302 widget.SetContentsView(contents_view);
1303 widget.Show();
1304 widget.Activate();
1305 RunPendingMessages();
1306 widget.SchedulePaintInRect(init_params.bounds);
1307 widget.Close();
1308 RunPendingMessages();
1309 EXPECT_FALSE(widget.received_paint_while_hidden());
1312 TEST_F(WidgetTest, DesktopNativeWidgetAuraNoPaintAfterHideTest) {
1313 View* contents_view = new View;
1314 contents_view->set_focusable(true);
1315 DesktopAuraTestValidPaintWidget widget;
1316 Widget::InitParams init_params =
1317 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1318 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1319 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1320 init_params.native_widget = new DesktopNativeWidgetAura(&widget);
1321 widget.Init(init_params);
1322 widget.SetContentsView(contents_view);
1323 widget.Show();
1324 widget.Activate();
1325 RunPendingMessages();
1326 widget.SchedulePaintInRect(init_params.bounds);
1327 widget.Hide();
1328 RunPendingMessages();
1329 EXPECT_FALSE(widget.received_paint_while_hidden());
1330 widget.Close();
1333 // This class provides functionality to test whether the destruction of full
1334 // screen child windows occurs correctly in desktop AURA without crashing.
1335 // It provides facilities to test the following cases:-
1336 // 1. Child window destroyed which should lead to the destruction of the
1337 // parent.
1338 // 2. Parent window destroyed which should lead to the child being destroyed.
1339 class DesktopAuraFullscreenChildWindowDestructionTest
1340 : public views::TestViewsDelegate,
1341 public aura::WindowObserver {
1342 public:
1343 DesktopAuraFullscreenChildWindowDestructionTest()
1344 : full_screen_widget_(NULL),
1345 child_window_(NULL),
1346 parent_destroyed_(false),
1347 child_destroyed_(false) {}
1349 ~DesktopAuraFullscreenChildWindowDestructionTest() {
1350 EXPECT_TRUE(parent_destroyed_);
1351 EXPECT_TRUE(child_destroyed_);
1352 full_screen_widget_ = NULL;
1353 child_window_ = NULL;
1356 // views::TestViewsDelegate overrides.
1357 virtual void OnBeforeWidgetInit(
1358 Widget::InitParams* params,
1359 internal::NativeWidgetDelegate* delegate) OVERRIDE {
1360 if (!params->native_widget)
1361 params->native_widget = new views::DesktopNativeWidgetAura(delegate);
1364 void CreateFullscreenChildWindow(const gfx::Rect& bounds) {
1365 Widget::InitParams init_params;
1366 init_params.type = Widget::InitParams::TYPE_WINDOW;
1367 init_params.bounds = bounds;
1368 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1369 init_params.layer_type = ui::LAYER_NOT_DRAWN;
1371 widget_.Init(init_params);
1373 child_window_ = new aura::Window(&child_window_delegate_);
1374 child_window_->SetType(aura::client::WINDOW_TYPE_NORMAL);
1375 child_window_->Init(ui::LAYER_TEXTURED);
1376 child_window_->SetName("TestFullscreenChildWindow");
1377 child_window_->SetProperty(aura::client::kShowStateKey,
1378 ui::SHOW_STATE_FULLSCREEN);
1379 child_window_->SetDefaultParentByRootWindow(
1380 widget_.GetNativeView()->GetRootWindow(), gfx::Rect(0, 0, 1900, 1600));
1381 child_window_->Show();
1382 child_window_->AddObserver(this);
1384 ASSERT_TRUE(child_window_->parent() != NULL);
1385 child_window_->parent()->AddObserver(this);
1387 full_screen_widget_ =
1388 views::Widget::GetWidgetForNativeView(child_window_->parent());
1389 ASSERT_TRUE(full_screen_widget_ != NULL);
1392 void DestroyChildWindow() {
1393 ASSERT_TRUE(child_window_ != NULL);
1394 delete child_window_;
1397 void DestroyParentWindow() {
1398 ASSERT_TRUE(full_screen_widget_ != NULL);
1399 full_screen_widget_->CloseNow();
1402 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
1403 window->RemoveObserver(this);
1404 if (window == child_window_) {
1405 child_destroyed_ = true;
1406 } else if (window == full_screen_widget_->GetNativeView()) {
1407 parent_destroyed_ = true;
1408 } else {
1409 ADD_FAILURE() << "Unexpected window destroyed callback: " << window;
1413 private:
1414 views::Widget widget_;
1415 views::Widget* full_screen_widget_;
1416 aura::Window* child_window_;
1417 bool parent_destroyed_;
1418 bool child_destroyed_;
1419 aura::test::TestWindowDelegate child_window_delegate_;
1421 DISALLOW_COPY_AND_ASSIGN(DesktopAuraFullscreenChildWindowDestructionTest);
1424 TEST_F(WidgetTest, DesktopAuraFullscreenChildDestroyedBeforeParentTest) {
1425 ViewsDelegate::views_delegate = NULL;
1426 DesktopAuraFullscreenChildWindowDestructionTest full_screen_child_test;
1427 ASSERT_NO_FATAL_FAILURE(full_screen_child_test.CreateFullscreenChildWindow(
1428 gfx::Rect(0, 0, 200, 200)));
1430 RunPendingMessages();
1431 ASSERT_NO_FATAL_FAILURE(full_screen_child_test.DestroyChildWindow());
1432 RunPendingMessages();
1435 TEST_F(WidgetTest, DesktopAuraFullscreenChildParentDestroyed) {
1436 ViewsDelegate::views_delegate = NULL;
1438 DesktopAuraFullscreenChildWindowDestructionTest full_screen_child_test;
1439 ASSERT_NO_FATAL_FAILURE(full_screen_child_test.CreateFullscreenChildWindow(
1440 gfx::Rect(0, 0, 200, 200)));
1442 RunPendingMessages();
1443 ASSERT_NO_FATAL_FAILURE(full_screen_child_test.DestroyParentWindow());
1444 RunPendingMessages();
1447 #endif // !defined(OS_CHROMEOS)
1449 // Tests that wheel events generted from scroll events are targetted to the
1450 // views under the cursor when the focused view does not processed them.
1451 TEST_F(WidgetTest, WheelEventsFromScrollEventTarget) {
1452 EventCountView* focused_view = new EventCountView;
1453 focused_view->set_focusable(true);
1455 EventCountView* cursor_view = new EventCountView;
1457 focused_view->SetBounds(0, 0, 50, 40);
1458 cursor_view->SetBounds(60, 0, 50, 40);
1460 Widget* widget = CreateTopLevelPlatformWidget();
1461 widget->GetRootView()->AddChildView(focused_view);
1462 widget->GetRootView()->AddChildView(cursor_view);
1464 focused_view->RequestFocus();
1465 EXPECT_TRUE(focused_view->HasFocus());
1467 // Generate a scroll event on the cursor view. The focused view will receive a
1468 // wheel event, but since it doesn't process the event, the view under the
1469 // cursor will receive the wheel event.
1470 ui::ScrollEvent scroll(ui::ET_SCROLL,
1471 gfx::Point(65, 5),
1472 ui::EventTimeForNow(),
1474 0, 20,
1475 0, 20,
1477 widget->OnScrollEvent(&scroll);
1479 EXPECT_EQ(0, focused_view->GetEventCount(ui::ET_SCROLL));
1480 EXPECT_EQ(1, focused_view->GetEventCount(ui::ET_MOUSEWHEEL));
1482 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_SCROLL));
1483 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1485 focused_view->ResetCounts();
1486 cursor_view->ResetCounts();
1488 ui::ScrollEvent scroll2(ui::ET_SCROLL,
1489 gfx::Point(5, 5),
1490 ui::EventTimeForNow(),
1492 0, 20,
1493 0, 20,
1495 widget->OnScrollEvent(&scroll2);
1496 EXPECT_EQ(1, focused_view->GetEventCount(ui::ET_SCROLL));
1497 EXPECT_EQ(1, focused_view->GetEventCount(ui::ET_MOUSEWHEEL));
1499 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_SCROLL));
1500 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1502 widget->CloseNow();
1505 #endif // defined(USE_AURA)
1507 // Tests that if a scroll-begin gesture is not handled, then subsequent scroll
1508 // events are not dispatched to any view.
1509 TEST_F(WidgetTest, GestureScrollEventDispatching) {
1510 EventCountView* noscroll_view = new EventCountView;
1511 EventCountView* scroll_view = new ScrollableEventCountView;
1513 noscroll_view->SetBounds(0, 0, 50, 40);
1514 scroll_view->SetBounds(60, 0, 40, 40);
1516 Widget* widget = CreateTopLevelPlatformWidget();
1517 widget->GetRootView()->AddChildView(noscroll_view);
1518 widget->GetRootView()->AddChildView(scroll_view);
1521 ui::GestureEvent begin(ui::ET_GESTURE_SCROLL_BEGIN,
1522 5, 5, 0, base::TimeDelta(),
1523 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0),
1525 widget->OnGestureEvent(&begin);
1526 ui::GestureEvent update(ui::ET_GESTURE_SCROLL_UPDATE,
1527 25, 15, 0, base::TimeDelta(),
1528 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10),
1530 widget->OnGestureEvent(&update);
1531 ui::GestureEvent end(ui::ET_GESTURE_SCROLL_END,
1532 25, 15, 0, base::TimeDelta(),
1533 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END, 0, 0),
1535 widget->OnGestureEvent(&end);
1537 EXPECT_EQ(1, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1538 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1539 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1543 ui::GestureEvent begin(ui::ET_GESTURE_SCROLL_BEGIN,
1544 65, 5, 0, base::TimeDelta(),
1545 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0),
1547 widget->OnGestureEvent(&begin);
1548 ui::GestureEvent update(ui::ET_GESTURE_SCROLL_UPDATE,
1549 85, 15, 0, base::TimeDelta(),
1550 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10),
1552 widget->OnGestureEvent(&update);
1553 ui::GestureEvent end(ui::ET_GESTURE_SCROLL_END,
1554 85, 15, 0, base::TimeDelta(),
1555 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END, 0, 0),
1557 widget->OnGestureEvent(&end);
1559 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1560 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1561 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1564 widget->CloseNow();
1567 // Tests that event-handlers installed on the RootView get triggered correctly.
1568 TEST_F(WidgetTest, EventHandlersOnRootView) {
1569 Widget* widget = CreateTopLevelNativeWidget();
1570 View* root_view = widget->GetRootView();
1572 EventCountView* view = new EventCountView;
1573 view->SetBounds(0, 0, 20, 20);
1574 root_view->AddChildView(view);
1576 EventCountHandler h1;
1577 root_view->AddPreTargetHandler(&h1);
1579 EventCountHandler h2;
1580 root_view->AddPostTargetHandler(&h2);
1582 widget->SetBounds(gfx::Rect(0, 0, 100, 100));
1583 widget->Show();
1585 ui::TouchEvent pressed(ui::ET_TOUCH_PRESSED,
1586 gfx::Point(10, 10),
1587 0, 0,
1588 ui::EventTimeForNow(),
1589 1.0, 0.0, 1.0, 0.0);
1590 widget->OnTouchEvent(&pressed);
1591 EXPECT_EQ(1, h1.GetEventCount(ui::ET_TOUCH_PRESSED));
1592 EXPECT_EQ(1, view->GetEventCount(ui::ET_TOUCH_PRESSED));
1593 EXPECT_EQ(1, h2.GetEventCount(ui::ET_TOUCH_PRESSED));
1595 ui::GestureEvent begin(ui::ET_GESTURE_BEGIN,
1596 5, 5, 0, ui::EventTimeForNow(),
1597 ui::GestureEventDetails(ui::ET_GESTURE_BEGIN, 0, 0), 1);
1598 ui::GestureEvent end(ui::ET_GESTURE_END,
1599 5, 5, 0, ui::EventTimeForNow(),
1600 ui::GestureEventDetails(ui::ET_GESTURE_END, 0, 0), 1);
1601 widget->OnGestureEvent(&begin);
1602 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_BEGIN));
1603 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_BEGIN));
1604 EXPECT_EQ(1, h2.GetEventCount(ui::ET_GESTURE_BEGIN));
1606 ui::TouchEvent released(ui::ET_TOUCH_RELEASED,
1607 gfx::Point(10, 10),
1608 0, 0,
1609 ui::EventTimeForNow(),
1610 1.0, 0.0, 1.0, 0.0);
1611 widget->OnTouchEvent(&released);
1612 EXPECT_EQ(1, h1.GetEventCount(ui::ET_TOUCH_RELEASED));
1613 EXPECT_EQ(1, view->GetEventCount(ui::ET_TOUCH_RELEASED));
1614 EXPECT_EQ(1, h2.GetEventCount(ui::ET_TOUCH_RELEASED));
1616 widget->OnGestureEvent(&end);
1617 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_END));
1618 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_END));
1619 EXPECT_EQ(1, h2.GetEventCount(ui::ET_GESTURE_END));
1621 ui::ScrollEvent scroll(ui::ET_SCROLL,
1622 gfx::Point(5, 5),
1623 ui::EventTimeForNow(),
1625 0, 20,
1626 0, 20,
1628 widget->OnScrollEvent(&scroll);
1629 EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL));
1630 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1631 EXPECT_EQ(1, h2.GetEventCount(ui::ET_SCROLL));
1633 widget->CloseNow();
1636 // Used by SingleWindowClosing to count number of times WindowClosing() has
1637 // been invoked.
1638 class ClosingDelegate : public WidgetDelegate {
1639 public:
1640 ClosingDelegate() : count_(0), widget_(NULL) {}
1642 int count() const { return count_; }
1644 void set_widget(views::Widget* widget) { widget_ = widget; }
1646 // WidgetDelegate overrides:
1647 virtual Widget* GetWidget() OVERRIDE { return widget_; }
1648 virtual const Widget* GetWidget() const OVERRIDE { return widget_; }
1649 virtual void WindowClosing() OVERRIDE {
1650 count_++;
1653 private:
1654 int count_;
1655 views::Widget* widget_;
1657 DISALLOW_COPY_AND_ASSIGN(ClosingDelegate);
1660 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget
1661 // is closed.
1662 TEST_F(WidgetTest, SingleWindowClosing) {
1663 scoped_ptr<ClosingDelegate> delegate(new ClosingDelegate());
1664 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1665 Widget::InitParams init_params =
1666 CreateParams(Widget::InitParams::TYPE_WINDOW);
1667 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1668 init_params.delegate = delegate.get();
1669 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1670 init_params.native_widget = new DesktopNativeWidgetAura(widget);
1671 #endif
1672 widget->Init(init_params);
1673 EXPECT_EQ(0, delegate->count());
1674 widget->CloseNow();
1675 EXPECT_EQ(1, delegate->count());
1678 // Used by SetTopLevelCorrectly to track calls to OnBeforeWidgetInit().
1679 class VerifyTopLevelDelegate : public TestViewsDelegate {
1680 public:
1681 VerifyTopLevelDelegate()
1682 : on_before_init_called_(false),
1683 is_top_level_(false) {
1686 bool on_before_init_called() const { return on_before_init_called_; }
1687 bool is_top_level() const { return is_top_level_; }
1689 virtual void OnBeforeWidgetInit(
1690 Widget::InitParams* params,
1691 internal::NativeWidgetDelegate* delegate) OVERRIDE {
1692 on_before_init_called_ = true;
1693 is_top_level_ = params->top_level;
1696 private:
1697 bool on_before_init_called_;
1698 bool is_top_level_;
1700 DISALLOW_COPY_AND_ASSIGN(VerifyTopLevelDelegate);
1703 // Verifies |top_level| is correctly passed to
1704 // ViewsDelegate::OnBeforeWidgetInit().
1705 TEST_F(WidgetTest, SetTopLevelCorrectly) {
1706 set_views_delegate(NULL);
1707 VerifyTopLevelDelegate* delegate = new VerifyTopLevelDelegate;
1708 set_views_delegate(delegate); // ViewsTestBase takes ownership.
1709 scoped_ptr<Widget> widget(new Widget);
1710 Widget::InitParams params =
1711 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1712 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1713 widget->Init(params);
1714 EXPECT_TRUE(delegate->on_before_init_called());
1715 EXPECT_TRUE(delegate->is_top_level());
1718 // A scumbag View that deletes its owning widget OnMousePressed.
1719 class WidgetDeleterView : public View {
1720 public:
1721 WidgetDeleterView() : View() {}
1723 // Overridden from View.
1724 bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
1725 delete GetWidget();
1726 return true;
1729 private:
1730 DISALLOW_COPY_AND_ASSIGN(WidgetDeleterView);
1733 TEST_F(WidgetTest, TestWidgetDeletedInOnMousePressed) {
1734 Widget* widget = new Widget;
1735 Widget::InitParams params =
1736 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1737 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1738 widget->Init(params);
1740 widget->SetContentsView(new WidgetDeleterView);
1742 widget->SetSize(gfx::Size(100, 100));
1743 widget->Show();
1745 gfx::Point click_location(45, 15);
1746 ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
1747 ui::EF_LEFT_MOUSE_BUTTON);
1748 widget->OnMouseEvent(&press);
1750 // Yay we did not crash!
1753 } // namespace
1754 } // namespace views