widget_unittest.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
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.
4
5#include "base/basictypes.h"
6#include "base/memory/scoped_ptr.h"
7#include "base/message_loop.h"
8#include "base/strings/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"
20
21#if defined(USE_AURA)
22#include "ui/aura/client/aura_constants.h"
23#include "ui/aura/root_window.h"
24#include "ui/aura/test/test_cursor_client.h"
25#include "ui/aura/test/test_window_delegate.h"
26#include "ui/aura/window.h"
27#include "ui/views/widget/native_widget_aura.h"
28#if !defined(OS_CHROMEOS)
29#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
30#endif
31#elif defined(OS_WIN)
32#include "ui/views/widget/native_widget_win.h"
33#endif
34
35namespace views {
36namespace {
37
38// A generic typedef to pick up relevant NativeWidget implementations.
39#if defined(USE_AURA)
40typedef NativeWidgetAura NativeWidgetPlatform;
41#elif defined(OS_WIN)
42typedef NativeWidgetWin NativeWidgetPlatform;
43#endif
44
45// A widget that assumes mouse capture always works. It won't on Aura in
46// testing, so we mock it.
47#if defined(USE_AURA)
48class NativeWidgetCapture : public NativeWidgetPlatform {
49 public:
50  explicit NativeWidgetCapture(internal::NativeWidgetDelegate* delegate)
51      : NativeWidgetPlatform(delegate),
52        mouse_capture_(false) {}
53  virtual ~NativeWidgetCapture() {}
54
55  virtual void SetCapture() OVERRIDE {
56    mouse_capture_ = true;
57  }
58  virtual void ReleaseCapture() OVERRIDE {
59    if (mouse_capture_)
60      delegate()->OnMouseCaptureLost();
61    mouse_capture_ = false;
62  }
63  virtual bool HasCapture() const OVERRIDE {
64    return mouse_capture_;
65  }
66
67 private:
68  bool mouse_capture_;
69
70  DISALLOW_COPY_AND_ASSIGN(NativeWidgetCapture);
71};
72#endif
73
74// A typedef that inserts our mock-capture NativeWidget implementation for
75// relevant platforms.
76#if defined(USE_AURA)
77typedef NativeWidgetCapture NativeWidgetPlatformForTest;
78#elif defined(OS_WIN)
79typedef NativeWidgetWin NativeWidgetPlatformForTest;
80#endif
81
82// A view that always processes all mouse events.
83class MouseView : public View {
84 public:
85  MouseView()
86      : View(),
87        entered_(0),
88        exited_(0),
89        pressed_(0) {
90  }
91  virtual ~MouseView() {}
92
93  virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
94    pressed_++;
95    return true;
96  }
97
98  virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE {
99    entered_++;
100  }
101
102  virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE {
103    exited_++;
104  }
105
106  // Return the number of OnMouseEntered calls and reset the counter.
107  int EnteredCalls() {
108    int i = entered_;
109    entered_ = 0;
110    return i;
111  }
112
113  // Return the number of OnMouseExited calls and reset the counter.
114  int ExitedCalls() {
115    int i = exited_;
116    exited_ = 0;
117    return i;
118  }
119
120  int pressed() const { return pressed_; }
121
122 private:
123  int entered_;
124  int exited_;
125
126  int pressed_;
127
128  DISALLOW_COPY_AND_ASSIGN(MouseView);
129};
130
131// A view that keeps track of the events it receives, but consumes no events.
132class EventCountView : public View {
133 public:
134  EventCountView() {}
135  virtual ~EventCountView() {}
136
137  int GetEventCount(ui::EventType type) {
138    return event_count_[type];
139  }
140
141  void ResetCounts() {
142    event_count_.clear();
143  }
144
145 protected:
146  // Overridden from ui::EventHandler:
147  virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
148    RecordEvent(*event);
149  }
150  virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
151    RecordEvent(*event);
152  }
153  virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE {
154    RecordEvent(*event);
155  }
156  virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE {
157    RecordEvent(*event);
158  }
159  virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
160    RecordEvent(*event);
161  }
162
163 private:
164  void RecordEvent(const ui::Event& event) {
165    ++event_count_[event.type()];
166  }
167
168  std::map<ui::EventType, int> event_count_;
169
170  DISALLOW_COPY_AND_ASSIGN(EventCountView);
171};
172
173// A view that keeps track of the events it receives, and consumes all scroll
174// gesture events.
175class ScrollableEventCountView : public EventCountView {
176 public:
177  ScrollableEventCountView() {}
178  virtual ~ScrollableEventCountView() {}
179
180 private:
181  // Overridden from ui::EventHandler:
182  virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
183    EventCountView::OnGestureEvent(event);
184    switch (event->type()) {
185      case ui::ET_GESTURE_SCROLL_BEGIN:
186      case ui::ET_GESTURE_SCROLL_UPDATE:
187      case ui::ET_GESTURE_SCROLL_END:
188      case ui::ET_SCROLL_FLING_START:
189        event->SetHandled();
190        break;
191      default:
192        break;
193    }
194  }
195
196  DISALLOW_COPY_AND_ASSIGN(ScrollableEventCountView);
197};
198
199// A view that does a capture on gesture-begin events.
200class GestureCaptureView : public View {
201 public:
202  GestureCaptureView() {}
203  virtual ~GestureCaptureView() {}
204
205 private:
206  // Overridden from View:
207  virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
208    if (event->type() == ui::ET_GESTURE_BEGIN) {
209      GetWidget()->SetCapture(this);
210      event->StopPropagation();
211    }
212  }
213
214  DISALLOW_COPY_AND_ASSIGN(GestureCaptureView);
215};
216
217// A view that implements GetMinimumSize.
218class MinimumSizeFrameView : public NativeFrameView {
219 public:
220  explicit MinimumSizeFrameView(Widget* frame): NativeFrameView(frame) {}
221  virtual ~MinimumSizeFrameView() {}
222
223 private:
224  // Overridden from View:
225  virtual gfx::Size GetMinimumSize() OVERRIDE {
226    return gfx::Size(300, 400);
227  }
228
229  DISALLOW_COPY_AND_ASSIGN(MinimumSizeFrameView);
230};
231
232// An event handler that simply keeps a count of the different types of events
233// it receives.
234class EventCountHandler : public ui::EventHandler {
235 public:
236  EventCountHandler() {}
237  virtual ~EventCountHandler() {}
238
239  int GetEventCount(ui::EventType type) {
240    return event_count_[type];
241  }
242
243  void ResetCounts() {
244    event_count_.clear();
245  }
246
247 protected:
248  // Overridden from ui::EventHandler:
249  virtual void OnEvent(ui::Event* event) OVERRIDE {
250    RecordEvent(*event);
251    ui::EventHandler::OnEvent(event);
252  }
253
254 private:
255  void RecordEvent(const ui::Event& event) {
256    ++event_count_[event.type()];
257  }
258
259  std::map<ui::EventType, int> event_count_;
260
261  DISALLOW_COPY_AND_ASSIGN(EventCountHandler);
262};
263
264class WidgetTest : public ViewsTestBase {
265 public:
266  WidgetTest() {}
267  virtual ~WidgetTest() {}
268
269  NativeWidget* CreatePlatformNativeWidget(
270      internal::NativeWidgetDelegate* delegate) {
271    return new NativeWidgetPlatformForTest(delegate);
272  }
273
274  Widget* CreateTopLevelPlatformWidget() {
275    Widget* toplevel = new Widget;
276    Widget::InitParams toplevel_params =
277        CreateParams(Widget::InitParams::TYPE_WINDOW);
278    toplevel_params.native_widget = CreatePlatformNativeWidget(toplevel);
279    toplevel->Init(toplevel_params);
280    return toplevel;
281  }
282
283  Widget* CreateTopLevelFramelessPlatformWidget() {
284    Widget* toplevel = new Widget;
285    Widget::InitParams toplevel_params =
286        CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
287    toplevel_params.native_widget = CreatePlatformNativeWidget(toplevel);
288    toplevel->Init(toplevel_params);
289    return toplevel;
290  }
291
292  Widget* CreateChildPlatformWidget(gfx::NativeView parent_native_view) {
293    Widget* child = new Widget;
294    Widget::InitParams child_params =
295        CreateParams(Widget::InitParams::TYPE_CONTROL);
296    child_params.native_widget = CreatePlatformNativeWidget(child);
297    child_params.parent = parent_native_view;
298    child->Init(child_params);
299    child->SetContentsView(new View);
300    return child;
301  }
302
303#if defined(OS_WIN) && !defined(USE_AURA)
304  // On Windows, it is possible for us to have a child window that is
305  // TYPE_POPUP.
306  Widget* CreateChildPopupPlatformWidget(gfx::NativeView parent_native_view) {
307    Widget* child = new Widget;
308    Widget::InitParams child_params =
309        CreateParams(Widget::InitParams::TYPE_POPUP);
310    child_params.child = true;
311    child_params.native_widget = CreatePlatformNativeWidget(child);
312    child_params.parent = parent_native_view;
313    child->Init(child_params);
314    child->SetContentsView(new View);
315    return child;
316  }
317#endif
318
319  Widget* CreateTopLevelNativeWidget() {
320    Widget* toplevel = new Widget;
321    Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
322    toplevel->Init(params);
323    return toplevel;
324  }
325
326  Widget* CreateChildNativeWidgetWithParent(Widget* parent) {
327    Widget* child = new Widget;
328    Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_CONTROL);
329    params.parent = parent->GetNativeView();
330    child->Init(params);
331    child->SetContentsView(new View);
332    return child;
333  }
334
335  Widget* CreateChildNativeWidget() {
336    return CreateChildNativeWidgetWithParent(NULL);
337  }
338};
339
340bool WidgetHasMouseCapture(const Widget* widget) {
341  return static_cast<const internal::NativeWidgetPrivate*>(widget->
342      native_widget())->HasCapture();
343}
344
345ui::WindowShowState GetWidgetShowState(const Widget* widget) {
346  // Use IsMaximized/IsMinimized/IsFullScreen instead of GetWindowPlacement
347  // because the former is implemented on all platforms but the latter is not.
348  return widget->IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN :
349      widget->IsMaximized() ? ui::SHOW_STATE_MAXIMIZED :
350      widget->IsMinimized() ? ui::SHOW_STATE_MINIMIZED :
351                              ui::SHOW_STATE_NORMAL;
352}
353
354TEST_F(WidgetTest, WidgetInitParams) {
355  ASSERT_FALSE(views_delegate().UseTransparentWindows());
356
357  // Widgets are not transparent by default.
358  Widget::InitParams init1;
359  EXPECT_FALSE(init1.transparent);
360
361  // Non-window widgets are not transparent either.
362  Widget::InitParams init2(Widget::InitParams::TYPE_MENU);
363  EXPECT_FALSE(init2.transparent);
364
365  // A ViewsDelegate can set windows transparent by default.
366  views_delegate().SetUseTransparentWindows(true);
367  Widget::InitParams init3;
368  EXPECT_TRUE(init3.transparent);
369
370  // Non-window widgets stay opaque.
371  Widget::InitParams init4(Widget::InitParams::TYPE_MENU);
372  EXPECT_FALSE(init4.transparent);
373}
374
375////////////////////////////////////////////////////////////////////////////////
376// Widget::GetTopLevelWidget tests.
377
378TEST_F(WidgetTest, GetTopLevelWidget_Native) {
379  // Create a hierarchy of native widgets.
380  Widget* toplevel = CreateTopLevelPlatformWidget();
381  gfx::NativeView parent = toplevel->GetNativeView();
382  Widget* child = CreateChildPlatformWidget(parent);
383
384  EXPECT_EQ(toplevel, toplevel->GetTopLevelWidget());
385  EXPECT_EQ(toplevel, child->GetTopLevelWidget());
386
387  toplevel->CloseNow();
388  // |child| should be automatically destroyed with |toplevel|.
389}
390
391// Tests some grab/ungrab events.
392TEST_F(WidgetTest, DISABLED_GrabUngrab) {
393  Widget* toplevel = CreateTopLevelPlatformWidget();
394  Widget* child1 = CreateChildNativeWidgetWithParent(toplevel);
395  Widget* child2 = CreateChildNativeWidgetWithParent(toplevel);
396
397  toplevel->SetBounds(gfx::Rect(0, 0, 500, 500));
398
399  child1->SetBounds(gfx::Rect(10, 10, 300, 300));
400  View* view = new MouseView();
401  view->SetBounds(0, 0, 300, 300);
402  child1->GetRootView()->AddChildView(view);
403
404  child2->SetBounds(gfx::Rect(200, 10, 200, 200));
405  view = new MouseView();
406  view->SetBounds(0, 0, 200, 200);
407  child2->GetRootView()->AddChildView(view);
408
409  toplevel->Show();
410  RunPendingMessages();
411
412  // Click on child1
413  gfx::Point p1(45, 45);
414  ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, p1, p1,
415                         ui::EF_LEFT_MOUSE_BUTTON);
416  toplevel->OnMouseEvent(&pressed);
417
418  EXPECT_TRUE(WidgetHasMouseCapture(toplevel));
419  EXPECT_TRUE(WidgetHasMouseCapture(child1));
420  EXPECT_FALSE(WidgetHasMouseCapture(child2));
421
422  ui::MouseEvent released(ui::ET_MOUSE_RELEASED, p1, p1,
423                          ui::EF_LEFT_MOUSE_BUTTON);
424  toplevel->OnMouseEvent(&released);
425
426  EXPECT_FALSE(WidgetHasMouseCapture(toplevel));
427  EXPECT_FALSE(WidgetHasMouseCapture(child1));
428  EXPECT_FALSE(WidgetHasMouseCapture(child2));
429
430  RunPendingMessages();
431
432  // Click on child2
433  gfx::Point p2(315, 45);
434  ui::MouseEvent pressed2(ui::ET_MOUSE_PRESSED, p2, p2,
435                          ui::EF_LEFT_MOUSE_BUTTON);
436  toplevel->OnMouseEvent(&pressed2);
437  EXPECT_TRUE(pressed2.handled());
438  EXPECT_TRUE(WidgetHasMouseCapture(toplevel));
439  EXPECT_TRUE(WidgetHasMouseCapture(child2));
440  EXPECT_FALSE(WidgetHasMouseCapture(child1));
441
442  ui::MouseEvent released2(ui::ET_MOUSE_RELEASED, p2, p2,
443                           ui::EF_LEFT_MOUSE_BUTTON);
444  toplevel->OnMouseEvent(&released2);
445  EXPECT_FALSE(WidgetHasMouseCapture(toplevel));
446  EXPECT_FALSE(WidgetHasMouseCapture(child1));
447  EXPECT_FALSE(WidgetHasMouseCapture(child2));
448
449  toplevel->CloseNow();
450}
451
452// Tests mouse move outside of the window into the "resize controller" and back
453// will still generate an OnMouseEntered and OnMouseExited event..
454TEST_F(WidgetTest, CheckResizeControllerEvents) {
455  Widget* toplevel = CreateTopLevelPlatformWidget();
456
457  toplevel->SetBounds(gfx::Rect(0, 0, 100, 100));
458
459  MouseView* view = new MouseView();
460  view->SetBounds(90, 90, 10, 10);
461  toplevel->GetRootView()->AddChildView(view);
462
463  toplevel->Show();
464  RunPendingMessages();
465
466  // Move to an outside position.
467  gfx::Point p1(200, 200);
468  ui::MouseEvent moved_out(ui::ET_MOUSE_MOVED, p1, p1, ui::EF_NONE);
469  toplevel->OnMouseEvent(&moved_out);
470  EXPECT_EQ(0, view->EnteredCalls());
471  EXPECT_EQ(0, view->ExitedCalls());
472
473  // Move onto the active view.
474  gfx::Point p2(95, 95);
475  ui::MouseEvent moved_over(ui::ET_MOUSE_MOVED, p2, p2, ui::EF_NONE);
476  toplevel->OnMouseEvent(&moved_over);
477  EXPECT_EQ(1, view->EnteredCalls());
478  EXPECT_EQ(0, view->ExitedCalls());
479
480  // Move onto the outer resizing border.
481  gfx::Point p3(102, 95);
482  ui::MouseEvent moved_resizer(ui::ET_MOUSE_MOVED, p3, p3, ui::EF_NONE);
483  toplevel->OnMouseEvent(&moved_resizer);
484  EXPECT_EQ(0, view->EnteredCalls());
485  EXPECT_EQ(1, view->ExitedCalls());
486
487  // Move onto the view again.
488  toplevel->OnMouseEvent(&moved_over);
489  EXPECT_EQ(1, view->EnteredCalls());
490  EXPECT_EQ(0, view->ExitedCalls());
491
492  RunPendingMessages();
493
494  toplevel->CloseNow();
495}
496
497// Test if a focus manager and an inputmethod work without CHECK failure
498// when window activation changes.
499TEST_F(WidgetTest, ChangeActivation) {
500  Widget* top1 = CreateTopLevelPlatformWidget();
501  // CreateInputMethod before activated
502  top1->GetInputMethod();
503  top1->Show();
504  RunPendingMessages();
505
506  Widget* top2 = CreateTopLevelPlatformWidget();
507  top2->Show();
508  RunPendingMessages();
509
510  top1->Activate();
511  RunPendingMessages();
512
513  // Create InputMethod after deactivated.
514  top2->GetInputMethod();
515  top2->Activate();
516  RunPendingMessages();
517
518  top1->Activate();
519  RunPendingMessages();
520
521  top1->CloseNow();
522  top2->CloseNow();
523}
524
525// Tests visibility of child widgets.
526TEST_F(WidgetTest, Visibility) {
527  Widget* toplevel = CreateTopLevelPlatformWidget();
528  gfx::NativeView parent = toplevel->GetNativeView();
529  Widget* child = CreateChildPlatformWidget(parent);
530
531  EXPECT_FALSE(toplevel->IsVisible());
532  EXPECT_FALSE(child->IsVisible());
533
534  child->Show();
535
536  EXPECT_FALSE(toplevel->IsVisible());
537  EXPECT_FALSE(child->IsVisible());
538
539  toplevel->Show();
540
541  EXPECT_TRUE(toplevel->IsVisible());
542  EXPECT_TRUE(child->IsVisible());
543
544  toplevel->CloseNow();
545  // |child| should be automatically destroyed with |toplevel|.
546}
547
548#if defined(OS_WIN) && !defined(USE_AURA)
549// On Windows, it is possible to have child window that are TYPE_POPUP.  Unlike
550// regular child windows, these should be created as hidden and must be shown
551// explicitly.
552TEST_F(WidgetTest, Visibility_ChildPopup) {
553  Widget* toplevel = CreateTopLevelPlatformWidget();
554  Widget* child_popup = CreateChildPopupPlatformWidget(
555      toplevel->GetNativeView());
556
557  EXPECT_FALSE(toplevel->IsVisible());
558  EXPECT_FALSE(child_popup->IsVisible());
559
560  toplevel->Show();
561
562  EXPECT_TRUE(toplevel->IsVisible());
563  EXPECT_FALSE(child_popup->IsVisible());
564
565  child_popup->Show();
566
567  EXPECT_TRUE(child_popup->IsVisible());
568
569  toplevel->CloseNow();
570  // |child_popup| should be automatically destroyed with |toplevel|.
571}
572#endif
573
574////////////////////////////////////////////////////////////////////////////////
575// Widget ownership tests.
576//
577// Tests various permutations of Widget ownership specified in the
578// InitParams::Ownership param.
579
580// A WidgetTest that supplies a toplevel widget for NativeWidget to parent to.
581class WidgetOwnershipTest : public WidgetTest {
582 public:
583  WidgetOwnershipTest() {}
584  virtual ~WidgetOwnershipTest() {}
585
586  virtual void SetUp() {
587    WidgetTest::SetUp();
588    desktop_widget_ = CreateTopLevelPlatformWidget();
589  }
590
591  virtual void TearDown() {
592    desktop_widget_->CloseNow();
593    WidgetTest::TearDown();
594  }
595
596 private:
597  Widget* desktop_widget_;
598
599  DISALLOW_COPY_AND_ASSIGN(WidgetOwnershipTest);
600};
601
602// A bag of state to monitor destructions.
603struct OwnershipTestState {
604  OwnershipTestState() : widget_deleted(false), native_widget_deleted(false) {}
605
606  bool widget_deleted;
607  bool native_widget_deleted;
608};
609
610// A platform NativeWidget subclass that updates a bag of state when it is
611// destroyed.
612class OwnershipTestNativeWidget : public NativeWidgetPlatform {
613 public:
614  OwnershipTestNativeWidget(internal::NativeWidgetDelegate* delegate,
615                            OwnershipTestState* state)
616      : NativeWidgetPlatform(delegate),
617        state_(state) {
618  }
619  virtual ~OwnershipTestNativeWidget() {
620    state_->native_widget_deleted = true;
621  }
622
623 private:
624  OwnershipTestState* state_;
625
626  DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidget);
627};
628
629// A views NativeWidget subclass that updates a bag of state when it is
630// destroyed.
631class OwnershipTestNativeWidgetPlatform : public NativeWidgetPlatformForTest {
632 public:
633  OwnershipTestNativeWidgetPlatform(internal::NativeWidgetDelegate* delegate,
634                                    OwnershipTestState* state)
635      : NativeWidgetPlatformForTest(delegate),
636        state_(state) {
637  }
638  virtual ~OwnershipTestNativeWidgetPlatform() {
639    state_->native_widget_deleted = true;
640  }
641
642 private:
643  OwnershipTestState* state_;
644
645  DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetPlatform);
646};
647
648// A Widget subclass that updates a bag of state when it is destroyed.
649class OwnershipTestWidget : public Widget {
650 public:
651  explicit OwnershipTestWidget(OwnershipTestState* state) : state_(state) {}
652  virtual ~OwnershipTestWidget() {
653    state_->widget_deleted = true;
654  }
655
656 private:
657  OwnershipTestState* state_;
658
659  DISALLOW_COPY_AND_ASSIGN(OwnershipTestWidget);
660};
661
662// Widget owns its NativeWidget, part 1: NativeWidget is a platform-native
663// widget.
664TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsPlatformNativeWidget) {
665  OwnershipTestState state;
666
667  scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
668  Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
669  params.native_widget =
670      new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
671  params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
672  widget->Init(params);
673
674  // Now delete the Widget, which should delete the NativeWidget.
675  widget.reset();
676
677  EXPECT_TRUE(state.widget_deleted);
678  EXPECT_TRUE(state.native_widget_deleted);
679
680  // TODO(beng): write test for this ownership scenario and the NativeWidget
681  //             being deleted out from under the Widget.
682}
683
684// Widget owns its NativeWidget, part 2: NativeWidget is a NativeWidget.
685TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsViewsNativeWidget) {
686  OwnershipTestState state;
687
688  scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
689  Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
690  params.native_widget =
691      new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
692  params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
693  widget->Init(params);
694
695  // Now delete the Widget, which should delete the NativeWidget.
696  widget.reset();
697
698  EXPECT_TRUE(state.widget_deleted);
699  EXPECT_TRUE(state.native_widget_deleted);
700
701  // TODO(beng): write test for this ownership scenario and the NativeWidget
702  //             being deleted out from under the Widget.
703}
704
705// Widget owns its NativeWidget, part 3: NativeWidget is a NativeWidget,
706// destroy the parent view.
707TEST_F(WidgetOwnershipTest,
708       Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView) {
709  OwnershipTestState state;
710
711  Widget* toplevel = CreateTopLevelPlatformWidget();
712
713  scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
714  Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
715  params.native_widget =
716      new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
717  params.parent = toplevel->GetNativeView();
718  params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
719  widget->Init(params);
720
721  // Now close the toplevel, which deletes the view hierarchy.
722  toplevel->CloseNow();
723
724  RunPendingMessages();
725
726  // This shouldn't delete the widget because it shouldn't be deleted
727  // from the native side.
728  EXPECT_FALSE(state.widget_deleted);
729  EXPECT_FALSE(state.native_widget_deleted);
730
731  // Now delete it explicitly.
732  widget.reset();
733
734  EXPECT_TRUE(state.widget_deleted);
735  EXPECT_TRUE(state.native_widget_deleted);
736}
737
738// NativeWidget owns its Widget, part 1: NativeWidget is a platform-native
739// widget.
740TEST_F(WidgetOwnershipTest, Ownership_PlatformNativeWidgetOwnsWidget) {
741  OwnershipTestState state;
742
743  Widget* widget = new OwnershipTestWidget(&state);
744  Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
745  params.native_widget =
746      new OwnershipTestNativeWidgetPlatform(widget, &state);
747  widget->Init(params);
748
749  // Now destroy the native widget.
750  widget->CloseNow();
751
752  EXPECT_TRUE(state.widget_deleted);
753  EXPECT_TRUE(state.native_widget_deleted);
754}
755
756// NativeWidget owns its Widget, part 2: NativeWidget is a NativeWidget.
757TEST_F(WidgetOwnershipTest, Ownership_ViewsNativeWidgetOwnsWidget) {
758  OwnershipTestState state;
759
760  Widget* toplevel = CreateTopLevelPlatformWidget();
761
762  Widget* widget = new OwnershipTestWidget(&state);
763  Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
764  params.native_widget =
765      new OwnershipTestNativeWidgetPlatform(widget, &state);
766  params.parent = toplevel->GetNativeView();
767  widget->Init(params);
768
769  // Now destroy the native widget. This is achieved by closing the toplevel.
770  toplevel->CloseNow();
771
772  // The NativeWidget won't be deleted until after a return to the message loop
773  // so we have to run pending messages before testing the destruction status.
774  RunPendingMessages();
775
776  EXPECT_TRUE(state.widget_deleted);
777  EXPECT_TRUE(state.native_widget_deleted);
778}
779
780// NativeWidget owns its Widget, part 3: NativeWidget is a platform-native
781// widget, destroyed out from under it by the OS.
782TEST_F(WidgetOwnershipTest,
783       Ownership_PlatformNativeWidgetOwnsWidget_NativeDestroy) {
784  OwnershipTestState state;
785
786  Widget* widget = new OwnershipTestWidget(&state);
787  Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
788  params.native_widget =
789      new OwnershipTestNativeWidgetPlatform(widget, &state);
790  widget->Init(params);
791
792  // Now simulate a destroy of the platform native widget from the OS:
793#if defined(USE_AURA)
794  delete widget->GetNativeView();
795#elif defined(OS_WIN)
796  DestroyWindow(widget->GetNativeView());
797#endif
798
799  EXPECT_TRUE(state.widget_deleted);
800  EXPECT_TRUE(state.native_widget_deleted);
801}
802
803// NativeWidget owns its Widget, part 4: NativeWidget is a NativeWidget,
804// destroyed by the view hierarchy that contains it.
805TEST_F(WidgetOwnershipTest,
806       Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy) {
807  OwnershipTestState state;
808
809  Widget* toplevel = CreateTopLevelPlatformWidget();
810
811  Widget* widget = new OwnershipTestWidget(&state);
812  Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
813  params.native_widget =
814      new OwnershipTestNativeWidgetPlatform(widget, &state);
815  params.parent = toplevel->GetNativeView();
816  widget->Init(params);
817
818  // Destroy the widget (achieved by closing the toplevel).
819  toplevel->CloseNow();
820
821  // The NativeWidget won't be deleted until after a return to the message loop
822  // so we have to run pending messages before testing the destruction status.
823  RunPendingMessages();
824
825  EXPECT_TRUE(state.widget_deleted);
826  EXPECT_TRUE(state.native_widget_deleted);
827}
828
829// NativeWidget owns its Widget, part 5: NativeWidget is a NativeWidget,
830// we close it directly.
831TEST_F(WidgetOwnershipTest,
832       Ownership_ViewsNativeWidgetOwnsWidget_Close) {
833  OwnershipTestState state;
834
835  Widget* toplevel = CreateTopLevelPlatformWidget();
836
837  Widget* widget = new OwnershipTestWidget(&state);
838  Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
839  params.native_widget =
840      new OwnershipTestNativeWidgetPlatform(widget, &state);
841  params.parent = toplevel->GetNativeView();
842  widget->Init(params);
843
844  // Destroy the widget.
845  widget->Close();
846  toplevel->CloseNow();
847
848  // The NativeWidget won't be deleted until after a return to the message loop
849  // so we have to run pending messages before testing the destruction status.
850  RunPendingMessages();
851
852  EXPECT_TRUE(state.widget_deleted);
853  EXPECT_TRUE(state.native_widget_deleted);
854}
855
856// Widget owns its NativeWidget and has a WidgetDelegateView as its contents.
857TEST_F(WidgetOwnershipTest,
858       Ownership_WidgetOwnsNativeWidgetWithWithWidgetDelegateView) {
859  OwnershipTestState state;
860
861  WidgetDelegateView* delegate_view = new WidgetDelegateView;
862
863  scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
864  Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
865  params.native_widget =
866      new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
867  params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
868  params.delegate = delegate_view;
869  widget->Init(params);
870  widget->SetContentsView(delegate_view);
871
872  // Now delete the Widget. There should be no crash or use-after-free.
873  widget.reset();
874
875  EXPECT_TRUE(state.widget_deleted);
876  EXPECT_TRUE(state.native_widget_deleted);
877}
878
879////////////////////////////////////////////////////////////////////////////////
880// Widget observer tests.
881//
882
883class WidgetObserverTest : public WidgetTest, public WidgetObserver {
884 public:
885  WidgetObserverTest()
886      : active_(NULL),
887        widget_closed_(NULL),
888        widget_activated_(NULL),
889        widget_shown_(NULL),
890        widget_hidden_(NULL),
891        widget_bounds_changed_(NULL) {
892  }
893
894  virtual ~WidgetObserverTest() {}
895
896  // Overridden from WidgetObserver:
897  virtual void OnWidgetDestroying(Widget* widget) OVERRIDE {
898    if (active_ == widget)
899      active_ = NULL;
900    widget_closed_ = widget;
901  }
902
903  virtual void OnWidgetActivationChanged(Widget* widget,
904                                         bool active) OVERRIDE {
905    if (active) {
906      if (widget_activated_)
907        widget_activated_->Deactivate();
908      widget_activated_ = widget;
909      active_ = widget;
910    } else {
911      if (widget_activated_ == widget)
912        widget_activated_ = NULL;
913      widget_deactivated_ = widget;
914    }
915  }
916
917  virtual void OnWidgetVisibilityChanged(Widget* widget,
918                                         bool visible) OVERRIDE {
919    if (visible)
920      widget_shown_ = widget;
921    else
922      widget_hidden_ = widget;
923  }
924
925  virtual void OnWidgetBoundsChanged(Widget* widget,
926                                     const gfx::Rect& new_bounds) OVERRIDE {
927    widget_bounds_changed_ = widget;
928  }
929
930  void reset() {
931    active_ = NULL;
932    widget_closed_ = NULL;
933    widget_activated_ = NULL;
934    widget_deactivated_ = NULL;
935    widget_shown_ = NULL;
936    widget_hidden_ = NULL;
937    widget_bounds_changed_ = NULL;
938  }
939
940  Widget* NewWidget() {
941    Widget* widget = CreateTopLevelNativeWidget();
942    widget->AddObserver(this);
943    return widget;
944  }
945
946  const Widget* active() const { return active_; }
947  const Widget* widget_closed() const { return widget_closed_; }
948  const Widget* widget_activated() const { return widget_activated_; }
949  const Widget* widget_deactivated() const { return widget_deactivated_; }
950  const Widget* widget_shown() const { return widget_shown_; }
951  const Widget* widget_hidden() const { return widget_hidden_; }
952  const Widget* widget_bounds_changed() const { return widget_bounds_changed_; }
953
954 private:
955  Widget* active_;
956
957  Widget* widget_closed_;
958  Widget* widget_activated_;
959  Widget* widget_deactivated_;
960  Widget* widget_shown_;
961  Widget* widget_hidden_;
962  Widget* widget_bounds_changed_;
963};
964
965TEST_F(WidgetObserverTest, DISABLED_ActivationChange) {
966  Widget* toplevel = CreateTopLevelPlatformWidget();
967
968  Widget* toplevel1 = NewWidget();
969  Widget* toplevel2 = NewWidget();
970
971  toplevel1->Show();
972  toplevel2->Show();
973
974  reset();
975
976  toplevel1->Activate();
977
978  RunPendingMessages();
979  EXPECT_EQ(toplevel1, widget_activated());
980
981  toplevel2->Activate();
982  RunPendingMessages();
983  EXPECT_EQ(toplevel1, widget_deactivated());
984  EXPECT_EQ(toplevel2, widget_activated());
985  EXPECT_EQ(toplevel2, active());
986
987  toplevel->CloseNow();
988}
989
990TEST_F(WidgetObserverTest, DISABLED_VisibilityChange) {
991  Widget* toplevel = CreateTopLevelPlatformWidget();
992
993  Widget* child1 = NewWidget();
994  Widget* child2 = NewWidget();
995
996  toplevel->Show();
997  child1->Show();
998  child2->Show();
999
1000  reset();
1001
1002  child1->Hide();
1003  EXPECT_EQ(child1, widget_hidden());
1004
1005  child2->Hide();
1006  EXPECT_EQ(child2, widget_hidden());
1007
1008  child1->Show();
1009  EXPECT_EQ(child1, widget_shown());
1010
1011  child2->Show();
1012  EXPECT_EQ(child2, widget_shown());
1013
1014  toplevel->CloseNow();
1015}
1016
1017TEST_F(WidgetObserverTest, DestroyBubble) {
1018  Widget* anchor = CreateTopLevelPlatformWidget();
1019  anchor->Show();
1020
1021  BubbleDelegateView* bubble_delegate =
1022      new BubbleDelegateView(anchor->client_view(), BubbleBorder::NONE);
1023  Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
1024  bubble_widget->Show();
1025  bubble_widget->CloseNow();
1026
1027  anchor->Hide();
1028  anchor->CloseNow();
1029}
1030
1031TEST_F(WidgetObserverTest, WidgetBoundsChanged) {
1032  Widget* child1 = NewWidget();
1033  Widget* child2 = NewWidget();
1034
1035  child1->OnNativeWidgetMove();
1036  EXPECT_EQ(child1, widget_bounds_changed());
1037
1038  child2->OnNativeWidgetMove();
1039  EXPECT_EQ(child2, widget_bounds_changed());
1040
1041  child1->OnNativeWidgetSizeChanged(gfx::Size());
1042  EXPECT_EQ(child1, widget_bounds_changed());
1043
1044  child2->OnNativeWidgetSizeChanged(gfx::Size());
1045  EXPECT_EQ(child2, widget_bounds_changed());
1046}
1047
1048#if !defined(USE_AURA) && defined(OS_WIN)
1049// Aura needs shell to maximize/fullscreen window.
1050// NativeWidgetGtk doesn't implement GetRestoredBounds.
1051TEST_F(WidgetTest, GetRestoredBounds) {
1052  Widget* toplevel = CreateTopLevelPlatformWidget();
1053  EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
1054            toplevel->GetRestoredBounds().ToString());
1055  toplevel->Show();
1056  toplevel->Maximize();
1057  RunPendingMessages();
1058  EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
1059            toplevel->GetRestoredBounds().ToString());
1060  EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
1061  EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
1062
1063  toplevel->Restore();
1064  RunPendingMessages();
1065  EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
1066            toplevel->GetRestoredBounds().ToString());
1067
1068  toplevel->SetFullscreen(true);
1069  RunPendingMessages();
1070  EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
1071            toplevel->GetRestoredBounds().ToString());
1072  EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
1073  EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
1074}
1075#endif
1076
1077// Test that window state is not changed after getting out of full screen.
1078TEST_F(WidgetTest, ExitFullscreenRestoreState) {
1079  Widget* toplevel = CreateTopLevelPlatformWidget();
1080
1081  toplevel->Show();
1082  RunPendingMessages();
1083
1084  // This should be a normal state window.
1085  EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
1086
1087  toplevel->SetFullscreen(true);
1088  while (GetWidgetShowState(toplevel) != ui::SHOW_STATE_FULLSCREEN)
1089    RunPendingMessages();
1090  toplevel->SetFullscreen(false);
1091  while (GetWidgetShowState(toplevel) == ui::SHOW_STATE_FULLSCREEN)
1092    RunPendingMessages();
1093
1094  // And it should still be in normal state after getting out of full screen.
1095  EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
1096
1097  // Now, make it maximized.
1098  toplevel->Maximize();
1099  while (GetWidgetShowState(toplevel) != ui::SHOW_STATE_MAXIMIZED)
1100    RunPendingMessages();
1101
1102  toplevel->SetFullscreen(true);
1103  while (GetWidgetShowState(toplevel) != ui::SHOW_STATE_FULLSCREEN)
1104    RunPendingMessages();
1105  toplevel->SetFullscreen(false);
1106  while (GetWidgetShowState(toplevel) == ui::SHOW_STATE_FULLSCREEN)
1107    RunPendingMessages();
1108
1109  // And it stays maximized after getting out of full screen.
1110  EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
1111
1112  // Clean up.
1113  toplevel->Close();
1114  RunPendingMessages();
1115}
1116
1117TEST_F(WidgetTest, ResetCaptureOnGestureEnd) {
1118  Widget* toplevel = CreateTopLevelFramelessPlatformWidget();
1119  View* container = new View;
1120  toplevel->SetContentsView(container);
1121
1122  View* gesture = new GestureCaptureView;
1123  gesture->SetBounds(0, 0, 30, 30);
1124  container->AddChildView(gesture);
1125
1126  MouseView* mouse = new MouseView;
1127  mouse->SetBounds(30, 0, 30, 30);
1128  container->AddChildView(mouse);
1129
1130  toplevel->SetSize(gfx::Size(100, 100));
1131  toplevel->Show();
1132
1133  // Start a gesture on |gesture|.
1134  ui::GestureEvent begin(ui::ET_GESTURE_BEGIN,
1135      15, 15, 0, base::TimeDelta(),
1136      ui::GestureEventDetails(ui::ET_GESTURE_BEGIN, 0, 0), 1);
1137  ui::GestureEvent end(ui::ET_GESTURE_END,
1138      15, 15, 0, base::TimeDelta(),
1139      ui::GestureEventDetails(ui::ET_GESTURE_END, 0, 0), 1);
1140  toplevel->OnGestureEvent(&begin);
1141
1142  // Now try to click on |mouse|. Since |gesture| will have capture, |mouse|
1143  // will not receive the event.
1144  gfx::Point click_location(45, 15);
1145
1146  ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
1147      ui::EF_LEFT_MOUSE_BUTTON);
1148  ui::MouseEvent release(ui::ET_MOUSE_RELEASED, click_location, click_location,
1149      ui::EF_LEFT_MOUSE_BUTTON);
1150
1151  toplevel->OnMouseEvent(&press);
1152  toplevel->OnMouseEvent(&release);
1153  EXPECT_EQ(0, mouse->pressed());
1154
1155  // The end of the gesture should release the capture, and pressing on |mouse|
1156  // should now reach |mouse|.
1157  toplevel->OnGestureEvent(&end);
1158  toplevel->OnMouseEvent(&press);
1159  toplevel->OnMouseEvent(&release);
1160  EXPECT_EQ(1, mouse->pressed());
1161
1162  toplevel->Close();
1163  RunPendingMessages();
1164}
1165
1166#if defined(USE_AURA)
1167// The key-event propagation from Widget happens differently on aura and
1168// non-aura systems because of the difference in IME. So this test works only on
1169// aura.
1170TEST_F(WidgetTest, KeyboardInputEvent) {
1171  Widget* toplevel = CreateTopLevelPlatformWidget();
1172  View* container = toplevel->client_view();
1173
1174  Textfield* textfield = new Textfield();
1175  textfield->SetText(ASCIIToUTF16("some text"));
1176  container->AddChildView(textfield);
1177  toplevel->Show();
1178  textfield->RequestFocus();
1179
1180  // The press gets handled. The release doesn't have an effect.
1181  ui::KeyEvent backspace_p(ui::ET_KEY_PRESSED, ui::VKEY_DELETE, 0, false);
1182  toplevel->OnKeyEvent(&backspace_p);
1183  EXPECT_TRUE(backspace_p.stopped_propagation());
1184  ui::KeyEvent backspace_r(ui::ET_KEY_RELEASED, ui::VKEY_DELETE, 0, false);
1185  toplevel->OnKeyEvent(&backspace_r);
1186  EXPECT_FALSE(backspace_r.handled());
1187
1188  toplevel->Close();
1189}
1190
1191// Verifies bubbles result in a focus lost when shown.
1192// TODO(msw): this tests relies on focus, it needs to be in
1193// interactive_ui_tests.
1194TEST_F(WidgetTest, DISABLED_FocusChangesOnBubble) {
1195  // Create a widget, show and activate it and focus the contents view.
1196  View* contents_view = new View;
1197  contents_view->set_focusable(true);
1198  Widget widget;
1199  Widget::InitParams init_params =
1200      CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1201  init_params.bounds = gfx::Rect(0, 0, 200, 200);
1202  init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1203#if !defined(OS_CHROMEOS)
1204  init_params.native_widget = new DesktopNativeWidgetAura(&widget);
1205#endif
1206  widget.Init(init_params);
1207  widget.SetContentsView(contents_view);
1208  widget.Show();
1209  widget.Activate();
1210  contents_view->RequestFocus();
1211  EXPECT_TRUE(contents_view->HasFocus());
1212
1213  // Show a bubble.
1214  BubbleDelegateView* bubble_delegate_view =
1215      new BubbleDelegateView(contents_view, BubbleBorder::TOP_LEFT);
1216  bubble_delegate_view->set_focusable(true);
1217  BubbleDelegateView::CreateBubble(bubble_delegate_view)->Show();
1218  bubble_delegate_view->RequestFocus();
1219
1220  // |contents_view_| should no longer have focus.
1221  EXPECT_FALSE(contents_view->HasFocus());
1222  EXPECT_TRUE(bubble_delegate_view->HasFocus());
1223
1224  bubble_delegate_view->GetWidget()->CloseNow();
1225
1226  // Closing the bubble should result in focus going back to the contents view.
1227  EXPECT_TRUE(contents_view->HasFocus());
1228}
1229
1230// Desktop native widget Aura tests are for non Chrome OS platforms.
1231#if !defined(OS_CHROMEOS)
1232// Test to ensure that after minimize, view width is set to zero.
1233TEST_F(WidgetTest, TestViewWidthAfterMinimizingWidget) {
1234  // Create a widget.
1235  Widget widget;
1236  Widget::InitParams init_params =
1237      CreateParams(Widget::InitParams::TYPE_WINDOW);
1238  init_params.show_state = ui::SHOW_STATE_NORMAL;
1239  gfx::Rect initial_bounds(0, 0, 300, 400);
1240  init_params.bounds = initial_bounds;
1241  init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1242  init_params.native_widget = new DesktopNativeWidgetAura(&widget);
1243  widget.Init(init_params);
1244  NonClientView* non_client_view = widget.non_client_view();
1245  NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1246  non_client_view->SetFrameView(frame_view);
1247  widget.Show();
1248  widget.Minimize();
1249  EXPECT_EQ(0, frame_view->width());
1250}
1251
1252// This class validates whether paints are received for a visible Widget.
1253// To achieve this it overrides the Show and Close methods on the Widget class
1254// and sets state whether subsequent paints are expected.
1255class DesktopAuraTestValidPaintWidget : public views::Widget {
1256 public:
1257  DesktopAuraTestValidPaintWidget()
1258    : expect_paint_(true),
1259      received_paint_while_hidden_(false) {
1260  }
1261
1262  virtual ~DesktopAuraTestValidPaintWidget() {
1263  }
1264
1265  virtual void Show() OVERRIDE {
1266    expect_paint_ = true;
1267    views::Widget::Show();
1268  }
1269
1270  virtual void Close() OVERRIDE {
1271    expect_paint_ = false;
1272    views::Widget::Close();
1273  }
1274
1275  void Hide() {
1276    expect_paint_ = false;
1277    views::Widget::Hide();
1278  }
1279
1280  virtual void OnNativeWidgetPaint(gfx::Canvas* canvas) OVERRIDE {
1281    EXPECT_TRUE(expect_paint_);
1282    if (!expect_paint_)
1283      received_paint_while_hidden_ = true;
1284    views::Widget::OnNativeWidgetPaint(canvas);
1285  }
1286
1287  bool received_paint_while_hidden() const {
1288    return received_paint_while_hidden_;
1289  }
1290
1291 private:
1292  bool expect_paint_;
1293  bool received_paint_while_hidden_;
1294};
1295
1296TEST_F(WidgetTest, DesktopNativeWidgetAuraNoPaintAfterCloseTest) {
1297  View* contents_view = new View;
1298  contents_view->set_focusable(true);
1299  DesktopAuraTestValidPaintWidget widget;
1300  Widget::InitParams init_params =
1301      CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1302  init_params.bounds = gfx::Rect(0, 0, 200, 200);
1303  init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1304  init_params.native_widget = new DesktopNativeWidgetAura(&widget);
1305  widget.Init(init_params);
1306  widget.SetContentsView(contents_view);
1307  widget.Show();
1308  widget.Activate();
1309  RunPendingMessages();
1310  widget.SchedulePaintInRect(init_params.bounds);
1311  widget.Close();
1312  RunPendingMessages();
1313  EXPECT_FALSE(widget.received_paint_while_hidden());
1314}
1315
1316TEST_F(WidgetTest, DesktopNativeWidgetAuraNoPaintAfterHideTest) {
1317  View* contents_view = new View;
1318  contents_view->set_focusable(true);
1319  DesktopAuraTestValidPaintWidget widget;
1320  Widget::InitParams init_params =
1321      CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1322  init_params.bounds = gfx::Rect(0, 0, 200, 200);
1323  init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1324  init_params.native_widget = new DesktopNativeWidgetAura(&widget);
1325  widget.Init(init_params);
1326  widget.SetContentsView(contents_view);
1327  widget.Show();
1328  widget.Activate();
1329  RunPendingMessages();
1330  widget.SchedulePaintInRect(init_params.bounds);
1331  widget.Hide();
1332  RunPendingMessages();
1333  EXPECT_FALSE(widget.received_paint_while_hidden());
1334  widget.Close();
1335}
1336
1337// This class provides functionality to test whether the destruction of full
1338// screen child windows occurs correctly in desktop AURA without crashing.
1339// It provides facilities to test the following cases:-
1340// 1. Child window destroyed which should lead to the destruction of the
1341//    parent.
1342// 2. Parent window destroyed which should lead to the child being destroyed.
1343class DesktopAuraFullscreenChildWindowDestructionTest
1344    : public views::TestViewsDelegate,
1345      public aura::WindowObserver {
1346 public:
1347  DesktopAuraFullscreenChildWindowDestructionTest()
1348      : full_screen_widget_(NULL),
1349        child_window_(NULL),
1350        parent_destroyed_(false),
1351        child_destroyed_(false) {}
1352
1353  virtual ~DesktopAuraFullscreenChildWindowDestructionTest() {
1354    EXPECT_TRUE(parent_destroyed_);
1355    EXPECT_TRUE(child_destroyed_);
1356    full_screen_widget_ = NULL;
1357    child_window_ = NULL;
1358  }
1359
1360  // views::TestViewsDelegate overrides.
1361  virtual void OnBeforeWidgetInit(
1362      Widget::InitParams* params,
1363      internal::NativeWidgetDelegate* delegate) OVERRIDE {
1364    if (!params->native_widget)
1365      params->native_widget = new views::DesktopNativeWidgetAura(delegate);
1366  }
1367
1368  void CreateFullscreenChildWindow(const gfx::Rect& bounds) {
1369    Widget::InitParams init_params;
1370    init_params.type = Widget::InitParams::TYPE_WINDOW;
1371    init_params.bounds = bounds;
1372    init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1373    init_params.layer_type = ui::LAYER_NOT_DRAWN;
1374
1375    widget_.Init(init_params);
1376
1377    child_window_ = new aura::Window(&child_window_delegate_);
1378    child_window_->SetType(aura::client::WINDOW_TYPE_NORMAL);
1379    child_window_->Init(ui::LAYER_TEXTURED);
1380    child_window_->SetName("TestFullscreenChildWindow");
1381    child_window_->SetProperty(aura::client::kShowStateKey,
1382                              ui::SHOW_STATE_FULLSCREEN);
1383    child_window_->SetDefaultParentByRootWindow(
1384        widget_.GetNativeView()->GetRootWindow(), gfx::Rect(0, 0, 1900, 1600));
1385    child_window_->Show();
1386    child_window_->AddObserver(this);
1387
1388    ASSERT_TRUE(child_window_->parent() != NULL);
1389    child_window_->parent()->AddObserver(this);
1390
1391    full_screen_widget_ =
1392        views::Widget::GetWidgetForNativeView(child_window_->parent());
1393    ASSERT_TRUE(full_screen_widget_ != NULL);
1394  }
1395
1396  void DestroyChildWindow() {
1397    ASSERT_TRUE(child_window_ != NULL);
1398    delete child_window_;
1399  }
1400
1401  void DestroyParentWindow() {
1402    ASSERT_TRUE(full_screen_widget_ != NULL);
1403    full_screen_widget_->CloseNow();
1404  }
1405
1406  virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
1407    window->RemoveObserver(this);
1408    if (window == child_window_) {
1409      child_destroyed_ = true;
1410    } else if (window == full_screen_widget_->GetNativeView()) {
1411      parent_destroyed_ = true;
1412    } else {
1413      ADD_FAILURE() << "Unexpected window destroyed callback: " << window;
1414    }
1415  }
1416
1417 private:
1418  views::Widget widget_;
1419  views::Widget* full_screen_widget_;
1420  aura::Window* child_window_;
1421  bool parent_destroyed_;
1422  bool child_destroyed_;
1423  aura::test::TestWindowDelegate child_window_delegate_;
1424
1425  DISALLOW_COPY_AND_ASSIGN(DesktopAuraFullscreenChildWindowDestructionTest);
1426};
1427
1428TEST_F(WidgetTest, DesktopAuraFullscreenChildDestroyedBeforeParentTest) {
1429  ViewsDelegate::views_delegate = NULL;
1430  DesktopAuraFullscreenChildWindowDestructionTest full_screen_child_test;
1431  ASSERT_NO_FATAL_FAILURE(full_screen_child_test.CreateFullscreenChildWindow(
1432      gfx::Rect(0, 0, 200, 200)));
1433
1434  RunPendingMessages();
1435  ASSERT_NO_FATAL_FAILURE(full_screen_child_test.DestroyChildWindow());
1436  RunPendingMessages();
1437}
1438
1439TEST_F(WidgetTest, DesktopAuraFullscreenChildParentDestroyed) {
1440  ViewsDelegate::views_delegate = NULL;
1441
1442  DesktopAuraFullscreenChildWindowDestructionTest full_screen_child_test;
1443  ASSERT_NO_FATAL_FAILURE(full_screen_child_test.CreateFullscreenChildWindow(
1444      gfx::Rect(0, 0, 200, 200)));
1445
1446  RunPendingMessages();
1447  ASSERT_NO_FATAL_FAILURE(full_screen_child_test.DestroyParentWindow());
1448  RunPendingMessages();
1449}
1450
1451// Test to ensure that the aura Window's visiblity state is set to visible if
1452// the underlying widget is hidden and then shown.
1453TEST_F(WidgetTest, TestWindowVisibilityAfterHide) {
1454  // Create a widget.
1455  Widget widget;
1456  Widget::InitParams init_params =
1457      CreateParams(Widget::InitParams::TYPE_WINDOW);
1458  init_params.show_state = ui::SHOW_STATE_NORMAL;
1459  gfx::Rect initial_bounds(0, 0, 300, 400);
1460  init_params.bounds = initial_bounds;
1461  init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1462  init_params.native_widget = new DesktopNativeWidgetAura(&widget);
1463  widget.Init(init_params);
1464  NonClientView* non_client_view = widget.non_client_view();
1465  NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1466  non_client_view->SetFrameView(frame_view);
1467
1468  widget.Hide();
1469  EXPECT_FALSE(widget.GetNativeView()->IsVisible());
1470  widget.Show();
1471  EXPECT_TRUE(widget.GetNativeView()->IsVisible());
1472}
1473
1474#endif  // !defined(OS_CHROMEOS)
1475
1476// Tests that wheel events generated from scroll events are targetted to the
1477// views under the cursor when the focused view does not processed them.
1478TEST_F(WidgetTest, WheelEventsFromScrollEventTarget) {
1479  EventCountView* cursor_view = new EventCountView;
1480  cursor_view->SetBounds(60, 0, 50, 40);
1481
1482  Widget* widget = CreateTopLevelPlatformWidget();
1483  widget->GetRootView()->AddChildView(cursor_view);
1484
1485  // Generate a scroll event on the cursor view.
1486  ui::ScrollEvent scroll(ui::ET_SCROLL,
1487                         gfx::Point(65, 5),
1488                         ui::EventTimeForNow(),
1489                         0,
1490                         0, 20,
1491                         0, 20,
1492                         2);
1493  widget->OnScrollEvent(&scroll);
1494
1495  EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_SCROLL));
1496  EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1497
1498  cursor_view->ResetCounts();
1499
1500  ui::ScrollEvent scroll2(ui::ET_SCROLL,
1501                          gfx::Point(5, 5),
1502                          ui::EventTimeForNow(),
1503                          0,
1504                          0, 20,
1505                          0, 20,
1506                          2);
1507  widget->OnScrollEvent(&scroll2);
1508
1509  EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_SCROLL));
1510  EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1511
1512  widget->CloseNow();
1513}
1514
1515#endif  // defined(USE_AURA)
1516
1517// Tests that if a scroll-begin gesture is not handled, then subsequent scroll
1518// events are not dispatched to any view.
1519TEST_F(WidgetTest, GestureScrollEventDispatching) {
1520  EventCountView* noscroll_view = new EventCountView;
1521  EventCountView* scroll_view = new ScrollableEventCountView;
1522
1523  noscroll_view->SetBounds(0, 0, 50, 40);
1524  scroll_view->SetBounds(60, 0, 40, 40);
1525
1526  Widget* widget = CreateTopLevelPlatformWidget();
1527  widget->GetRootView()->AddChildView(noscroll_view);
1528  widget->GetRootView()->AddChildView(scroll_view);
1529
1530  {
1531    ui::GestureEvent begin(ui::ET_GESTURE_SCROLL_BEGIN,
1532        5, 5, 0, base::TimeDelta(),
1533        ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0),
1534        1);
1535    widget->OnGestureEvent(&begin);
1536    ui::GestureEvent update(ui::ET_GESTURE_SCROLL_UPDATE,
1537        25, 15, 0, base::TimeDelta(),
1538        ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10),
1539        1);
1540    widget->OnGestureEvent(&update);
1541    ui::GestureEvent end(ui::ET_GESTURE_SCROLL_END,
1542        25, 15, 0, base::TimeDelta(),
1543        ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END, 0, 0),
1544        1);
1545    widget->OnGestureEvent(&end);
1546
1547    EXPECT_EQ(1, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1548    EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1549    EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1550  }
1551
1552  {
1553    ui::GestureEvent begin(ui::ET_GESTURE_SCROLL_BEGIN,
1554        65, 5, 0, base::TimeDelta(),
1555        ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0),
1556        1);
1557    widget->OnGestureEvent(&begin);
1558    ui::GestureEvent update(ui::ET_GESTURE_SCROLL_UPDATE,
1559        85, 15, 0, base::TimeDelta(),
1560        ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10),
1561        1);
1562    widget->OnGestureEvent(&update);
1563    ui::GestureEvent end(ui::ET_GESTURE_SCROLL_END,
1564        85, 15, 0, base::TimeDelta(),
1565        ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END, 0, 0),
1566        1);
1567    widget->OnGestureEvent(&end);
1568
1569    EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1570    EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1571    EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1572  }
1573
1574  widget->CloseNow();
1575}
1576
1577// Tests that event-handlers installed on the RootView get triggered correctly.
1578TEST_F(WidgetTest, EventHandlersOnRootView) {
1579  Widget* widget = CreateTopLevelNativeWidget();
1580  View* root_view = widget->GetRootView();
1581
1582  EventCountView* view = new EventCountView;
1583  view->SetBounds(0, 0, 20, 20);
1584  root_view->AddChildView(view);
1585
1586  EventCountHandler h1;
1587  root_view->AddPreTargetHandler(&h1);
1588
1589  EventCountHandler h2;
1590  root_view->AddPostTargetHandler(&h2);
1591
1592  widget->SetBounds(gfx::Rect(0, 0, 100, 100));
1593  widget->Show();
1594
1595  ui::TouchEvent pressed(ui::ET_TOUCH_PRESSED,
1596                         gfx::Point(10, 10),
1597                         0, 0,
1598                         ui::EventTimeForNow(),
1599                         1.0, 0.0, 1.0, 0.0);
1600  widget->OnTouchEvent(&pressed);
1601  EXPECT_EQ(1, h1.GetEventCount(ui::ET_TOUCH_PRESSED));
1602  EXPECT_EQ(1, view->GetEventCount(ui::ET_TOUCH_PRESSED));
1603  EXPECT_EQ(1, h2.GetEventCount(ui::ET_TOUCH_PRESSED));
1604
1605  ui::GestureEvent begin(ui::ET_GESTURE_BEGIN,
1606      5, 5, 0, ui::EventTimeForNow(),
1607      ui::GestureEventDetails(ui::ET_GESTURE_BEGIN, 0, 0), 1);
1608  ui::GestureEvent end(ui::ET_GESTURE_END,
1609      5, 5, 0, ui::EventTimeForNow(),
1610      ui::GestureEventDetails(ui::ET_GESTURE_END, 0, 0), 1);
1611  widget->OnGestureEvent(&begin);
1612  EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_BEGIN));
1613  EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_BEGIN));
1614  EXPECT_EQ(1, h2.GetEventCount(ui::ET_GESTURE_BEGIN));
1615
1616  ui::TouchEvent released(ui::ET_TOUCH_RELEASED,
1617                          gfx::Point(10, 10),
1618                          0, 0,
1619                          ui::EventTimeForNow(),
1620                          1.0, 0.0, 1.0, 0.0);
1621  widget->OnTouchEvent(&released);
1622  EXPECT_EQ(1, h1.GetEventCount(ui::ET_TOUCH_RELEASED));
1623  EXPECT_EQ(1, view->GetEventCount(ui::ET_TOUCH_RELEASED));
1624  EXPECT_EQ(1, h2.GetEventCount(ui::ET_TOUCH_RELEASED));
1625
1626  widget->OnGestureEvent(&end);
1627  EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_END));
1628  EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_END));
1629  EXPECT_EQ(1, h2.GetEventCount(ui::ET_GESTURE_END));
1630
1631  ui::ScrollEvent scroll(ui::ET_SCROLL,
1632                         gfx::Point(5, 5),
1633                         ui::EventTimeForNow(),
1634                         0,
1635                         0, 20,
1636                         0, 20,
1637                         2);
1638  widget->OnScrollEvent(&scroll);
1639  EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL));
1640  EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1641  EXPECT_EQ(1, h2.GetEventCount(ui::ET_SCROLL));
1642
1643  widget->CloseNow();
1644}
1645
1646TEST_F(WidgetTest, SynthesizeMouseMoveEvent) {
1647  Widget* widget = CreateTopLevelNativeWidget();
1648  View* root_view = widget->GetRootView();
1649
1650  EventCountView* v1 = new EventCountView();
1651  v1->SetBounds(0, 0, 10, 10);
1652  root_view->AddChildView(v1);
1653  EventCountView* v2 = new EventCountView();
1654  v2->SetBounds(0, 10, 10, 10);
1655  root_view->AddChildView(v2);
1656
1657  gfx::Point cursor_location(5, 5);
1658  ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
1659                      ui::EF_NONE);
1660  widget->OnMouseEvent(&move);
1661
1662  EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
1663  EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1664
1665  delete v1;
1666  v2->SetBounds(0, 0, 10, 10);
1667  EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1668
1669  widget->SynthesizeMouseMoveEvent();
1670  EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1671}
1672
1673TEST_F(WidgetTest, MouseEventsHandled) {
1674  Widget* widget = CreateTopLevelNativeWidget();
1675  View* root_view = widget->GetRootView();
1676
1677#if defined(USE_AURA)
1678  aura::test::TestCursorClient cursor_client;
1679  aura::client::SetCursorClient(
1680      widget->GetNativeView()->GetRootWindow(), &cursor_client);
1681#endif
1682
1683  EventCountView* v1 = new EventCountView();
1684  v1->SetBounds(0, 0, 10, 10);
1685  root_view->AddChildView(v1);
1686  EventCountView* v2 = new EventCountView();
1687  v2->SetBounds(0, 10, 10, 10);
1688  root_view->AddChildView(v2);
1689
1690  gfx::Point cursor_location1(5, 5);
1691  ui::MouseEvent move1(ui::ET_MOUSE_MOVED, cursor_location1, cursor_location1,
1692                       ui::EF_NONE);
1693  widget->OnMouseEvent(&move1);
1694  EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
1695  EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1696  EXPECT_EQ(0, v1->GetEventCount(ui::ET_MOUSE_EXITED));
1697  EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_EXITED));
1698  v1->ResetCounts();
1699  v2->ResetCounts();
1700
1701  gfx::Point cursor_location2(5, 15);
1702  ui::MouseEvent move2(ui::ET_MOUSE_MOVED, cursor_location2, cursor_location2,
1703                       ui::EF_NONE);
1704  widget->OnMouseEvent(&move2);
1705  EXPECT_EQ(0, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
1706  EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1707  EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_EXITED));
1708  EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_EXITED));
1709  v1->ResetCounts();
1710  v2->ResetCounts();
1711
1712#if defined(USE_AURA)
1713  // In Aura, we suppress mouse events if mouse events are disabled.
1714  cursor_client.DisableMouseEvents();
1715
1716  widget->OnMouseEvent(&move1);
1717  EXPECT_EQ(0, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
1718  EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1719  EXPECT_EQ(0, v1->GetEventCount(ui::ET_MOUSE_EXITED));
1720  EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_EXITED));
1721  v1->ResetCounts();
1722  v2->ResetCounts();
1723
1724  widget->OnMouseEvent(&move2);
1725  EXPECT_EQ(0, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
1726  EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1727  EXPECT_EQ(0, v1->GetEventCount(ui::ET_MOUSE_EXITED));
1728  EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_EXITED));
1729
1730  cursor_client.EnableMouseEvents();
1731#endif
1732}
1733
1734// Used by SingleWindowClosing to count number of times WindowClosing() has
1735// been invoked.
1736class ClosingDelegate : public WidgetDelegate {
1737 public:
1738  ClosingDelegate() : count_(0), widget_(NULL) {}
1739
1740  int count() const { return count_; }
1741
1742  void set_widget(views::Widget* widget) { widget_ = widget; }
1743
1744  // WidgetDelegate overrides:
1745  virtual Widget* GetWidget() OVERRIDE { return widget_; }
1746  virtual const Widget* GetWidget() const OVERRIDE { return widget_; }
1747  virtual void WindowClosing() OVERRIDE {
1748    count_++;
1749  }
1750
1751 private:
1752  int count_;
1753  views::Widget* widget_;
1754
1755  DISALLOW_COPY_AND_ASSIGN(ClosingDelegate);
1756};
1757
1758// Verifies WindowClosing() is invoked correctly on the delegate when a Widget
1759// is closed.
1760TEST_F(WidgetTest, SingleWindowClosing) {
1761  scoped_ptr<ClosingDelegate> delegate(new ClosingDelegate());
1762  Widget* widget = new Widget();  // Destroyed by CloseNow() below.
1763  Widget::InitParams init_params =
1764      CreateParams(Widget::InitParams::TYPE_WINDOW);
1765  init_params.bounds = gfx::Rect(0, 0, 200, 200);
1766  init_params.delegate = delegate.get();
1767#if defined(USE_AURA) && !defined(OS_CHROMEOS)
1768  init_params.native_widget = new DesktopNativeWidgetAura(widget);
1769#endif
1770  widget->Init(init_params);
1771  EXPECT_EQ(0, delegate->count());
1772  widget->CloseNow();
1773  EXPECT_EQ(1, delegate->count());
1774}
1775
1776// Used by SetTopLevelCorrectly to track calls to OnBeforeWidgetInit().
1777class VerifyTopLevelDelegate : public TestViewsDelegate {
1778 public:
1779  VerifyTopLevelDelegate()
1780      : on_before_init_called_(false),
1781        is_top_level_(false) {
1782  }
1783
1784  bool on_before_init_called() const { return on_before_init_called_; }
1785  bool is_top_level() const { return is_top_level_; }
1786
1787  virtual void OnBeforeWidgetInit(
1788      Widget::InitParams* params,
1789      internal::NativeWidgetDelegate* delegate) OVERRIDE {
1790    on_before_init_called_ = true;
1791    is_top_level_ = params->top_level;
1792  }
1793
1794 private:
1795  bool on_before_init_called_;
1796  bool is_top_level_;
1797
1798  DISALLOW_COPY_AND_ASSIGN(VerifyTopLevelDelegate);
1799};
1800
1801// Verifies |top_level| is correctly passed to
1802// ViewsDelegate::OnBeforeWidgetInit().
1803TEST_F(WidgetTest, SetTopLevelCorrectly) {
1804  set_views_delegate(NULL);
1805  VerifyTopLevelDelegate* delegate = new VerifyTopLevelDelegate;
1806  set_views_delegate(delegate);  // ViewsTestBase takes ownership.
1807  scoped_ptr<Widget> widget(new Widget);
1808  Widget::InitParams params =
1809      CreateParams(views::Widget::InitParams::TYPE_POPUP);
1810  params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1811  widget->Init(params);
1812  EXPECT_TRUE(delegate->on_before_init_called());
1813  EXPECT_TRUE(delegate->is_top_level());
1814}
1815
1816// A scumbag View that deletes its owning widget OnMousePressed.
1817class WidgetDeleterView : public View {
1818 public:
1819  WidgetDeleterView() : View() {}
1820
1821  // Overridden from View.
1822  virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
1823    delete GetWidget();
1824    return true;
1825  }
1826
1827 private:
1828  DISALLOW_COPY_AND_ASSIGN(WidgetDeleterView);
1829};
1830
1831TEST_F(WidgetTest, TestWidgetDeletedInOnMousePressed) {
1832  Widget* widget = new Widget;
1833  Widget::InitParams params =
1834      CreateParams(views::Widget::InitParams::TYPE_POPUP);
1835  params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1836  widget->Init(params);
1837
1838  widget->SetContentsView(new WidgetDeleterView);
1839
1840  widget->SetSize(gfx::Size(100, 100));
1841  widget->Show();
1842
1843  gfx::Point click_location(45, 15);
1844  ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
1845      ui::EF_LEFT_MOUSE_BUTTON);
1846  widget->OnMouseEvent(&press);
1847
1848  // Yay we did not crash!
1849}
1850
1851}  // namespace
1852}  // namespace views
1853