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