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