Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / ui / views / widget / widget_unittest.cc
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 <algorithm>
6 #include <set>
7
8 #include "base/basictypes.h"
9 #include "base/bind.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "ui/base/hit_test.h"
16 #include "ui/events/event_utils.h"
17 #include "ui/gfx/native_widget_types.h"
18 #include "ui/gfx/point.h"
19 #include "ui/views/bubble/bubble_delegate.h"
20 #include "ui/views/controls/textfield/textfield.h"
21 #include "ui/views/test/test_views_delegate.h"
22 #include "ui/views/test/widget_test.h"
23 #include "ui/views/views_delegate.h"
24 #include "ui/views/widget/native_widget_delegate.h"
25 #include "ui/views/widget/root_view.h"
26 #include "ui/views/window/dialog_delegate.h"
27 #include "ui/views/window/native_frame_view.h"
28
29 #if defined(USE_AURA)
30 #include "ui/aura/client/aura_constants.h"
31 #include "ui/aura/client/window_tree_client.h"
32 #include "ui/aura/root_window.h"
33 #include "ui/aura/test/test_window_delegate.h"
34 #include "ui/aura/window.h"
35 #include "ui/views/widget/native_widget_aura.h"
36 #if !defined(OS_CHROMEOS)
37 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
38 #endif
39 #elif defined(OS_WIN)
40 #include "ui/views/widget/native_widget_win.h"
41 #endif
42
43 #if defined(OS_WIN)
44 #include "ui/views/win/hwnd_util.h"
45 #endif
46
47 namespace views {
48 namespace test {
49
50 // A view that keeps track of the events it receives, but consumes no events.
51 class EventCountView : public View {
52  public:
53   EventCountView() {}
54   virtual ~EventCountView() {}
55
56   int GetEventCount(ui::EventType type) {
57     return event_count_[type];
58   }
59
60   void ResetCounts() {
61     event_count_.clear();
62   }
63
64  protected:
65   // Overridden from ui::EventHandler:
66   virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
67     RecordEvent(*event);
68   }
69   virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
70     RecordEvent(*event);
71   }
72   virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE {
73     RecordEvent(*event);
74   }
75   virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE {
76     RecordEvent(*event);
77   }
78   virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
79     RecordEvent(*event);
80   }
81
82  private:
83   void RecordEvent(const ui::Event& event) {
84     ++event_count_[event.type()];
85   }
86
87   std::map<ui::EventType, int> event_count_;
88
89   DISALLOW_COPY_AND_ASSIGN(EventCountView);
90 };
91
92 // A view that keeps track of the events it receives, and consumes all scroll
93 // gesture events.
94 class ScrollableEventCountView : public EventCountView {
95  public:
96   ScrollableEventCountView() {}
97   virtual ~ScrollableEventCountView() {}
98
99  private:
100   // Overridden from ui::EventHandler:
101   virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
102     EventCountView::OnGestureEvent(event);
103     switch (event->type()) {
104       case ui::ET_GESTURE_SCROLL_BEGIN:
105       case ui::ET_GESTURE_SCROLL_UPDATE:
106       case ui::ET_GESTURE_SCROLL_END:
107       case ui::ET_SCROLL_FLING_START:
108         event->SetHandled();
109         break;
110       default:
111         break;
112     }
113   }
114
115   DISALLOW_COPY_AND_ASSIGN(ScrollableEventCountView);
116 };
117
118 // A view that implements GetMinimumSize.
119 class MinimumSizeFrameView : public NativeFrameView {
120  public:
121   explicit MinimumSizeFrameView(Widget* frame): NativeFrameView(frame) {}
122   virtual ~MinimumSizeFrameView() {}
123
124  private:
125   // Overridden from View:
126   virtual gfx::Size GetMinimumSize() OVERRIDE {
127     return gfx::Size(300, 400);
128   }
129
130   DISALLOW_COPY_AND_ASSIGN(MinimumSizeFrameView);
131 };
132
133 // An event handler that simply keeps a count of the different types of events
134 // it receives.
135 class EventCountHandler : public ui::EventHandler {
136  public:
137   EventCountHandler() {}
138   virtual ~EventCountHandler() {}
139
140   int GetEventCount(ui::EventType type) {
141     return event_count_[type];
142   }
143
144   void ResetCounts() {
145     event_count_.clear();
146   }
147
148  protected:
149   // Overridden from ui::EventHandler:
150   virtual void OnEvent(ui::Event* event) OVERRIDE {
151     RecordEvent(*event);
152     ui::EventHandler::OnEvent(event);
153   }
154
155  private:
156   void RecordEvent(const ui::Event& event) {
157     ++event_count_[event.type()];
158   }
159
160   std::map<ui::EventType, int> event_count_;
161
162   DISALLOW_COPY_AND_ASSIGN(EventCountHandler);
163 };
164
165 ui::WindowShowState GetWidgetShowState(const Widget* widget) {
166   // Use IsMaximized/IsMinimized/IsFullScreen instead of GetWindowPlacement
167   // because the former is implemented on all platforms but the latter is not.
168   return widget->IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN :
169       widget->IsMaximized() ? ui::SHOW_STATE_MAXIMIZED :
170       widget->IsMinimized() ? ui::SHOW_STATE_MINIMIZED :
171       widget->IsActive() ? ui::SHOW_STATE_NORMAL :
172                            ui::SHOW_STATE_INACTIVE;
173 }
174
175 TEST_F(WidgetTest, WidgetInitParams) {
176   // Widgets are not transparent by default.
177   Widget::InitParams init1;
178   EXPECT_EQ(Widget::InitParams::INFER_OPACITY, init1.opacity);
179 }
180
181 ////////////////////////////////////////////////////////////////////////////////
182 // Widget::GetTopLevelWidget tests.
183
184 TEST_F(WidgetTest, GetTopLevelWidget_Native) {
185   // Create a hierarchy of native widgets.
186   Widget* toplevel = CreateTopLevelPlatformWidget();
187   gfx::NativeView parent = toplevel->GetNativeView();
188   Widget* child = CreateChildPlatformWidget(parent);
189
190   EXPECT_EQ(toplevel, toplevel->GetTopLevelWidget());
191   EXPECT_EQ(toplevel, child->GetTopLevelWidget());
192
193   toplevel->CloseNow();
194   // |child| should be automatically destroyed with |toplevel|.
195 }
196
197 // Test if a focus manager and an inputmethod work without CHECK failure
198 // when window activation changes.
199 TEST_F(WidgetTest, ChangeActivation) {
200   Widget* top1 = CreateTopLevelPlatformWidget();
201   // CreateInputMethod before activated
202   top1->GetInputMethod();
203   top1->Show();
204   RunPendingMessages();
205
206   Widget* top2 = CreateTopLevelPlatformWidget();
207   top2->Show();
208   RunPendingMessages();
209
210   top1->Activate();
211   RunPendingMessages();
212
213   // Create InputMethod after deactivated.
214   top2->GetInputMethod();
215   top2->Activate();
216   RunPendingMessages();
217
218   top1->Activate();
219   RunPendingMessages();
220
221   top1->CloseNow();
222   top2->CloseNow();
223 }
224
225 // Tests visibility of child widgets.
226 TEST_F(WidgetTest, Visibility) {
227   Widget* toplevel = CreateTopLevelPlatformWidget();
228   gfx::NativeView parent = toplevel->GetNativeView();
229   Widget* child = CreateChildPlatformWidget(parent);
230
231   EXPECT_FALSE(toplevel->IsVisible());
232   EXPECT_FALSE(child->IsVisible());
233
234   child->Show();
235
236   EXPECT_FALSE(toplevel->IsVisible());
237   EXPECT_FALSE(child->IsVisible());
238
239   toplevel->Show();
240
241   EXPECT_TRUE(toplevel->IsVisible());
242   EXPECT_TRUE(child->IsVisible());
243
244   toplevel->CloseNow();
245   // |child| should be automatically destroyed with |toplevel|.
246 }
247
248 ////////////////////////////////////////////////////////////////////////////////
249 // Widget ownership tests.
250 //
251 // Tests various permutations of Widget ownership specified in the
252 // InitParams::Ownership param.
253
254 // A WidgetTest that supplies a toplevel widget for NativeWidget to parent to.
255 class WidgetOwnershipTest : public WidgetTest {
256  public:
257   WidgetOwnershipTest() {}
258   virtual ~WidgetOwnershipTest() {}
259
260   virtual void SetUp() {
261     WidgetTest::SetUp();
262     desktop_widget_ = CreateTopLevelPlatformWidget();
263   }
264
265   virtual void TearDown() {
266     desktop_widget_->CloseNow();
267     WidgetTest::TearDown();
268   }
269
270  private:
271   Widget* desktop_widget_;
272
273   DISALLOW_COPY_AND_ASSIGN(WidgetOwnershipTest);
274 };
275
276 // A bag of state to monitor destructions.
277 struct OwnershipTestState {
278   OwnershipTestState() : widget_deleted(false), native_widget_deleted(false) {}
279
280   bool widget_deleted;
281   bool native_widget_deleted;
282 };
283
284 // A platform NativeWidget subclass that updates a bag of state when it is
285 // destroyed.
286 class OwnershipTestNativeWidget : public NativeWidgetPlatform {
287  public:
288   OwnershipTestNativeWidget(internal::NativeWidgetDelegate* delegate,
289                             OwnershipTestState* state)
290       : NativeWidgetPlatform(delegate),
291         state_(state) {
292   }
293   virtual ~OwnershipTestNativeWidget() {
294     state_->native_widget_deleted = true;
295   }
296
297  private:
298   OwnershipTestState* state_;
299
300   DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidget);
301 };
302
303 // A views NativeWidget subclass that updates a bag of state when it is
304 // destroyed.
305 class OwnershipTestNativeWidgetPlatform : public NativeWidgetPlatformForTest {
306  public:
307   OwnershipTestNativeWidgetPlatform(internal::NativeWidgetDelegate* delegate,
308                                     OwnershipTestState* state)
309       : NativeWidgetPlatformForTest(delegate),
310         state_(state) {
311   }
312   virtual ~OwnershipTestNativeWidgetPlatform() {
313     state_->native_widget_deleted = true;
314   }
315
316  private:
317   OwnershipTestState* state_;
318
319   DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetPlatform);
320 };
321
322 // A Widget subclass that updates a bag of state when it is destroyed.
323 class OwnershipTestWidget : public Widget {
324  public:
325   explicit OwnershipTestWidget(OwnershipTestState* state) : state_(state) {}
326   virtual ~OwnershipTestWidget() {
327     state_->widget_deleted = true;
328   }
329
330  private:
331   OwnershipTestState* state_;
332
333   DISALLOW_COPY_AND_ASSIGN(OwnershipTestWidget);
334 };
335
336 // Widget owns its NativeWidget, part 1: NativeWidget is a platform-native
337 // widget.
338 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsPlatformNativeWidget) {
339   OwnershipTestState state;
340
341   scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
342   Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
343   params.native_widget =
344       new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
345   params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
346   widget->Init(params);
347
348   // Now delete the Widget, which should delete the NativeWidget.
349   widget.reset();
350
351   EXPECT_TRUE(state.widget_deleted);
352   EXPECT_TRUE(state.native_widget_deleted);
353
354   // TODO(beng): write test for this ownership scenario and the NativeWidget
355   //             being deleted out from under the Widget.
356 }
357
358 // Widget owns its NativeWidget, part 2: NativeWidget is a NativeWidget.
359 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsViewsNativeWidget) {
360   OwnershipTestState state;
361
362   scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
363   Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
364   params.native_widget =
365       new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
366   params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
367   widget->Init(params);
368
369   // Now delete the Widget, which should delete the NativeWidget.
370   widget.reset();
371
372   EXPECT_TRUE(state.widget_deleted);
373   EXPECT_TRUE(state.native_widget_deleted);
374
375   // TODO(beng): write test for this ownership scenario and the NativeWidget
376   //             being deleted out from under the Widget.
377 }
378
379 // Widget owns its NativeWidget, part 3: NativeWidget is a NativeWidget,
380 // destroy the parent view.
381 TEST_F(WidgetOwnershipTest,
382        Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView) {
383   OwnershipTestState state;
384
385   Widget* toplevel = CreateTopLevelPlatformWidget();
386
387   scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
388   Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
389   params.native_widget =
390       new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
391   params.parent = toplevel->GetNativeView();
392   params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
393   widget->Init(params);
394
395   // Now close the toplevel, which deletes the view hierarchy.
396   toplevel->CloseNow();
397
398   RunPendingMessages();
399
400   // This shouldn't delete the widget because it shouldn't be deleted
401   // from the native side.
402   EXPECT_FALSE(state.widget_deleted);
403   EXPECT_FALSE(state.native_widget_deleted);
404
405   // Now delete it explicitly.
406   widget.reset();
407
408   EXPECT_TRUE(state.widget_deleted);
409   EXPECT_TRUE(state.native_widget_deleted);
410 }
411
412 // NativeWidget owns its Widget, part 1: NativeWidget is a platform-native
413 // widget.
414 TEST_F(WidgetOwnershipTest, Ownership_PlatformNativeWidgetOwnsWidget) {
415   OwnershipTestState state;
416
417   Widget* widget = new OwnershipTestWidget(&state);
418   Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
419   params.native_widget =
420       new OwnershipTestNativeWidgetPlatform(widget, &state);
421   widget->Init(params);
422
423   // Now destroy the native widget.
424   widget->CloseNow();
425
426   EXPECT_TRUE(state.widget_deleted);
427   EXPECT_TRUE(state.native_widget_deleted);
428 }
429
430 // NativeWidget owns its Widget, part 2: NativeWidget is a NativeWidget.
431 TEST_F(WidgetOwnershipTest, Ownership_ViewsNativeWidgetOwnsWidget) {
432   OwnershipTestState state;
433
434   Widget* toplevel = CreateTopLevelPlatformWidget();
435
436   Widget* widget = new OwnershipTestWidget(&state);
437   Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
438   params.native_widget =
439       new OwnershipTestNativeWidgetPlatform(widget, &state);
440   params.parent = toplevel->GetNativeView();
441   widget->Init(params);
442
443   // Now destroy the native widget. This is achieved by closing the toplevel.
444   toplevel->CloseNow();
445
446   // The NativeWidget won't be deleted until after a return to the message loop
447   // so we have to run pending messages before testing the destruction status.
448   RunPendingMessages();
449
450   EXPECT_TRUE(state.widget_deleted);
451   EXPECT_TRUE(state.native_widget_deleted);
452 }
453
454 // NativeWidget owns its Widget, part 3: NativeWidget is a platform-native
455 // widget, destroyed out from under it by the OS.
456 TEST_F(WidgetOwnershipTest,
457        Ownership_PlatformNativeWidgetOwnsWidget_NativeDestroy) {
458   OwnershipTestState state;
459
460   Widget* widget = new OwnershipTestWidget(&state);
461   Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
462   params.native_widget =
463       new OwnershipTestNativeWidgetPlatform(widget, &state);
464   widget->Init(params);
465
466   // Now simulate a destroy of the platform native widget from the OS:
467 #if defined(USE_AURA)
468   delete widget->GetNativeView();
469 #elif defined(OS_WIN)
470   DestroyWindow(widget->GetNativeView());
471 #endif
472
473   EXPECT_TRUE(state.widget_deleted);
474   EXPECT_TRUE(state.native_widget_deleted);
475 }
476
477 // NativeWidget owns its Widget, part 4: NativeWidget is a NativeWidget,
478 // destroyed by the view hierarchy that contains it.
479 TEST_F(WidgetOwnershipTest,
480        Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy) {
481   OwnershipTestState state;
482
483   Widget* toplevel = CreateTopLevelPlatformWidget();
484
485   Widget* widget = new OwnershipTestWidget(&state);
486   Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
487   params.native_widget =
488       new OwnershipTestNativeWidgetPlatform(widget, &state);
489   params.parent = toplevel->GetNativeView();
490   widget->Init(params);
491
492   // Destroy the widget (achieved by closing the toplevel).
493   toplevel->CloseNow();
494
495   // The NativeWidget won't be deleted until after a return to the message loop
496   // so we have to run pending messages before testing the destruction status.
497   RunPendingMessages();
498
499   EXPECT_TRUE(state.widget_deleted);
500   EXPECT_TRUE(state.native_widget_deleted);
501 }
502
503 // NativeWidget owns its Widget, part 5: NativeWidget is a NativeWidget,
504 // we close it directly.
505 TEST_F(WidgetOwnershipTest,
506        Ownership_ViewsNativeWidgetOwnsWidget_Close) {
507   OwnershipTestState state;
508
509   Widget* toplevel = CreateTopLevelPlatformWidget();
510
511   Widget* widget = new OwnershipTestWidget(&state);
512   Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
513   params.native_widget =
514       new OwnershipTestNativeWidgetPlatform(widget, &state);
515   params.parent = toplevel->GetNativeView();
516   widget->Init(params);
517
518   // Destroy the widget.
519   widget->Close();
520   toplevel->CloseNow();
521
522   // The NativeWidget won't be deleted until after a return to the message loop
523   // so we have to run pending messages before testing the destruction status.
524   RunPendingMessages();
525
526   EXPECT_TRUE(state.widget_deleted);
527   EXPECT_TRUE(state.native_widget_deleted);
528 }
529
530 // Widget owns its NativeWidget and has a WidgetDelegateView as its contents.
531 TEST_F(WidgetOwnershipTest,
532        Ownership_WidgetOwnsNativeWidgetWithWithWidgetDelegateView) {
533   OwnershipTestState state;
534
535   WidgetDelegateView* delegate_view = new WidgetDelegateView;
536
537   scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
538   Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
539   params.native_widget =
540       new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
541   params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
542   params.delegate = delegate_view;
543   widget->Init(params);
544   widget->SetContentsView(delegate_view);
545
546   // Now delete the Widget. There should be no crash or use-after-free.
547   widget.reset();
548
549   EXPECT_TRUE(state.widget_deleted);
550   EXPECT_TRUE(state.native_widget_deleted);
551 }
552
553 ////////////////////////////////////////////////////////////////////////////////
554 // Test to verify using various Widget methods doesn't crash when the underlying
555 // NativeView is destroyed.
556 //
557 class WidgetWithDestroyedNativeViewTest : public ViewsTestBase {
558  public:
559   WidgetWithDestroyedNativeViewTest() {}
560   virtual ~WidgetWithDestroyedNativeViewTest() {}
561
562   void InvokeWidgetMethods(Widget* widget) {
563     widget->GetNativeView();
564     widget->GetNativeWindow();
565     ui::Accelerator accelerator;
566     widget->GetAccelerator(0, &accelerator);
567     widget->GetTopLevelWidget();
568     widget->GetWindowBoundsInScreen();
569     widget->GetClientAreaBoundsInScreen();
570     widget->SetBounds(gfx::Rect(0, 0, 100, 80));
571     widget->SetSize(gfx::Size(10, 11));
572     widget->SetBoundsConstrained(gfx::Rect(0, 0, 120, 140));
573     widget->SetVisibilityChangedAnimationsEnabled(false);
574     widget->StackAtTop();
575     widget->IsClosed();
576     widget->Close();
577     widget->Hide();
578     widget->Activate();
579     widget->Deactivate();
580     widget->IsActive();
581     widget->DisableInactiveRendering();
582     widget->SetAlwaysOnTop(true);
583     widget->IsAlwaysOnTop();
584     widget->Maximize();
585     widget->Minimize();
586     widget->Restore();
587     widget->IsMaximized();
588     widget->IsFullscreen();
589     widget->SetOpacity(0);
590     widget->SetUseDragFrame(true);
591     widget->FlashFrame(true);
592     widget->IsVisible();
593     widget->GetThemeProvider();
594     widget->GetNativeTheme();
595     widget->GetFocusManager();
596     widget->GetInputMethod();
597     widget->SchedulePaintInRect(gfx::Rect(0, 0, 1, 2));
598     widget->IsMouseEventsEnabled();
599     widget->SetNativeWindowProperty("xx", widget);
600     widget->GetNativeWindowProperty("xx");
601     widget->GetFocusTraversable();
602     widget->GetLayer();
603     widget->ReorderNativeViews();
604     widget->SetCapture(widget->GetRootView());
605     widget->ReleaseCapture();
606     widget->HasCapture();
607     widget->GetWorkAreaBoundsInScreen();
608     // These three crash with NativeWidgetWin, so I'm assuming we don't need
609     // them to work for the other NativeWidget impls.
610     // widget->CenterWindow(gfx::Size(50, 60));
611     // widget->GetRestoredBounds();
612     // widget->ShowInactive();
613     // widget->Show();
614   }
615
616  private:
617   DISALLOW_COPY_AND_ASSIGN(WidgetWithDestroyedNativeViewTest);
618 };
619
620 TEST_F(WidgetWithDestroyedNativeViewTest, Test) {
621   {
622     Widget widget;
623     Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
624     params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
625     widget.Init(params);
626     widget.Show();
627
628     widget.native_widget_private()->CloseNow();
629     InvokeWidgetMethods(&widget);
630   }
631 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
632   {
633     Widget widget;
634     Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
635     params.native_widget = new DesktopNativeWidgetAura(&widget);
636     params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
637     widget.Init(params);
638     widget.Show();
639
640     widget.native_widget_private()->CloseNow();
641     InvokeWidgetMethods(&widget);
642   }
643 #endif
644 }
645
646 ////////////////////////////////////////////////////////////////////////////////
647 // Widget observer tests.
648 //
649
650 class WidgetObserverTest : public WidgetTest, public WidgetObserver {
651  public:
652   WidgetObserverTest()
653       : active_(NULL),
654         widget_closed_(NULL),
655         widget_activated_(NULL),
656         widget_shown_(NULL),
657         widget_hidden_(NULL),
658         widget_bounds_changed_(NULL) {
659   }
660
661   virtual ~WidgetObserverTest() {}
662
663   // Overridden from WidgetObserver:
664   virtual void OnWidgetDestroying(Widget* widget) OVERRIDE {
665     if (active_ == widget)
666       active_ = NULL;
667     widget_closed_ = widget;
668   }
669
670   virtual void OnWidgetActivationChanged(Widget* widget,
671                                          bool active) OVERRIDE {
672     if (active) {
673       if (widget_activated_)
674         widget_activated_->Deactivate();
675       widget_activated_ = widget;
676       active_ = widget;
677     } else {
678       if (widget_activated_ == widget)
679         widget_activated_ = NULL;
680       widget_deactivated_ = widget;
681     }
682   }
683
684   virtual void OnWidgetVisibilityChanged(Widget* widget,
685                                          bool visible) OVERRIDE {
686     if (visible)
687       widget_shown_ = widget;
688     else
689       widget_hidden_ = widget;
690   }
691
692   virtual void OnWidgetBoundsChanged(Widget* widget,
693                                      const gfx::Rect& new_bounds) OVERRIDE {
694     widget_bounds_changed_ = widget;
695   }
696
697   void reset() {
698     active_ = NULL;
699     widget_closed_ = NULL;
700     widget_activated_ = NULL;
701     widget_deactivated_ = NULL;
702     widget_shown_ = NULL;
703     widget_hidden_ = NULL;
704     widget_bounds_changed_ = NULL;
705   }
706
707   Widget* NewWidget() {
708     Widget* widget = CreateTopLevelNativeWidget();
709     widget->AddObserver(this);
710     return widget;
711   }
712
713   const Widget* active() const { return active_; }
714   const Widget* widget_closed() const { return widget_closed_; }
715   const Widget* widget_activated() const { return widget_activated_; }
716   const Widget* widget_deactivated() const { return widget_deactivated_; }
717   const Widget* widget_shown() const { return widget_shown_; }
718   const Widget* widget_hidden() const { return widget_hidden_; }
719   const Widget* widget_bounds_changed() const { return widget_bounds_changed_; }
720
721  private:
722   Widget* active_;
723
724   Widget* widget_closed_;
725   Widget* widget_activated_;
726   Widget* widget_deactivated_;
727   Widget* widget_shown_;
728   Widget* widget_hidden_;
729   Widget* widget_bounds_changed_;
730 };
731
732 TEST_F(WidgetObserverTest, DISABLED_ActivationChange) {
733   Widget* toplevel = CreateTopLevelPlatformWidget();
734
735   Widget* toplevel1 = NewWidget();
736   Widget* toplevel2 = NewWidget();
737
738   toplevel1->Show();
739   toplevel2->Show();
740
741   reset();
742
743   toplevel1->Activate();
744
745   RunPendingMessages();
746   EXPECT_EQ(toplevel1, widget_activated());
747
748   toplevel2->Activate();
749   RunPendingMessages();
750   EXPECT_EQ(toplevel1, widget_deactivated());
751   EXPECT_EQ(toplevel2, widget_activated());
752   EXPECT_EQ(toplevel2, active());
753
754   toplevel->CloseNow();
755 }
756
757 TEST_F(WidgetObserverTest, DISABLED_VisibilityChange) {
758   Widget* toplevel = CreateTopLevelPlatformWidget();
759
760   Widget* child1 = NewWidget();
761   Widget* child2 = NewWidget();
762
763   toplevel->Show();
764   child1->Show();
765   child2->Show();
766
767   reset();
768
769   child1->Hide();
770   EXPECT_EQ(child1, widget_hidden());
771
772   child2->Hide();
773   EXPECT_EQ(child2, widget_hidden());
774
775   child1->Show();
776   EXPECT_EQ(child1, widget_shown());
777
778   child2->Show();
779   EXPECT_EQ(child2, widget_shown());
780
781   toplevel->CloseNow();
782 }
783
784 TEST_F(WidgetObserverTest, DestroyBubble) {
785   Widget* anchor = CreateTopLevelPlatformWidget();
786   anchor->Show();
787
788   BubbleDelegateView* bubble_delegate =
789       new BubbleDelegateView(anchor->client_view(), BubbleBorder::NONE);
790   Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
791   bubble_widget->Show();
792   bubble_widget->CloseNow();
793
794   anchor->Hide();
795   anchor->CloseNow();
796 }
797
798 TEST_F(WidgetObserverTest, WidgetBoundsChanged) {
799   Widget* child1 = NewWidget();
800   Widget* child2 = NewWidget();
801
802   child1->OnNativeWidgetMove();
803   EXPECT_EQ(child1, widget_bounds_changed());
804
805   child2->OnNativeWidgetMove();
806   EXPECT_EQ(child2, widget_bounds_changed());
807
808   child1->OnNativeWidgetSizeChanged(gfx::Size());
809   EXPECT_EQ(child1, widget_bounds_changed());
810
811   child2->OnNativeWidgetSizeChanged(gfx::Size());
812   EXPECT_EQ(child2, widget_bounds_changed());
813 }
814
815 #if !defined(USE_AURA) && defined(OS_WIN)
816 // Aura needs shell to maximize/fullscreen window.
817 // NativeWidgetGtk doesn't implement GetRestoredBounds.
818 TEST_F(WidgetTest, GetRestoredBounds) {
819   Widget* toplevel = CreateTopLevelPlatformWidget();
820   EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
821             toplevel->GetRestoredBounds().ToString());
822   toplevel->Show();
823   toplevel->Maximize();
824   RunPendingMessages();
825   EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
826             toplevel->GetRestoredBounds().ToString());
827   EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
828   EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
829
830   toplevel->Restore();
831   RunPendingMessages();
832   EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
833             toplevel->GetRestoredBounds().ToString());
834
835   toplevel->SetFullscreen(true);
836   RunPendingMessages();
837   EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
838             toplevel->GetRestoredBounds().ToString());
839   EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
840   EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
841 }
842 #endif
843
844 // Test that window state is not changed after getting out of full screen.
845 TEST_F(WidgetTest, ExitFullscreenRestoreState) {
846   Widget* toplevel = CreateTopLevelPlatformWidget();
847
848   toplevel->Show();
849   RunPendingMessages();
850
851   // This should be a normal state window.
852   EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
853
854   toplevel->SetFullscreen(true);
855   while (GetWidgetShowState(toplevel) != ui::SHOW_STATE_FULLSCREEN)
856     RunPendingMessages();
857   toplevel->SetFullscreen(false);
858   while (GetWidgetShowState(toplevel) == ui::SHOW_STATE_FULLSCREEN)
859     RunPendingMessages();
860
861   // And it should still be in normal state after getting out of full screen.
862   EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
863
864   // Now, make it maximized.
865   toplevel->Maximize();
866   while (GetWidgetShowState(toplevel) != ui::SHOW_STATE_MAXIMIZED)
867     RunPendingMessages();
868
869   toplevel->SetFullscreen(true);
870   while (GetWidgetShowState(toplevel) != ui::SHOW_STATE_FULLSCREEN)
871     RunPendingMessages();
872   toplevel->SetFullscreen(false);
873   while (GetWidgetShowState(toplevel) == ui::SHOW_STATE_FULLSCREEN)
874     RunPendingMessages();
875
876   // And it stays maximized after getting out of full screen.
877   EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
878
879   // Clean up.
880   toplevel->Close();
881   RunPendingMessages();
882 }
883
884 #if defined(USE_AURA)
885 // The key-event propagation from Widget happens differently on aura and
886 // non-aura systems because of the difference in IME. So this test works only on
887 // aura.
888 TEST_F(WidgetTest, KeyboardInputEvent) {
889   Widget* toplevel = CreateTopLevelPlatformWidget();
890   View* container = toplevel->client_view();
891
892   Textfield* textfield = new Textfield();
893   textfield->SetText(base::ASCIIToUTF16("some text"));
894   container->AddChildView(textfield);
895   toplevel->Show();
896   textfield->RequestFocus();
897
898   // The press gets handled. The release doesn't have an effect.
899   ui::KeyEvent backspace_p(ui::ET_KEY_PRESSED, ui::VKEY_DELETE, 0, false);
900   toplevel->OnKeyEvent(&backspace_p);
901   EXPECT_TRUE(backspace_p.stopped_propagation());
902   ui::KeyEvent backspace_r(ui::ET_KEY_RELEASED, ui::VKEY_DELETE, 0, false);
903   toplevel->OnKeyEvent(&backspace_r);
904   EXPECT_FALSE(backspace_r.handled());
905
906   toplevel->Close();
907 }
908
909 // Verifies bubbles result in a focus lost when shown.
910 // TODO(msw): this tests relies on focus, it needs to be in
911 // interactive_ui_tests.
912 TEST_F(WidgetTest, DISABLED_FocusChangesOnBubble) {
913   // Create a widget, show and activate it and focus the contents view.
914   View* contents_view = new View;
915   contents_view->SetFocusable(true);
916   Widget widget;
917   Widget::InitParams init_params =
918       CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
919   init_params.bounds = gfx::Rect(0, 0, 200, 200);
920   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
921 #if !defined(OS_CHROMEOS)
922   init_params.native_widget = new DesktopNativeWidgetAura(&widget);
923 #endif
924   widget.Init(init_params);
925   widget.SetContentsView(contents_view);
926   widget.Show();
927   widget.Activate();
928   contents_view->RequestFocus();
929   EXPECT_TRUE(contents_view->HasFocus());
930
931   // Show a bubble.
932   BubbleDelegateView* bubble_delegate_view =
933       new BubbleDelegateView(contents_view, BubbleBorder::TOP_LEFT);
934   bubble_delegate_view->SetFocusable(true);
935   BubbleDelegateView::CreateBubble(bubble_delegate_view)->Show();
936   bubble_delegate_view->RequestFocus();
937
938   // |contents_view_| should no longer have focus.
939   EXPECT_FALSE(contents_view->HasFocus());
940   EXPECT_TRUE(bubble_delegate_view->HasFocus());
941
942   bubble_delegate_view->GetWidget()->CloseNow();
943
944   // Closing the bubble should result in focus going back to the contents view.
945   EXPECT_TRUE(contents_view->HasFocus());
946 }
947
948 class TestBubbleDelegateView : public BubbleDelegateView {
949  public:
950   TestBubbleDelegateView(View* anchor)
951       : BubbleDelegateView(anchor, BubbleBorder::NONE),
952         reset_controls_called_(false) {}
953   virtual ~TestBubbleDelegateView() {}
954
955   virtual bool ShouldShowCloseButton() const OVERRIDE {
956     reset_controls_called_ = true;
957     return true;
958   }
959
960   mutable bool reset_controls_called_;
961 };
962
963 TEST_F(WidgetTest, BubbleControlsResetOnInit) {
964   Widget* anchor = CreateTopLevelPlatformWidget();
965   anchor->Show();
966
967   TestBubbleDelegateView* bubble_delegate =
968       new TestBubbleDelegateView(anchor->client_view());
969   Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
970   EXPECT_TRUE(bubble_delegate->reset_controls_called_);
971   bubble_widget->Show();
972   bubble_widget->CloseNow();
973
974   anchor->Hide();
975   anchor->CloseNow();
976 }
977
978 // Desktop native widget Aura tests are for non Chrome OS platforms.
979 #if !defined(OS_CHROMEOS)
980 // Test to ensure that after minimize, view width is set to zero.
981 TEST_F(WidgetTest, TestViewWidthAfterMinimizingWidget) {
982   // Create a widget.
983   Widget widget;
984   Widget::InitParams init_params =
985       CreateParams(Widget::InitParams::TYPE_WINDOW);
986   init_params.show_state = ui::SHOW_STATE_NORMAL;
987   gfx::Rect initial_bounds(0, 0, 300, 400);
988   init_params.bounds = initial_bounds;
989   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
990   init_params.native_widget = new DesktopNativeWidgetAura(&widget);
991   widget.Init(init_params);
992   NonClientView* non_client_view = widget.non_client_view();
993   NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
994   non_client_view->SetFrameView(frame_view);
995   widget.Show();
996   widget.Minimize();
997   EXPECT_EQ(0, frame_view->width());
998 }
999
1000 // This class validates whether paints are received for a visible Widget.
1001 // To achieve this it overrides the Show and Close methods on the Widget class
1002 // and sets state whether subsequent paints are expected.
1003 class DesktopAuraTestValidPaintWidget : public views::Widget {
1004  public:
1005   DesktopAuraTestValidPaintWidget()
1006     : expect_paint_(true),
1007       received_paint_while_hidden_(false) {
1008   }
1009
1010   virtual ~DesktopAuraTestValidPaintWidget() {
1011   }
1012
1013   virtual void Show() OVERRIDE {
1014     expect_paint_ = true;
1015     views::Widget::Show();
1016   }
1017
1018   virtual void Close() OVERRIDE {
1019     expect_paint_ = false;
1020     views::Widget::Close();
1021   }
1022
1023   void Hide() {
1024     expect_paint_ = false;
1025     views::Widget::Hide();
1026   }
1027
1028   virtual void OnNativeWidgetPaint(gfx::Canvas* canvas) OVERRIDE {
1029     EXPECT_TRUE(expect_paint_);
1030     if (!expect_paint_)
1031       received_paint_while_hidden_ = true;
1032     views::Widget::OnNativeWidgetPaint(canvas);
1033   }
1034
1035   bool received_paint_while_hidden() const {
1036     return received_paint_while_hidden_;
1037   }
1038
1039  private:
1040   bool expect_paint_;
1041   bool received_paint_while_hidden_;
1042 };
1043
1044 TEST_F(WidgetTest, DesktopNativeWidgetAuraNoPaintAfterCloseTest) {
1045   View* contents_view = new View;
1046   contents_view->SetFocusable(true);
1047   DesktopAuraTestValidPaintWidget widget;
1048   Widget::InitParams init_params =
1049       CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1050   init_params.bounds = gfx::Rect(0, 0, 200, 200);
1051   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1052   init_params.native_widget = new DesktopNativeWidgetAura(&widget);
1053   widget.Init(init_params);
1054   widget.SetContentsView(contents_view);
1055   widget.Show();
1056   widget.Activate();
1057   RunPendingMessages();
1058   widget.SchedulePaintInRect(init_params.bounds);
1059   widget.Close();
1060   RunPendingMessages();
1061   EXPECT_FALSE(widget.received_paint_while_hidden());
1062 }
1063
1064 TEST_F(WidgetTest, DesktopNativeWidgetAuraNoPaintAfterHideTest) {
1065   View* contents_view = new View;
1066   contents_view->SetFocusable(true);
1067   DesktopAuraTestValidPaintWidget widget;
1068   Widget::InitParams init_params =
1069       CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1070   init_params.bounds = gfx::Rect(0, 0, 200, 200);
1071   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1072   init_params.native_widget = new DesktopNativeWidgetAura(&widget);
1073   widget.Init(init_params);
1074   widget.SetContentsView(contents_view);
1075   widget.Show();
1076   widget.Activate();
1077   RunPendingMessages();
1078   widget.SchedulePaintInRect(init_params.bounds);
1079   widget.Hide();
1080   RunPendingMessages();
1081   EXPECT_FALSE(widget.received_paint_while_hidden());
1082   widget.Close();
1083 }
1084
1085 // This class provides functionality to create fullscreen and top level popup
1086 // windows. It additionally tests whether the destruction of these windows
1087 // occurs correctly in desktop AURA without crashing.
1088 // It provides facilities to test the following cases:-
1089 // 1. Child window destroyed which should lead to the destruction of the
1090 //    parent.
1091 // 2. Parent window destroyed which should lead to the child being destroyed.
1092 class DesktopAuraTopLevelWindowTest
1093     : public views::TestViewsDelegate,
1094       public aura::WindowObserver {
1095  public:
1096   DesktopAuraTopLevelWindowTest()
1097       : top_level_widget_(NULL),
1098         owned_window_(NULL),
1099         owner_destroyed_(false),
1100         owned_window_destroyed_(false) {}
1101
1102   virtual ~DesktopAuraTopLevelWindowTest() {
1103     EXPECT_TRUE(owner_destroyed_);
1104     EXPECT_TRUE(owned_window_destroyed_);
1105     top_level_widget_ = NULL;
1106     owned_window_ = NULL;
1107   }
1108
1109   // views::TestViewsDelegate overrides.
1110   virtual void OnBeforeWidgetInit(
1111       Widget::InitParams* params,
1112       internal::NativeWidgetDelegate* delegate) OVERRIDE {
1113     if (!params->native_widget)
1114       params->native_widget = new views::DesktopNativeWidgetAura(delegate);
1115   }
1116
1117   void CreateTopLevelWindow(const gfx::Rect& bounds, bool fullscreen) {
1118     Widget::InitParams init_params;
1119     init_params.type = Widget::InitParams::TYPE_WINDOW;
1120     init_params.bounds = bounds;
1121     init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1122     init_params.layer_type = aura::WINDOW_LAYER_NOT_DRAWN;
1123     init_params.accept_events = fullscreen;
1124
1125     widget_.Init(init_params);
1126
1127     owned_window_ = new aura::Window(&child_window_delegate_);
1128     owned_window_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
1129     owned_window_->SetName("TestTopLevelWindow");
1130     if (fullscreen) {
1131       owned_window_->SetProperty(aura::client::kShowStateKey,
1132                                  ui::SHOW_STATE_FULLSCREEN);
1133     } else {
1134       owned_window_->SetType(ui::wm::WINDOW_TYPE_MENU);
1135     }
1136     owned_window_->Init(aura::WINDOW_LAYER_TEXTURED);
1137     aura::client::ParentWindowWithContext(
1138         owned_window_,
1139         widget_.GetNativeView()->GetRootWindow(),
1140         gfx::Rect(0, 0, 1900, 1600));
1141     owned_window_->Show();
1142     owned_window_->AddObserver(this);
1143
1144     ASSERT_TRUE(owned_window_->parent() != NULL);
1145     owned_window_->parent()->AddObserver(this);
1146
1147     top_level_widget_ =
1148         views::Widget::GetWidgetForNativeView(owned_window_->parent());
1149     ASSERT_TRUE(top_level_widget_ != NULL);
1150   }
1151
1152   void DestroyOwnedWindow() {
1153     ASSERT_TRUE(owned_window_ != NULL);
1154     delete owned_window_;
1155   }
1156
1157   void DestroyOwnerWindow() {
1158     ASSERT_TRUE(top_level_widget_ != NULL);
1159     top_level_widget_->CloseNow();
1160   }
1161
1162   virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
1163     window->RemoveObserver(this);
1164     if (window == owned_window_) {
1165       owned_window_destroyed_ = true;
1166     } else if (window == top_level_widget_->GetNativeView()) {
1167       owner_destroyed_ = true;
1168     } else {
1169       ADD_FAILURE() << "Unexpected window destroyed callback: " << window;
1170     }
1171   }
1172
1173   aura::Window* owned_window() {
1174     return owned_window_;
1175   }
1176
1177   views::Widget* top_level_widget() {
1178     return top_level_widget_;
1179   }
1180
1181  private:
1182   views::Widget widget_;
1183   views::Widget* top_level_widget_;
1184   aura::Window* owned_window_;
1185   bool owner_destroyed_;
1186   bool owned_window_destroyed_;
1187   aura::test::TestWindowDelegate child_window_delegate_;
1188
1189   DISALLOW_COPY_AND_ASSIGN(DesktopAuraTopLevelWindowTest);
1190 };
1191
1192 TEST_F(WidgetTest, DesktopAuraFullscreenWindowDestroyedBeforeOwnerTest) {
1193   ViewsDelegate::views_delegate = NULL;
1194   DesktopAuraTopLevelWindowTest fullscreen_window;
1195   ASSERT_NO_FATAL_FAILURE(fullscreen_window.CreateTopLevelWindow(
1196       gfx::Rect(0, 0, 200, 200), true));
1197
1198   RunPendingMessages();
1199   ASSERT_NO_FATAL_FAILURE(fullscreen_window.DestroyOwnedWindow());
1200   RunPendingMessages();
1201 }
1202
1203 TEST_F(WidgetTest, DesktopAuraFullscreenWindowOwnerDestroyed) {
1204   ViewsDelegate::views_delegate = NULL;
1205
1206   DesktopAuraTopLevelWindowTest fullscreen_window;
1207   ASSERT_NO_FATAL_FAILURE(fullscreen_window.CreateTopLevelWindow(
1208       gfx::Rect(0, 0, 200, 200), true));
1209
1210   RunPendingMessages();
1211   ASSERT_NO_FATAL_FAILURE(fullscreen_window.DestroyOwnerWindow());
1212   RunPendingMessages();
1213 }
1214
1215 TEST_F(WidgetTest, DesktopAuraTopLevelOwnedPopupTest) {
1216   ViewsDelegate::views_delegate = NULL;
1217   DesktopAuraTopLevelWindowTest popup_window;
1218   ASSERT_NO_FATAL_FAILURE(popup_window.CreateTopLevelWindow(
1219       gfx::Rect(0, 0, 200, 200), false));
1220
1221   RunPendingMessages();
1222   ASSERT_NO_FATAL_FAILURE(popup_window.DestroyOwnedWindow());
1223   RunPendingMessages();
1224 }
1225
1226 // This test validates that when a top level owned popup Aura window is
1227 // resized, the widget is resized as well.
1228 TEST_F(WidgetTest, DesktopAuraTopLevelOwnedPopupResizeTest) {
1229   ViewsDelegate::views_delegate = NULL;
1230   DesktopAuraTopLevelWindowTest popup_window;
1231   ASSERT_NO_FATAL_FAILURE(popup_window.CreateTopLevelWindow(
1232       gfx::Rect(0, 0, 200, 200), false));
1233
1234   gfx::Rect new_size(0, 0, 400, 400);
1235   popup_window.owned_window()->SetBounds(new_size);
1236
1237   EXPECT_EQ(popup_window.top_level_widget()->GetNativeView()->bounds().size(),
1238             new_size.size());
1239   RunPendingMessages();
1240   ASSERT_NO_FATAL_FAILURE(popup_window.DestroyOwnedWindow());
1241   RunPendingMessages();
1242 }
1243
1244 // Test to ensure that the aura Window's visiblity state is set to visible if
1245 // the underlying widget is hidden and then shown.
1246 TEST_F(WidgetTest, TestWindowVisibilityAfterHide) {
1247   // Create a widget.
1248   Widget widget;
1249   Widget::InitParams init_params =
1250       CreateParams(Widget::InitParams::TYPE_WINDOW);
1251   init_params.show_state = ui::SHOW_STATE_NORMAL;
1252   gfx::Rect initial_bounds(0, 0, 300, 400);
1253   init_params.bounds = initial_bounds;
1254   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1255   init_params.native_widget = new DesktopNativeWidgetAura(&widget);
1256   widget.Init(init_params);
1257   NonClientView* non_client_view = widget.non_client_view();
1258   NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1259   non_client_view->SetFrameView(frame_view);
1260
1261   widget.Hide();
1262   EXPECT_FALSE(widget.GetNativeView()->IsVisible());
1263   widget.Show();
1264   EXPECT_TRUE(widget.GetNativeView()->IsVisible());
1265 }
1266
1267 // The following code verifies we can correctly destroy a Widget from a mouse
1268 // enter/exit. We could test move/drag/enter/exit but in general we don't run
1269 // nested message loops from such events, nor has the code ever really dealt
1270 // with this situation.
1271
1272 // Class that closes the widget (which ends up deleting it immediately) when the
1273 // appropriate event is received.
1274 class CloseWidgetView : public View {
1275  public:
1276   explicit CloseWidgetView(ui::EventType event_type)
1277       : event_type_(event_type) {
1278   }
1279
1280   // View overrides:
1281   virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
1282     if (!CloseWidget(event))
1283       View::OnMousePressed(event);
1284     return true;
1285   }
1286   virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE {
1287     if (!CloseWidget(event))
1288       View::OnMouseDragged(event);
1289     return true;
1290   }
1291   virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE {
1292     if (!CloseWidget(event))
1293       View::OnMouseReleased(event);
1294   }
1295   virtual void OnMouseMoved(const ui::MouseEvent& event) OVERRIDE {
1296     if (!CloseWidget(event))
1297       View::OnMouseMoved(event);
1298   }
1299   virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE {
1300     if (!CloseWidget(event))
1301       View::OnMouseEntered(event);
1302   }
1303
1304  private:
1305   bool CloseWidget(const ui::LocatedEvent& event) {
1306     if (event.type() == event_type_) {
1307       // Go through NativeWidgetPrivate to simulate what happens if the OS
1308       // deletes the NativeWindow out from under us.
1309       GetWidget()->native_widget_private()->CloseNow();
1310       return true;
1311     }
1312     return false;
1313   }
1314
1315   const ui::EventType event_type_;
1316
1317   DISALLOW_COPY_AND_ASSIGN(CloseWidgetView);
1318 };
1319
1320 // Generates two moves (first generates enter, second real move), a press, drag
1321 // and release stopping at |last_event_type|.
1322 void GenerateMouseEvents(Widget* widget, ui::EventType last_event_type) {
1323   const gfx::Rect screen_bounds(widget->GetWindowBoundsInScreen());
1324   ui::MouseEvent move_event(ui::ET_MOUSE_MOVED, screen_bounds.CenterPoint(),
1325                             screen_bounds.CenterPoint(), 0, 0);
1326   aura::WindowEventDispatcher* dispatcher =
1327       widget->GetNativeWindow()->GetDispatcher();
1328   ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&move_event);
1329   if (last_event_type == ui::ET_MOUSE_ENTERED || details.dispatcher_destroyed)
1330     return;
1331   details = dispatcher->OnEventFromSource(&move_event);
1332   if (last_event_type == ui::ET_MOUSE_MOVED || details.dispatcher_destroyed)
1333     return;
1334
1335   ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, screen_bounds.CenterPoint(),
1336                              screen_bounds.CenterPoint(), 0, 0);
1337   details = dispatcher->OnEventFromSource(&press_event);
1338   if (last_event_type == ui::ET_MOUSE_PRESSED || details.dispatcher_destroyed)
1339     return;
1340
1341   gfx::Point end_point(screen_bounds.CenterPoint());
1342   end_point.Offset(1, 1);
1343   ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, end_point, end_point, 0, 0);
1344   details = dispatcher->OnEventFromSource(&drag_event);
1345   if (last_event_type == ui::ET_MOUSE_DRAGGED || details.dispatcher_destroyed)
1346     return;
1347
1348   ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, end_point, end_point, 0,
1349                                0);
1350   details = dispatcher->OnEventFromSource(&release_event);
1351   if (details.dispatcher_destroyed)
1352     return;
1353 }
1354
1355 // Creates a widget and invokes GenerateMouseEvents() with |last_event_type|.
1356 void RunCloseWidgetDuringDispatchTest(WidgetTest* test,
1357                                       ui::EventType last_event_type) {
1358   // |widget| is deleted by CloseWidgetView.
1359   Widget* widget = new Widget;
1360   Widget::InitParams params =
1361       test->CreateParams(Widget::InitParams::TYPE_POPUP);
1362   params.native_widget = new DesktopNativeWidgetAura(widget);
1363   params.bounds = gfx::Rect(0, 0, 50, 100);
1364   widget->Init(params);
1365   widget->SetContentsView(new CloseWidgetView(last_event_type));
1366   widget->Show();
1367   GenerateMouseEvents(widget, last_event_type);
1368 }
1369
1370 // Verifies deleting the widget from a mouse pressed event doesn't crash.
1371 TEST_F(WidgetTest, CloseWidgetDuringMousePress) {
1372   RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_PRESSED);
1373 }
1374
1375 // Verifies deleting the widget from a mouse released event doesn't crash.
1376 TEST_F(WidgetTest, CloseWidgetDuringMouseReleased) {
1377   RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_RELEASED);
1378 }
1379
1380 #endif  // !defined(OS_CHROMEOS)
1381
1382 // Tests that wheel events generated from scroll events are targetted to the
1383 // views under the cursor when the focused view does not processed them.
1384 TEST_F(WidgetTest, WheelEventsFromScrollEventTarget) {
1385   EventCountView* cursor_view = new EventCountView;
1386   cursor_view->SetBounds(60, 0, 50, 40);
1387
1388   Widget* widget = CreateTopLevelPlatformWidget();
1389   widget->GetRootView()->AddChildView(cursor_view);
1390
1391   // Generate a scroll event on the cursor view.
1392   ui::ScrollEvent scroll(ui::ET_SCROLL,
1393                          gfx::Point(65, 5),
1394                          ui::EventTimeForNow(),
1395                          0,
1396                          0, 20,
1397                          0, 20,
1398                          2);
1399   widget->OnScrollEvent(&scroll);
1400
1401   EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_SCROLL));
1402   EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1403
1404   cursor_view->ResetCounts();
1405
1406   ui::ScrollEvent scroll2(ui::ET_SCROLL,
1407                           gfx::Point(5, 5),
1408                           ui::EventTimeForNow(),
1409                           0,
1410                           0, 20,
1411                           0, 20,
1412                           2);
1413   widget->OnScrollEvent(&scroll2);
1414
1415   EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_SCROLL));
1416   EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1417
1418   widget->CloseNow();
1419 }
1420
1421 #endif  // defined(USE_AURA)
1422
1423 // Tests that if a scroll-begin gesture is not handled, then subsequent scroll
1424 // events are not dispatched to any view.
1425 TEST_F(WidgetTest, GestureScrollEventDispatching) {
1426   EventCountView* noscroll_view = new EventCountView;
1427   EventCountView* scroll_view = new ScrollableEventCountView;
1428
1429   noscroll_view->SetBounds(0, 0, 50, 40);
1430   scroll_view->SetBounds(60, 0, 40, 40);
1431
1432   Widget* widget = CreateTopLevelPlatformWidget();
1433   widget->GetRootView()->AddChildView(noscroll_view);
1434   widget->GetRootView()->AddChildView(scroll_view);
1435
1436   {
1437     ui::GestureEvent begin(ui::ET_GESTURE_SCROLL_BEGIN,
1438         5, 5, 0, base::TimeDelta(),
1439         ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0),
1440         1);
1441     widget->OnGestureEvent(&begin);
1442     ui::GestureEvent update(ui::ET_GESTURE_SCROLL_UPDATE,
1443         25, 15, 0, base::TimeDelta(),
1444         ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10),
1445         1);
1446     widget->OnGestureEvent(&update);
1447     ui::GestureEvent end(ui::ET_GESTURE_SCROLL_END,
1448         25, 15, 0, base::TimeDelta(),
1449         ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END, 0, 0),
1450         1);
1451     widget->OnGestureEvent(&end);
1452
1453     EXPECT_EQ(1, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1454     EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1455     EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1456   }
1457
1458   {
1459     ui::GestureEvent begin(ui::ET_GESTURE_SCROLL_BEGIN,
1460         65, 5, 0, base::TimeDelta(),
1461         ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0),
1462         1);
1463     widget->OnGestureEvent(&begin);
1464     ui::GestureEvent update(ui::ET_GESTURE_SCROLL_UPDATE,
1465         85, 15, 0, base::TimeDelta(),
1466         ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10),
1467         1);
1468     widget->OnGestureEvent(&update);
1469     ui::GestureEvent end(ui::ET_GESTURE_SCROLL_END,
1470         85, 15, 0, base::TimeDelta(),
1471         ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END, 0, 0),
1472         1);
1473     widget->OnGestureEvent(&end);
1474
1475     EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1476     EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1477     EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1478   }
1479
1480   widget->CloseNow();
1481 }
1482
1483 // Tests that event-handlers installed on the RootView get triggered correctly.
1484 TEST_F(WidgetTest, EventHandlersOnRootView) {
1485   Widget* widget = CreateTopLevelNativeWidget();
1486   View* root_view = widget->GetRootView();
1487
1488   EventCountView* view = new EventCountView;
1489   view->SetBounds(0, 0, 20, 20);
1490   root_view->AddChildView(view);
1491
1492   EventCountHandler h1;
1493   root_view->AddPreTargetHandler(&h1);
1494
1495   EventCountHandler h2;
1496   root_view->AddPostTargetHandler(&h2);
1497
1498   widget->SetBounds(gfx::Rect(0, 0, 100, 100));
1499   widget->Show();
1500
1501   ui::TouchEvent pressed(ui::ET_TOUCH_PRESSED,
1502                          gfx::Point(10, 10),
1503                          0, 0,
1504                          ui::EventTimeForNow(),
1505                          1.0, 0.0, 1.0, 0.0);
1506   widget->OnTouchEvent(&pressed);
1507   EXPECT_EQ(1, h1.GetEventCount(ui::ET_TOUCH_PRESSED));
1508   EXPECT_EQ(1, view->GetEventCount(ui::ET_TOUCH_PRESSED));
1509   EXPECT_EQ(1, h2.GetEventCount(ui::ET_TOUCH_PRESSED));
1510
1511   ui::GestureEvent begin(ui::ET_GESTURE_BEGIN,
1512       5, 5, 0, ui::EventTimeForNow(),
1513       ui::GestureEventDetails(ui::ET_GESTURE_BEGIN, 0, 0), 1);
1514   ui::GestureEvent end(ui::ET_GESTURE_END,
1515       5, 5, 0, ui::EventTimeForNow(),
1516       ui::GestureEventDetails(ui::ET_GESTURE_END, 0, 0), 1);
1517   widget->OnGestureEvent(&begin);
1518   EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_BEGIN));
1519   EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_BEGIN));
1520   EXPECT_EQ(1, h2.GetEventCount(ui::ET_GESTURE_BEGIN));
1521
1522   ui::TouchEvent released(ui::ET_TOUCH_RELEASED,
1523                           gfx::Point(10, 10),
1524                           0, 0,
1525                           ui::EventTimeForNow(),
1526                           1.0, 0.0, 1.0, 0.0);
1527   widget->OnTouchEvent(&released);
1528   EXPECT_EQ(1, h1.GetEventCount(ui::ET_TOUCH_RELEASED));
1529   EXPECT_EQ(1, view->GetEventCount(ui::ET_TOUCH_RELEASED));
1530   EXPECT_EQ(1, h2.GetEventCount(ui::ET_TOUCH_RELEASED));
1531
1532   widget->OnGestureEvent(&end);
1533   EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_END));
1534   EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_END));
1535   EXPECT_EQ(1, h2.GetEventCount(ui::ET_GESTURE_END));
1536
1537   ui::ScrollEvent scroll(ui::ET_SCROLL,
1538                          gfx::Point(5, 5),
1539                          ui::EventTimeForNow(),
1540                          0,
1541                          0, 20,
1542                          0, 20,
1543                          2);
1544   widget->OnScrollEvent(&scroll);
1545   EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL));
1546   EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1547   EXPECT_EQ(1, h2.GetEventCount(ui::ET_SCROLL));
1548
1549   widget->CloseNow();
1550 }
1551
1552 TEST_F(WidgetTest, SynthesizeMouseMoveEvent) {
1553   Widget* widget = CreateTopLevelNativeWidget();
1554   View* root_view = widget->GetRootView();
1555
1556   EventCountView* v1 = new EventCountView();
1557   v1->SetBounds(0, 0, 10, 10);
1558   root_view->AddChildView(v1);
1559   EventCountView* v2 = new EventCountView();
1560   v2->SetBounds(0, 10, 10, 10);
1561   root_view->AddChildView(v2);
1562
1563   gfx::Point cursor_location(5, 5);
1564   ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
1565                       ui::EF_NONE, ui::EF_NONE);
1566   widget->OnMouseEvent(&move);
1567
1568   EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
1569   EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1570
1571   delete v1;
1572   v2->SetBounds(0, 0, 10, 10);
1573   EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1574
1575   widget->SynthesizeMouseMoveEvent();
1576   EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1577 }
1578
1579 // Used by SingleWindowClosing to count number of times WindowClosing() has
1580 // been invoked.
1581 class ClosingDelegate : public WidgetDelegate {
1582  public:
1583   ClosingDelegate() : count_(0), widget_(NULL) {}
1584
1585   int count() const { return count_; }
1586
1587   void set_widget(views::Widget* widget) { widget_ = widget; }
1588
1589   // WidgetDelegate overrides:
1590   virtual Widget* GetWidget() OVERRIDE { return widget_; }
1591   virtual const Widget* GetWidget() const OVERRIDE { return widget_; }
1592   virtual void WindowClosing() OVERRIDE {
1593     count_++;
1594   }
1595
1596  private:
1597   int count_;
1598   views::Widget* widget_;
1599
1600   DISALLOW_COPY_AND_ASSIGN(ClosingDelegate);
1601 };
1602
1603 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget
1604 // is closed.
1605 TEST_F(WidgetTest, SingleWindowClosing) {
1606   scoped_ptr<ClosingDelegate> delegate(new ClosingDelegate());
1607   Widget* widget = new Widget();  // Destroyed by CloseNow() below.
1608   Widget::InitParams init_params =
1609       CreateParams(Widget::InitParams::TYPE_WINDOW);
1610   init_params.bounds = gfx::Rect(0, 0, 200, 200);
1611   init_params.delegate = delegate.get();
1612 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1613   init_params.native_widget = new DesktopNativeWidgetAura(widget);
1614 #endif
1615   widget->Init(init_params);
1616   EXPECT_EQ(0, delegate->count());
1617   widget->CloseNow();
1618   EXPECT_EQ(1, delegate->count());
1619 }
1620
1621 class WidgetWindowTitleTest : public WidgetTest {
1622  protected:
1623   void RunTest(bool desktop_native_widget) {
1624     Widget* widget = new Widget();  // Destroyed by CloseNow() below.
1625     Widget::InitParams init_params =
1626         CreateParams(Widget::InitParams::TYPE_WINDOW);
1627     widget->Init(init_params);
1628
1629 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1630     if (desktop_native_widget)
1631       init_params.native_widget = new DesktopNativeWidgetAura(widget);
1632 #else
1633     DCHECK(!desktop_native_widget)
1634         << "DesktopNativeWidget does not exist on non-Aura or on ChromeOS.";
1635 #endif
1636
1637     internal::NativeWidgetPrivate* native_widget =
1638         widget->native_widget_private();
1639
1640     base::string16 empty;
1641     base::string16 s1(base::UTF8ToUTF16("Title1"));
1642     base::string16 s2(base::UTF8ToUTF16("Title2"));
1643     base::string16 s3(base::UTF8ToUTF16("TitleLong"));
1644
1645     // The widget starts with no title, setting empty should not change
1646     // anything.
1647     EXPECT_FALSE(native_widget->SetWindowTitle(empty));
1648     // Setting the title to something non-empty should cause a change.
1649     EXPECT_TRUE(native_widget->SetWindowTitle(s1));
1650     // Setting the title to something else with the same length should cause a
1651     // change.
1652     EXPECT_TRUE(native_widget->SetWindowTitle(s2));
1653     // Setting the title to something else with a different length should cause
1654     // a change.
1655     EXPECT_TRUE(native_widget->SetWindowTitle(s3));
1656     // Setting the title to the same thing twice should not cause a change.
1657     EXPECT_FALSE(native_widget->SetWindowTitle(s3));
1658
1659     widget->CloseNow();
1660   }
1661 };
1662
1663 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_NativeWidget) {
1664   // Use the default NativeWidget.
1665   bool desktop_native_widget = false;
1666   RunTest(desktop_native_widget);
1667 }
1668
1669 // DesktopNativeWidget does not exist on non-Aura or on ChromeOS.
1670 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1671 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_DesktopNativeWidget) {
1672   // Override to use a DesktopNativeWidget.
1673   bool desktop_native_widget = true;
1674   RunTest(desktop_native_widget);
1675 }
1676 #endif  // USE_AURA && !OS_CHROMEOS
1677
1678 // Used by SetTopLevelCorrectly to track calls to OnBeforeWidgetInit().
1679 class VerifyTopLevelDelegate : public TestViewsDelegate {
1680  public:
1681   VerifyTopLevelDelegate()
1682       : on_before_init_called_(false),
1683         is_top_level_(false) {
1684   }
1685
1686   bool on_before_init_called() const { return on_before_init_called_; }
1687   bool is_top_level() const { return is_top_level_; }
1688
1689   virtual void OnBeforeWidgetInit(
1690       Widget::InitParams* params,
1691       internal::NativeWidgetDelegate* delegate) OVERRIDE {
1692     on_before_init_called_ = true;
1693     is_top_level_ = params->top_level;
1694   }
1695
1696  private:
1697   bool on_before_init_called_;
1698   bool is_top_level_;
1699
1700   DISALLOW_COPY_AND_ASSIGN(VerifyTopLevelDelegate);
1701 };
1702
1703 // Verifies |top_level| is correctly passed to
1704 // ViewsDelegate::OnBeforeWidgetInit().
1705 TEST_F(WidgetTest, SetTopLevelCorrectly) {
1706   set_views_delegate(NULL);
1707   VerifyTopLevelDelegate* delegate = new VerifyTopLevelDelegate;
1708   set_views_delegate(delegate);  // ViewsTestBase takes ownership.
1709   scoped_ptr<Widget> widget(new Widget);
1710   Widget::InitParams params =
1711       CreateParams(views::Widget::InitParams::TYPE_POPUP);
1712   params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1713   widget->Init(params);
1714   EXPECT_TRUE(delegate->on_before_init_called());
1715   EXPECT_TRUE(delegate->is_top_level());
1716 }
1717
1718 // A scumbag View that deletes its owning widget OnMousePressed.
1719 class WidgetDeleterView : public View {
1720  public:
1721   WidgetDeleterView() : View() {}
1722
1723   // Overridden from View.
1724   virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
1725     delete GetWidget();
1726     return true;
1727   }
1728
1729  private:
1730   DISALLOW_COPY_AND_ASSIGN(WidgetDeleterView);
1731 };
1732
1733 TEST_F(WidgetTest, TestWidgetDeletedInOnMousePressed) {
1734   Widget* widget = new Widget;
1735   Widget::InitParams params =
1736       CreateParams(views::Widget::InitParams::TYPE_POPUP);
1737   params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1738   widget->Init(params);
1739
1740   widget->SetContentsView(new WidgetDeleterView);
1741
1742   widget->SetSize(gfx::Size(100, 100));
1743   widget->Show();
1744
1745   gfx::Point click_location(45, 15);
1746   ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
1747                        ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
1748   widget->OnMouseEvent(&press);
1749
1750   // Yay we did not crash!
1751 }
1752
1753 // See description of RunGetNativeThemeFromDestructor() for details.
1754 class GetNativeThemeFromDestructorView : public WidgetDelegateView {
1755  public:
1756   GetNativeThemeFromDestructorView() {}
1757   virtual ~GetNativeThemeFromDestructorView() {
1758     VerifyNativeTheme();
1759   }
1760
1761   virtual View* GetContentsView() OVERRIDE {
1762     return this;
1763   }
1764
1765  private:
1766   void VerifyNativeTheme() {
1767     ASSERT_TRUE(GetNativeTheme() != NULL);
1768   }
1769
1770   DISALLOW_COPY_AND_ASSIGN(GetNativeThemeFromDestructorView);
1771 };
1772
1773 // Verifies GetNativeTheme() from the destructor of a WidgetDelegateView doesn't
1774 // crash. |is_first_run| is true if this is the first call. A return value of
1775 // true indicates this should be run again with a value of false.
1776 // First run uses DesktopNativeWidgetAura (if possible). Second run doesn't.
1777 bool RunGetNativeThemeFromDestructor(const Widget::InitParams& in_params,
1778                                      bool is_first_run) {
1779   bool needs_second_run = false;
1780   // Destroyed by CloseNow() below.
1781   Widget* widget = new Widget;
1782   Widget::InitParams params(in_params);
1783   // Deletes itself when the Widget is destroyed.
1784   params.delegate = new GetNativeThemeFromDestructorView;
1785 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1786   if (is_first_run) {
1787     params.native_widget = new DesktopNativeWidgetAura(widget);
1788     needs_second_run = true;
1789   }
1790 #endif
1791   widget->Init(params);
1792   widget->CloseNow();
1793   return needs_second_run;
1794 }
1795
1796 // See description of RunGetNativeThemeFromDestructor() for details.
1797 TEST_F(WidgetTest, GetNativeThemeFromDestructor) {
1798   Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1799   if (RunGetNativeThemeFromDestructor(params, true))
1800     RunGetNativeThemeFromDestructor(params, false);
1801 }
1802
1803 // Used by HideCloseDestroy. Allows setting a boolean when the widget is
1804 // destroyed.
1805 class CloseDestroysWidget : public Widget {
1806  public:
1807   explicit CloseDestroysWidget(bool* destroyed)
1808       : destroyed_(destroyed) {
1809   }
1810
1811   virtual ~CloseDestroysWidget() {
1812     if (destroyed_) {
1813       *destroyed_ = true;
1814       base::MessageLoop::current()->QuitNow();
1815     }
1816   }
1817
1818   void Detach() { destroyed_ = NULL; }
1819
1820  private:
1821   // If non-null set to true from destructor.
1822   bool* destroyed_;
1823
1824   DISALLOW_COPY_AND_ASSIGN(CloseDestroysWidget);
1825 };
1826
1827 // Verifies Close() results in destroying.
1828 TEST_F(WidgetTest, CloseDestroys) {
1829   bool destroyed = false;
1830   CloseDestroysWidget* widget = new CloseDestroysWidget(&destroyed);
1831   Widget::InitParams params =
1832       CreateParams(views::Widget::InitParams::TYPE_MENU);
1833   params.opacity = Widget::InitParams::OPAQUE_WINDOW;
1834 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1835   params.native_widget = new DesktopNativeWidgetAura(widget);
1836 #endif
1837   widget->Init(params);
1838   widget->Show();
1839   widget->Hide();
1840   widget->Close();
1841   // Run the message loop as Close() asynchronously deletes.
1842   RunPendingMessages();
1843   EXPECT_TRUE(destroyed);
1844   // Close() should destroy the widget. If not we'll cleanup to avoid leaks.
1845   if (!destroyed) {
1846     widget->Detach();
1847     widget->CloseNow();
1848   }
1849 }
1850
1851 // A view that consumes mouse-pressed event and gesture-tap-down events.
1852 class RootViewTestView : public View {
1853  public:
1854   RootViewTestView(): View() {}
1855
1856  private:
1857   virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
1858     return true;
1859   }
1860
1861   virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
1862     if (event->type() == ui::ET_GESTURE_TAP_DOWN)
1863       event->SetHandled();
1864   }
1865 };
1866
1867 // Checks if RootView::*_handler_ fields are unset when widget is hidden.
1868 // Fails on chromium.webkit Windows bot, see crbug.com/264872.
1869 #if defined(OS_WIN)
1870 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1871     DISABLED_TestRootViewHandlersWhenHidden
1872 #else
1873 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1874     TestRootViewHandlersWhenHidden
1875 #endif
1876 TEST_F(WidgetTest, MAYBE_DisableTestRootViewHandlersWhenHidden) {
1877   Widget* widget = CreateTopLevelNativeWidget();
1878   widget->SetBounds(gfx::Rect(0, 0, 300, 300));
1879   View* view = new RootViewTestView();
1880   view->SetBounds(0, 0, 300, 300);
1881   internal::RootView* root_view =
1882       static_cast<internal::RootView*>(widget->GetRootView());
1883   root_view->AddChildView(view);
1884
1885   // Check RootView::mouse_pressed_handler_.
1886   widget->Show();
1887   EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
1888   gfx::Point click_location(45, 15);
1889   ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
1890                        ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
1891   widget->OnMouseEvent(&press);
1892   EXPECT_EQ(view, GetMousePressedHandler(root_view));
1893   widget->Hide();
1894   EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
1895
1896   // Check RootView::mouse_move_handler_.
1897   widget->Show();
1898   EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
1899   gfx::Point move_location(45, 15);
1900   ui::MouseEvent move(ui::ET_MOUSE_MOVED, move_location, move_location, 0, 0);
1901   widget->OnMouseEvent(&move);
1902   EXPECT_EQ(view, GetMouseMoveHandler(root_view));
1903   widget->Hide();
1904   EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
1905
1906   // Check RootView::gesture_handler_.
1907   widget->Show();
1908   EXPECT_EQ(NULL, GetGestureHandler(root_view));
1909   ui::GestureEvent tap_down(
1910       ui::ET_GESTURE_TAP_DOWN,
1911       15,
1912       15,
1913       0,
1914       base::TimeDelta(),
1915       ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN, 0, 0),
1916       1);
1917   widget->OnGestureEvent(&tap_down);
1918   EXPECT_EQ(view, GetGestureHandler(root_view));
1919   widget->Hide();
1920   EXPECT_EQ(NULL, GetGestureHandler(root_view));
1921
1922   widget->Close();
1923 }
1924
1925 // Test the result of Widget::GetAllChildWidgets().
1926 TEST_F(WidgetTest, GetAllChildWidgets) {
1927   // Create the following widget hierarchy:
1928   //
1929   // toplevel
1930   // +-- w1
1931   //     +-- w11
1932   // +-- w2
1933   //     +-- w21
1934   //     +-- w22
1935   Widget* toplevel = CreateTopLevelPlatformWidget();
1936   Widget* w1 = CreateChildPlatformWidget(toplevel->GetNativeView());
1937   Widget* w11 = CreateChildPlatformWidget(w1->GetNativeView());
1938   Widget* w2 = CreateChildPlatformWidget(toplevel->GetNativeView());
1939   Widget* w21 = CreateChildPlatformWidget(w2->GetNativeView());
1940   Widget* w22 = CreateChildPlatformWidget(w2->GetNativeView());
1941
1942   std::set<Widget*> expected;
1943   expected.insert(toplevel);
1944   expected.insert(w1);
1945   expected.insert(w11);
1946   expected.insert(w2);
1947   expected.insert(w21);
1948   expected.insert(w22);
1949
1950   std::set<Widget*> widgets;
1951   Widget::GetAllChildWidgets(toplevel->GetNativeView(), &widgets);
1952
1953   EXPECT_EQ(expected.size(), widgets.size());
1954   EXPECT_TRUE(std::equal(expected.begin(), expected.end(), widgets.begin()));
1955 }
1956
1957 // Used by DestroyChildWidgetsInOrder. On destruction adds the supplied name to
1958 // a vector.
1959 class DestroyedTrackingView : public View {
1960  public:
1961   DestroyedTrackingView(const std::string& name,
1962                         std::vector<std::string>* add_to)
1963       : name_(name),
1964         add_to_(add_to) {
1965   }
1966
1967   virtual ~DestroyedTrackingView() {
1968     add_to_->push_back(name_);
1969   }
1970
1971  private:
1972   const std::string name_;
1973   std::vector<std::string>* add_to_;
1974
1975   DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingView);
1976 };
1977
1978 class WidgetChildDestructionTest : public WidgetTest {
1979  public:
1980   WidgetChildDestructionTest() {}
1981
1982   // Creates a top level and a child, destroys the child and verifies the views
1983   // of the child are destroyed before the views of the parent.
1984   void RunDestroyChildWidgetsTest(bool top_level_has_desktop_native_widget_aura,
1985                                   bool child_has_desktop_native_widget_aura) {
1986     // When a View is destroyed its name is added here.
1987     std::vector<std::string> destroyed;
1988
1989     Widget* top_level = new Widget;
1990     Widget::InitParams params =
1991         CreateParams(views::Widget::InitParams::TYPE_WINDOW);
1992 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
1993     if (top_level_has_desktop_native_widget_aura)
1994       params.native_widget = new DesktopNativeWidgetAura(top_level);
1995 #endif
1996     top_level->Init(params);
1997     top_level->GetRootView()->AddChildView(
1998         new DestroyedTrackingView("parent", &destroyed));
1999     top_level->Show();
2000
2001     Widget* child = new Widget;
2002     Widget::InitParams child_params =
2003         CreateParams(views::Widget::InitParams::TYPE_POPUP);
2004     child_params.parent = top_level->GetNativeView();
2005 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
2006     if (child_has_desktop_native_widget_aura)
2007       child_params.native_widget = new DesktopNativeWidgetAura(child);
2008 #endif
2009     child->Init(child_params);
2010     child->GetRootView()->AddChildView(
2011         new DestroyedTrackingView("child", &destroyed));
2012     child->Show();
2013
2014     // Should trigger destruction of the child too.
2015     top_level->native_widget_private()->CloseNow();
2016
2017     // Child should be destroyed first.
2018     ASSERT_EQ(2u, destroyed.size());
2019     EXPECT_EQ("child", destroyed[0]);
2020     EXPECT_EQ("parent", destroyed[1]);
2021   }
2022
2023  private:
2024   DISALLOW_COPY_AND_ASSIGN(WidgetChildDestructionTest);
2025 };
2026
2027 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
2028 // See description of RunDestroyChildWidgetsTest(). Parent uses
2029 // DesktopNativeWidgetAura.
2030 TEST_F(WidgetChildDestructionTest,
2031        DestroyChildWidgetsInOrderWithDesktopNativeWidget) {
2032   RunDestroyChildWidgetsTest(true, false);
2033 }
2034
2035 // See description of RunDestroyChildWidgetsTest(). Both parent and child use
2036 // DesktopNativeWidgetAura.
2037 TEST_F(WidgetChildDestructionTest,
2038        DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth) {
2039   RunDestroyChildWidgetsTest(true, true);
2040 }
2041 #endif
2042
2043 // See description of RunDestroyChildWidgetsTest().
2044 TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) {
2045   RunDestroyChildWidgetsTest(false, false);
2046 }
2047
2048 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
2049 // Provides functionality to create a window modal dialog.
2050 class ModalDialogDelegate : public DialogDelegateView {
2051  public:
2052   ModalDialogDelegate() {}
2053   virtual ~ModalDialogDelegate() {}
2054
2055   // WidgetDelegate overrides.
2056   virtual ui::ModalType GetModalType() const OVERRIDE {
2057     return ui::MODAL_TYPE_WINDOW;
2058   }
2059
2060  private:
2061   DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate);
2062 };
2063
2064 // This test verifies that whether mouse events when a modal dialog is
2065 // displayed are eaten or recieved by the dialog.
2066 TEST_F(WidgetTest, WindowMouseModalityTest) {
2067   // Create a top level widget.
2068   Widget top_level_widget;
2069   Widget::InitParams init_params =
2070       CreateParams(Widget::InitParams::TYPE_WINDOW);
2071   init_params.show_state = ui::SHOW_STATE_NORMAL;
2072   gfx::Rect initial_bounds(0, 0, 500, 500);
2073   init_params.bounds = initial_bounds;
2074   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2075   init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget);
2076   top_level_widget.Init(init_params);
2077   top_level_widget.Show();
2078   EXPECT_TRUE(top_level_widget.IsVisible());
2079
2080   // Create a view and validate that a mouse moves makes it to the view.
2081   EventCountView* widget_view = new EventCountView();
2082   widget_view->SetBounds(0, 0, 10, 10);
2083   top_level_widget.GetRootView()->AddChildView(widget_view);
2084
2085   gfx::Point cursor_location_main(5, 5);
2086   ui::MouseEvent move_main(ui::ET_MOUSE_MOVED,
2087                            cursor_location_main,
2088                            cursor_location_main,
2089                            ui::EF_NONE,
2090                            ui::EF_NONE);
2091   ui::EventDispatchDetails details = top_level_widget.GetNativeView()->
2092       GetDispatcher()->OnEventFromSource(&move_main);
2093   ASSERT_FALSE(details.dispatcher_destroyed);
2094
2095   EXPECT_EQ(1, widget_view->GetEventCount(ui::ET_MOUSE_ENTERED));
2096   widget_view->ResetCounts();
2097
2098   // Create a modal dialog and validate that a mouse down message makes it to
2099   // the main view within the dialog.
2100
2101   // This instance will be destroyed when the dialog is destroyed.
2102   ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
2103
2104   Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
2105       dialog_delegate, NULL, top_level_widget.GetNativeWindow());
2106   modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
2107   EventCountView* dialog_widget_view = new EventCountView();
2108   dialog_widget_view->SetBounds(0, 0, 50, 50);
2109   modal_dialog_widget->GetRootView()->AddChildView(dialog_widget_view);
2110   modal_dialog_widget->Show();
2111   EXPECT_TRUE(modal_dialog_widget->IsVisible());
2112
2113   gfx::Point cursor_location_dialog(100, 100);
2114   ui::MouseEvent mouse_down_dialog(ui::ET_MOUSE_PRESSED,
2115                                    cursor_location_dialog,
2116                                    cursor_location_dialog,
2117                                    ui::EF_NONE,
2118                                    ui::EF_NONE);
2119   details = top_level_widget.GetNativeView()->GetDispatcher()->
2120       OnEventFromSource(&mouse_down_dialog);
2121   ASSERT_FALSE(details.dispatcher_destroyed);
2122   EXPECT_EQ(1, dialog_widget_view->GetEventCount(ui::ET_MOUSE_PRESSED));
2123
2124   // Send a mouse move message to the main window. It should not be received by
2125   // the main window as the modal dialog is still active.
2126   gfx::Point cursor_location_main2(6, 6);
2127   ui::MouseEvent mouse_down_main(ui::ET_MOUSE_MOVED,
2128                                  cursor_location_main2,
2129                                  cursor_location_main2,
2130                                  ui::EF_NONE,
2131                                  ui::EF_NONE);
2132   details = top_level_widget.GetNativeView()->GetDispatcher()->
2133       OnEventFromSource(&mouse_down_main);
2134   ASSERT_FALSE(details.dispatcher_destroyed);
2135   EXPECT_EQ(0, widget_view->GetEventCount(ui::ET_MOUSE_MOVED));
2136
2137   modal_dialog_widget->CloseNow();
2138   top_level_widget.CloseNow();
2139 }
2140
2141 #if defined(USE_AURA)
2142 // Verifies nativeview visbility matches that of Widget visibility when
2143 // SetFullscreen is invoked.
2144 TEST_F(WidgetTest, FullscreenStatePropagated) {
2145   Widget::InitParams init_params =
2146       CreateParams(Widget::InitParams::TYPE_WINDOW);
2147   init_params.show_state = ui::SHOW_STATE_NORMAL;
2148   init_params.bounds = gfx::Rect(0, 0, 500, 500);
2149   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2150
2151   {
2152     Widget top_level_widget;
2153     top_level_widget.Init(init_params);
2154     top_level_widget.SetFullscreen(true);
2155     EXPECT_EQ(top_level_widget.IsVisible(),
2156               top_level_widget.GetNativeView()->IsVisible());
2157     top_level_widget.CloseNow();
2158   }
2159
2160 #if !defined(OS_CHROMEOS)
2161   {
2162     Widget top_level_widget;
2163     init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget);
2164     top_level_widget.Init(init_params);
2165     top_level_widget.SetFullscreen(true);
2166     EXPECT_EQ(top_level_widget.IsVisible(),
2167               top_level_widget.GetNativeView()->IsVisible());
2168     top_level_widget.CloseNow();
2169   }
2170 #endif
2171 }
2172 #endif
2173
2174 #if defined(OS_WIN)
2175
2176 // Provides functionality to test widget activation via an activation flag
2177 // which can be set by an accessor.
2178 class ModalWindowTestWidgetDelegate : public WidgetDelegate {
2179  public:
2180   ModalWindowTestWidgetDelegate()
2181       : widget_(NULL),
2182         can_activate_(true) {}
2183
2184   virtual ~ModalWindowTestWidgetDelegate() {}
2185
2186   // Overridden from WidgetDelegate:
2187   virtual void DeleteDelegate() OVERRIDE {
2188     delete this;
2189   }
2190   virtual Widget* GetWidget() OVERRIDE {
2191     return widget_;
2192   }
2193   virtual const Widget* GetWidget() const OVERRIDE {
2194     return widget_;
2195   }
2196   virtual bool CanActivate() const OVERRIDE {
2197     return can_activate_;
2198   }
2199   virtual bool ShouldAdvanceFocusToTopLevelWidget() const OVERRIDE {
2200     return true;
2201   }
2202
2203   void set_can_activate(bool can_activate) {
2204     can_activate_ = can_activate;
2205   }
2206
2207   void set_widget(Widget* widget) {
2208     widget_ = widget;
2209   }
2210
2211  private:
2212   Widget* widget_;
2213   bool can_activate_;
2214
2215   DISALLOW_COPY_AND_ASSIGN(ModalWindowTestWidgetDelegate);
2216 };
2217
2218 // Tests whether we can activate the top level widget when a modal dialog is
2219 // active.
2220 TEST_F(WidgetTest, WindowModalityActivationTest) {
2221   // Destroyed when the top level widget created below is destroyed.
2222   ModalWindowTestWidgetDelegate* widget_delegate =
2223       new ModalWindowTestWidgetDelegate;
2224   // Create a top level widget.
2225   Widget top_level_widget;
2226   Widget::InitParams init_params =
2227       CreateParams(Widget::InitParams::TYPE_WINDOW);
2228   init_params.show_state = ui::SHOW_STATE_NORMAL;
2229   gfx::Rect initial_bounds(0, 0, 500, 500);
2230   init_params.bounds = initial_bounds;
2231   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2232   init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget);
2233   init_params.delegate = widget_delegate;
2234   top_level_widget.Init(init_params);
2235   widget_delegate->set_widget(&top_level_widget);
2236   top_level_widget.Show();
2237   EXPECT_TRUE(top_level_widget.IsVisible());
2238
2239   HWND win32_window = views::HWNDForWidget(&top_level_widget);
2240   EXPECT_TRUE(::IsWindow(win32_window));
2241
2242   // This instance will be destroyed when the dialog is destroyed.
2243   ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
2244
2245   // We should be able to activate the window even if the WidgetDelegate
2246   // says no, when a modal dialog is active.
2247   widget_delegate->set_can_activate(false);
2248
2249   Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
2250       dialog_delegate, NULL, top_level_widget.GetNativeWindow());
2251   modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
2252   modal_dialog_widget->Show();
2253   EXPECT_TRUE(modal_dialog_widget->IsVisible());
2254
2255   LRESULT activate_result = ::SendMessage(
2256       win32_window,
2257       WM_MOUSEACTIVATE,
2258       reinterpret_cast<WPARAM>(win32_window),
2259       MAKELPARAM(WM_LBUTTONDOWN, HTCLIENT));
2260   EXPECT_EQ(activate_result, MA_ACTIVATE);
2261
2262   modal_dialog_widget->CloseNow();
2263   top_level_widget.CloseNow();
2264 }
2265 #endif
2266 #endif
2267
2268 TEST_F(WidgetTest, ShowCreatesActiveWindow) {
2269   Widget* widget = CreateTopLevelPlatformWidget();
2270
2271   widget->Show();
2272   EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2273
2274   widget->CloseNow();
2275 }
2276
2277 TEST_F(WidgetTest, ShowInactive) {
2278   Widget* widget = CreateTopLevelPlatformWidget();
2279
2280   widget->ShowInactive();
2281   EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_INACTIVE);
2282
2283   widget->CloseNow();
2284 }
2285
2286 TEST_F(WidgetTest, ShowInactiveAfterShow) {
2287   Widget* widget = CreateTopLevelPlatformWidget();
2288
2289   widget->Show();
2290   widget->ShowInactive();
2291   EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2292
2293   widget->CloseNow();
2294 }
2295
2296 TEST_F(WidgetTest, ShowAfterShowInactive) {
2297   Widget* widget = CreateTopLevelPlatformWidget();
2298
2299   widget->ShowInactive();
2300   widget->Show();
2301   EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2302
2303   widget->CloseNow();
2304 }
2305
2306 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
2307 TEST_F(WidgetTest, InactiveWidgetDoesNotGrabActivation) {
2308   Widget* widget = CreateTopLevelPlatformWidget();
2309   widget->Show();
2310   EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2311
2312   Widget widget2;
2313   Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2314   params.can_activate = false;
2315   params.native_widget = new DesktopNativeWidgetAura(&widget2);
2316   params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2317   widget2.Init(params);
2318   widget2.Show();
2319
2320   EXPECT_EQ(GetWidgetShowState(&widget2), ui::SHOW_STATE_INACTIVE);
2321   EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2322
2323   widget->CloseNow();
2324   widget2.CloseNow();
2325 }
2326 #endif
2327
2328 namespace {
2329
2330 class FullscreenAwareFrame : public views::NonClientFrameView {
2331  public:
2332   explicit FullscreenAwareFrame(views::Widget* widget)
2333       : widget_(widget), fullscreen_layout_called_(false) {}
2334   virtual ~FullscreenAwareFrame() {}
2335
2336   // views::NonClientFrameView overrides:
2337   virtual gfx::Rect GetBoundsForClientView() const OVERRIDE {
2338     return gfx::Rect();
2339   }
2340   virtual gfx::Rect GetWindowBoundsForClientBounds(
2341       const gfx::Rect& client_bounds) const OVERRIDE {
2342     return gfx::Rect();
2343   }
2344   virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE {
2345     return HTNOWHERE;
2346   }
2347   virtual void GetWindowMask(const gfx::Size& size,
2348                              gfx::Path* window_mask) OVERRIDE {}
2349   virtual void ResetWindowControls() OVERRIDE {}
2350   virtual void UpdateWindowIcon() OVERRIDE {}
2351   virtual void UpdateWindowTitle() OVERRIDE {}
2352
2353   // views::View overrides:
2354   virtual void Layout() OVERRIDE {
2355     if (widget_->IsFullscreen())
2356       fullscreen_layout_called_ = true;
2357   }
2358
2359   bool fullscreen_layout_called() const { return fullscreen_layout_called_; }
2360
2361  private:
2362   views::Widget* widget_;
2363   bool fullscreen_layout_called_;
2364
2365   DISALLOW_COPY_AND_ASSIGN(FullscreenAwareFrame);
2366 };
2367
2368 }  // namespace
2369
2370 // Tests that frame Layout is called when a widget goes fullscreen without
2371 // changing its size or title.
2372 TEST_F(WidgetTest, FullscreenFrameLayout) {
2373   Widget* widget = CreateTopLevelPlatformWidget();
2374   FullscreenAwareFrame* frame = new FullscreenAwareFrame(widget);
2375   widget->non_client_view()->SetFrameView(frame);  // Owns |frame|.
2376
2377   widget->Maximize();
2378   RunPendingMessages();
2379
2380   EXPECT_FALSE(frame->fullscreen_layout_called());
2381   widget->SetFullscreen(true);
2382   widget->Show();
2383   RunPendingMessages();
2384   EXPECT_TRUE(frame->fullscreen_layout_called());
2385
2386   widget->CloseNow();
2387 }
2388
2389 #if !defined(OS_CHROMEOS)
2390 namespace {
2391
2392 // Trivial WidgetObserverTest that invokes Widget::IsActive() from
2393 // OnWindowDestroying.
2394 class IsActiveFromDestroyObserver : public WidgetObserver {
2395  public:
2396   IsActiveFromDestroyObserver() {}
2397   virtual ~IsActiveFromDestroyObserver() {}
2398   virtual void OnWidgetDestroying(Widget* widget) OVERRIDE {
2399     widget->IsActive();
2400   }
2401
2402  private:
2403   DISALLOW_COPY_AND_ASSIGN(IsActiveFromDestroyObserver);
2404 };
2405
2406 }  // namespace
2407
2408 // Verifies Widget::IsActive() invoked from
2409 // WidgetObserver::OnWidgetDestroying() in a child widget doesn't crash.
2410 TEST_F(WidgetTest, IsActiveFromDestroy) {
2411   // Create two widgets, one a child of the other.
2412   IsActiveFromDestroyObserver observer;
2413   Widget parent_widget;
2414   Widget::InitParams parent_params =
2415       CreateParams(Widget::InitParams::TYPE_POPUP);
2416   parent_params.native_widget = new DesktopNativeWidgetAura(&parent_widget);
2417   parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2418   parent_widget.Init(parent_params);
2419   parent_widget.Show();
2420
2421   Widget child_widget;
2422   Widget::InitParams child_params =
2423       CreateParams(Widget::InitParams::TYPE_POPUP);
2424   child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2425   child_params.context = parent_widget.GetNativeView();
2426   child_widget.Init(child_params);
2427   child_widget.AddObserver(&observer);
2428   child_widget.Show();
2429
2430   parent_widget.CloseNow();
2431 }
2432 #endif
2433
2434 }  // namespace test
2435 }  // namespace views