OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "base/basictypes.h" | |
6 #include "base/memory/scoped_ptr.h" | |
7 #include "base/message_loop.h" | |
8 #include "testing/gtest/include/gtest/gtest.h" | |
9 #include "ui/views/test/test_views_delegate.h" | |
10 #include "ui/views/test/views_test_base.h" | |
11 #include "ui/gfx/point.h" | |
12 #include "ui/gfx/native_widget_types.h" | |
13 #include "views/views_delegate.h" | |
14 #include "views/widget/native_widget_delegate.h" | |
15 | |
16 #if defined(USE_AURA) | |
17 #include "ui/aura/window.h" | |
18 #include "views/widget/native_widget_aura.h" | |
19 #elif defined(OS_WIN) | |
20 #include "views/widget/native_widget_win.h" | |
21 #elif defined(TOOLKIT_USES_GTK) | |
22 #include "views/widget/native_widget_gtk.h" | |
23 #endif | |
24 | |
25 namespace views { | |
26 namespace { | |
27 | |
28 // A generic typedef to pick up relevant NativeWidget implementations. | |
29 #if defined(USE_AURA) | |
30 typedef NativeWidgetAura NativeWidgetPlatform; | |
31 #elif defined(OS_WIN) | |
32 typedef NativeWidgetWin NativeWidgetPlatform; | |
33 #elif defined(TOOLKIT_USES_GTK) | |
34 typedef NativeWidgetGtk NativeWidgetPlatform; | |
35 #endif | |
36 | |
37 // A widget that assumes mouse capture always works. It won't on Gtk/Aura in | |
38 // testing, so we mock it. | |
39 #if defined(TOOLKIT_USES_GTK) || defined(USE_AURA) | |
40 class NativeWidgetCapture : public NativeWidgetPlatform { | |
41 public: | |
42 NativeWidgetCapture(internal::NativeWidgetDelegate* delegate) | |
43 : NativeWidgetPlatform(delegate), | |
44 mouse_capture_(false) {} | |
45 virtual ~NativeWidgetCapture() {} | |
46 | |
47 virtual void SetMouseCapture() OVERRIDE { | |
48 mouse_capture_ = true; | |
49 } | |
50 virtual void ReleaseMouseCapture() OVERRIDE { | |
51 if (mouse_capture_) | |
52 delegate()->OnMouseCaptureLost(); | |
53 mouse_capture_ = false; | |
54 } | |
55 virtual bool HasMouseCapture() const OVERRIDE { | |
56 return mouse_capture_; | |
57 } | |
58 | |
59 private: | |
60 bool mouse_capture_; | |
61 | |
62 DISALLOW_COPY_AND_ASSIGN(NativeWidgetCapture); | |
63 }; | |
64 #endif | |
65 | |
66 // A typedef that inserts our mock-capture NativeWidget implementation for | |
67 // relevant platforms. | |
68 #if defined(USE_AURA) | |
69 typedef NativeWidgetCapture NativeWidgetPlatformForTest; | |
70 #elif defined(OS_WIN) | |
71 typedef NativeWidgetWin NativeWidgetPlatformForTest; | |
72 #elif defined(TOOLKIT_USES_GTK) | |
73 typedef NativeWidgetCapture NativeWidgetPlatformForTest; | |
74 #endif | |
75 | |
76 // A view that always processes all mouse events. | |
77 class MouseView : public View { | |
78 public: | |
79 MouseView() : View() { | |
80 } | |
81 virtual ~MouseView() {} | |
82 | |
83 virtual bool OnMousePressed(const MouseEvent& event) OVERRIDE { | |
84 return true; | |
85 } | |
86 }; | |
87 | |
88 typedef ViewsTestBase WidgetTest; | |
89 | |
90 NativeWidget* CreatePlatformNativeWidget( | |
91 internal::NativeWidgetDelegate* delegate) { | |
92 return new NativeWidgetPlatformForTest(delegate); | |
93 } | |
94 | |
95 Widget* CreateTopLevelPlatformWidget() { | |
96 Widget* toplevel = new Widget; | |
97 Widget::InitParams toplevel_params(Widget::InitParams::TYPE_WINDOW); | |
98 toplevel_params.native_widget = CreatePlatformNativeWidget(toplevel); | |
99 toplevel->Init(toplevel_params); | |
100 return toplevel; | |
101 } | |
102 | |
103 Widget* CreateChildPlatformWidget(gfx::NativeView parent_native_view) { | |
104 Widget* child = new Widget; | |
105 Widget::InitParams child_params(Widget::InitParams::TYPE_CONTROL); | |
106 child_params.native_widget = CreatePlatformNativeWidget(child); | |
107 child_params.parent = parent_native_view; | |
108 child->Init(child_params); | |
109 child->SetContentsView(new View); | |
110 return child; | |
111 } | |
112 | |
113 #if defined(OS_WIN) && !defined(USE_AURA) | |
114 // On Windows, it is possible for us to have a child window that is TYPE_POPUP. | |
115 Widget* CreateChildPopupPlatformWidget(gfx::NativeView parent_native_view) { | |
116 Widget* child = new Widget; | |
117 Widget::InitParams child_params(Widget::InitParams::TYPE_POPUP); | |
118 child_params.child = true; | |
119 child_params.native_widget = CreatePlatformNativeWidget(child); | |
120 child_params.parent = parent_native_view; | |
121 child->Init(child_params); | |
122 child->SetContentsView(new View); | |
123 return child; | |
124 } | |
125 #endif | |
126 | |
127 Widget* CreateTopLevelNativeWidget() { | |
128 Widget* toplevel = new Widget; | |
129 Widget::InitParams params(Widget::InitParams::TYPE_WINDOW); | |
130 toplevel->Init(params); | |
131 toplevel->SetContentsView(new View); | |
132 return toplevel; | |
133 } | |
134 | |
135 Widget* CreateChildNativeWidgetWithParent(Widget* parent) { | |
136 Widget* child = new Widget; | |
137 Widget::InitParams params(Widget::InitParams::TYPE_CONTROL); | |
138 params.parent_widget = parent; | |
139 child->Init(params); | |
140 child->SetContentsView(new View); | |
141 return child; | |
142 } | |
143 | |
144 Widget* CreateChildNativeWidget() { | |
145 return CreateChildNativeWidgetWithParent(NULL); | |
146 } | |
147 | |
148 bool WidgetHasMouseCapture(const Widget* widget) { | |
149 return static_cast<const internal::NativeWidgetPrivate*>(widget-> | |
150 native_widget())->HasMouseCapture(); | |
151 } | |
152 | |
153 //////////////////////////////////////////////////////////////////////////////// | |
154 // Widget::GetTopLevelWidget tests. | |
155 | |
156 TEST_F(WidgetTest, GetTopLevelWidget_Native) { | |
157 // Create a hierarchy of native widgets. | |
158 Widget* toplevel = CreateTopLevelPlatformWidget(); | |
159 #if defined(TOOLKIT_USES_GTK) | |
160 NativeWidgetGtk* native_widget = | |
161 static_cast<NativeWidgetGtk*>(toplevel->native_widget()); | |
162 gfx::NativeView parent = native_widget->window_contents(); | |
163 #else | |
164 gfx::NativeView parent = toplevel->GetNativeView(); | |
165 #endif | |
166 Widget* child = CreateChildPlatformWidget(parent); | |
167 | |
168 EXPECT_EQ(toplevel, toplevel->GetTopLevelWidget()); | |
169 EXPECT_EQ(toplevel, child->GetTopLevelWidget()); | |
170 | |
171 toplevel->CloseNow(); | |
172 // |child| should be automatically destroyed with |toplevel|. | |
173 } | |
174 | |
175 TEST_F(WidgetTest, GetTopLevelWidget_Synthetic) { | |
176 // Create a hierarchy consisting of a top level platform native widget and a | |
177 // child NativeWidget. | |
178 Widget* toplevel = CreateTopLevelPlatformWidget(); | |
179 Widget* child = CreateTopLevelNativeWidget(); | |
180 | |
181 EXPECT_EQ(toplevel, toplevel->GetTopLevelWidget()); | |
182 EXPECT_EQ(child, child->GetTopLevelWidget()); | |
183 | |
184 toplevel->CloseNow(); | |
185 // |child| should be automatically destroyed with |toplevel|. | |
186 } | |
187 | |
188 // Creates a hierarchy consisting of a desktop platform native widget, a | |
189 // toplevel NativeWidget, and a child of that toplevel, another NativeWidget. | |
190 TEST_F(WidgetTest, GetTopLevelWidget_SyntheticDesktop) { | |
191 // Create a hierarchy consisting of a desktop platform native widget, | |
192 // a toplevel NativeWidget and a chlid NativeWidget. | |
193 Widget* desktop = CreateTopLevelPlatformWidget(); | |
194 Widget* toplevel = CreateTopLevelNativeWidget(); // Will be parented | |
195 // automatically to | |
196 // |toplevel|. | |
197 | |
198 Widget* child = CreateChildNativeWidgetWithParent(toplevel); | |
199 | |
200 EXPECT_EQ(desktop, desktop->GetTopLevelWidget()); | |
201 EXPECT_EQ(toplevel, toplevel->GetTopLevelWidget()); | |
202 EXPECT_EQ(toplevel, child->GetTopLevelWidget()); | |
203 | |
204 desktop->CloseNow(); | |
205 // |toplevel|, |child| should be automatically destroyed with |toplevel|. | |
206 } | |
207 | |
208 // Tests some grab/ungrab events. | |
209 TEST_F(WidgetTest, DISABLED_GrabUngrab) { | |
210 Widget* toplevel = CreateTopLevelPlatformWidget(); | |
211 Widget* child1 = CreateChildNativeWidgetWithParent(toplevel); | |
212 Widget* child2 = CreateChildNativeWidgetWithParent(toplevel); | |
213 | |
214 toplevel->SetBounds(gfx::Rect(0, 0, 500, 500)); | |
215 | |
216 child1->SetBounds(gfx::Rect(10, 10, 300, 300)); | |
217 View* view = new MouseView(); | |
218 view->SetBounds(0, 0, 300, 300); | |
219 child1->GetRootView()->AddChildView(view); | |
220 | |
221 child2->SetBounds(gfx::Rect(200, 10, 200, 200)); | |
222 view = new MouseView(); | |
223 view->SetBounds(0, 0, 200, 200); | |
224 child2->GetRootView()->AddChildView(view); | |
225 | |
226 toplevel->Show(); | |
227 RunPendingMessages(); | |
228 | |
229 // Click on child1 | |
230 MouseEvent pressed(ui::ET_MOUSE_PRESSED, 45, 45, ui::EF_LEFT_BUTTON_DOWN); | |
231 toplevel->OnMouseEvent(pressed); | |
232 | |
233 EXPECT_TRUE(WidgetHasMouseCapture(toplevel)); | |
234 EXPECT_TRUE(WidgetHasMouseCapture(child1)); | |
235 EXPECT_FALSE(WidgetHasMouseCapture(child2)); | |
236 | |
237 MouseEvent released(ui::ET_MOUSE_RELEASED, 45, 45, ui::EF_LEFT_BUTTON_DOWN); | |
238 toplevel->OnMouseEvent(released); | |
239 | |
240 EXPECT_FALSE(WidgetHasMouseCapture(toplevel)); | |
241 EXPECT_FALSE(WidgetHasMouseCapture(child1)); | |
242 EXPECT_FALSE(WidgetHasMouseCapture(child2)); | |
243 | |
244 RunPendingMessages(); | |
245 | |
246 // Click on child2 | |
247 MouseEvent pressed2(ui::ET_MOUSE_PRESSED, 315, 45, ui::EF_LEFT_BUTTON_DOWN); | |
248 EXPECT_TRUE(toplevel->OnMouseEvent(pressed2)); | |
249 EXPECT_TRUE(WidgetHasMouseCapture(toplevel)); | |
250 EXPECT_TRUE(WidgetHasMouseCapture(child2)); | |
251 EXPECT_FALSE(WidgetHasMouseCapture(child1)); | |
252 | |
253 MouseEvent released2(ui::ET_MOUSE_RELEASED, 315, 45, ui::EF_LEFT_BUTTON_DOWN); | |
254 toplevel->OnMouseEvent(released2); | |
255 EXPECT_FALSE(WidgetHasMouseCapture(toplevel)); | |
256 EXPECT_FALSE(WidgetHasMouseCapture(child1)); | |
257 EXPECT_FALSE(WidgetHasMouseCapture(child2)); | |
258 | |
259 toplevel->CloseNow(); | |
260 } | |
261 | |
262 // Test if a focus manager and an inputmethod work without CHECK failure | |
263 // when window activation changes. | |
264 TEST_F(WidgetTest, ChangeActivation) { | |
265 Widget* top1 = CreateTopLevelPlatformWidget(); | |
266 // CreateInputMethod before activated | |
267 top1->GetInputMethod(); | |
268 top1->Show(); | |
269 RunPendingMessages(); | |
270 | |
271 Widget* top2 = CreateTopLevelPlatformWidget(); | |
272 top2->Show(); | |
273 RunPendingMessages(); | |
274 | |
275 top1->Activate(); | |
276 RunPendingMessages(); | |
277 | |
278 // Create InputMethod after deactivated. | |
279 top2->GetInputMethod(); | |
280 top2->Activate(); | |
281 RunPendingMessages(); | |
282 | |
283 top1->Activate(); | |
284 RunPendingMessages(); | |
285 | |
286 top1->CloseNow(); | |
287 top2->CloseNow(); | |
288 } | |
289 | |
290 // Tests visibility of child widgets. | |
291 TEST_F(WidgetTest, Visibility) { | |
292 Widget* toplevel = CreateTopLevelPlatformWidget(); | |
293 #if defined(TOOLKIT_USES_GTK) | |
294 NativeWidgetGtk* native_widget = | |
295 static_cast<NativeWidgetGtk*>(toplevel->native_widget()); | |
296 gfx::NativeView parent = native_widget->window_contents(); | |
297 #else | |
298 gfx::NativeView parent = toplevel->GetNativeView(); | |
299 #endif | |
300 Widget* child = CreateChildPlatformWidget(parent); | |
301 | |
302 EXPECT_FALSE(toplevel->IsVisible()); | |
303 EXPECT_FALSE(child->IsVisible()); | |
304 | |
305 child->Show(); | |
306 | |
307 EXPECT_FALSE(toplevel->IsVisible()); | |
308 EXPECT_FALSE(child->IsVisible()); | |
309 | |
310 toplevel->Show(); | |
311 | |
312 EXPECT_TRUE(toplevel->IsVisible()); | |
313 EXPECT_TRUE(child->IsVisible()); | |
314 | |
315 toplevel->CloseNow(); | |
316 // |child| should be automatically destroyed with |toplevel|. | |
317 } | |
318 | |
319 #if defined(OS_WIN) && !defined(USE_AURA) | |
320 // On Windows, it is possible to have child window that are TYPE_POPUP. Unlike | |
321 // regular child windows, these should be created as hidden and must be shown | |
322 // explicitly. | |
323 TEST_F(WidgetTest, Visibility_ChildPopup) { | |
324 Widget* toplevel = CreateTopLevelPlatformWidget(); | |
325 Widget* child_popup = CreateChildPopupPlatformWidget( | |
326 toplevel->GetNativeView()); | |
327 | |
328 EXPECT_FALSE(toplevel->IsVisible()); | |
329 EXPECT_FALSE(child_popup->IsVisible()); | |
330 | |
331 toplevel->Show(); | |
332 | |
333 EXPECT_TRUE(toplevel->IsVisible()); | |
334 EXPECT_FALSE(child_popup->IsVisible()); | |
335 | |
336 child_popup->Show(); | |
337 | |
338 EXPECT_TRUE(child_popup->IsVisible()); | |
339 | |
340 toplevel->CloseNow(); | |
341 // |child_popup| should be automatically destroyed with |toplevel|. | |
342 } | |
343 #endif | |
344 | |
345 // Tests visibility of synthetic child widgets. | |
346 TEST_F(WidgetTest, Visibility_Synthetic) { | |
347 // Create a hierarchy consisting of a desktop platform native widget, | |
348 // a toplevel NativeWidget and a chlid NativeWidget. | |
349 Widget* desktop = CreateTopLevelPlatformWidget(); | |
350 desktop->Show(); | |
351 | |
352 Widget* toplevel = CreateTopLevelNativeWidget(); // Will be parented | |
353 // automatically to | |
354 // |toplevel|. | |
355 | |
356 Widget* child = CreateChildNativeWidgetWithParent(toplevel); | |
357 | |
358 EXPECT_FALSE(toplevel->IsVisible()); | |
359 EXPECT_FALSE(child->IsVisible()); | |
360 | |
361 child->Show(); | |
362 | |
363 EXPECT_FALSE(toplevel->IsVisible()); | |
364 EXPECT_FALSE(child->IsVisible()); | |
365 | |
366 toplevel->Show(); | |
367 | |
368 EXPECT_TRUE(toplevel->IsVisible()); | |
369 EXPECT_TRUE(child->IsVisible()); | |
370 | |
371 desktop->CloseNow(); | |
372 } | |
373 | |
374 //////////////////////////////////////////////////////////////////////////////// | |
375 // Widget ownership tests. | |
376 // | |
377 // Tests various permutations of Widget ownership specified in the | |
378 // InitParams::Ownership param. | |
379 | |
380 // A WidgetTest that supplies a toplevel widget for NativeWidget to parent to. | |
381 class WidgetOwnershipTest : public WidgetTest { | |
382 public: | |
383 WidgetOwnershipTest() {} | |
384 virtual ~WidgetOwnershipTest() {} | |
385 | |
386 virtual void SetUp() { | |
387 WidgetTest::SetUp(); | |
388 desktop_widget_ = CreateTopLevelPlatformWidget(); | |
389 } | |
390 | |
391 virtual void TearDown() { | |
392 desktop_widget_->CloseNow(); | |
393 WidgetTest::TearDown(); | |
394 } | |
395 | |
396 private: | |
397 Widget* desktop_widget_; | |
398 | |
399 DISALLOW_COPY_AND_ASSIGN(WidgetOwnershipTest); | |
400 }; | |
401 | |
402 // A bag of state to monitor destructions. | |
403 struct OwnershipTestState { | |
404 OwnershipTestState() : widget_deleted(false), native_widget_deleted(false) {} | |
405 | |
406 bool widget_deleted; | |
407 bool native_widget_deleted; | |
408 }; | |
409 | |
410 // A platform NativeWidget subclass that updates a bag of state when it is | |
411 // destroyed. | |
412 class OwnershipTestNativeWidget : public NativeWidgetPlatform { | |
413 public: | |
414 OwnershipTestNativeWidget(internal::NativeWidgetDelegate* delegate, | |
415 OwnershipTestState* state) | |
416 : NativeWidgetPlatform(delegate), | |
417 state_(state) { | |
418 } | |
419 virtual ~OwnershipTestNativeWidget() { | |
420 state_->native_widget_deleted = true; | |
421 } | |
422 | |
423 private: | |
424 OwnershipTestState* state_; | |
425 | |
426 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidget); | |
427 }; | |
428 | |
429 // A views NativeWidget subclass that updates a bag of state when it is | |
430 // destroyed. | |
431 class OwnershipTestNativeWidgetPlatform : public NativeWidgetPlatformForTest { | |
432 public: | |
433 OwnershipTestNativeWidgetPlatform(internal::NativeWidgetDelegate* delegate, | |
434 OwnershipTestState* state) | |
435 : NativeWidgetPlatformForTest(delegate), | |
436 state_(state) { | |
437 } | |
438 virtual ~OwnershipTestNativeWidgetPlatform() { | |
439 state_->native_widget_deleted = true; | |
440 } | |
441 | |
442 private: | |
443 OwnershipTestState* state_; | |
444 | |
445 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetPlatform); | |
446 }; | |
447 | |
448 // A Widget subclass that updates a bag of state when it is destroyed. | |
449 class OwnershipTestWidget : public Widget { | |
450 public: | |
451 OwnershipTestWidget(OwnershipTestState* state) : state_(state) {} | |
452 virtual ~OwnershipTestWidget() { | |
453 state_->widget_deleted = true; | |
454 } | |
455 | |
456 private: | |
457 OwnershipTestState* state_; | |
458 | |
459 DISALLOW_COPY_AND_ASSIGN(OwnershipTestWidget); | |
460 }; | |
461 | |
462 // Widget owns its NativeWidget, part 1: NativeWidget is a platform-native | |
463 // widget. | |
464 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsPlatformNativeWidget) { | |
465 OwnershipTestState state; | |
466 | |
467 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state)); | |
468 Widget::InitParams params(Widget::InitParams::TYPE_POPUP); | |
469 params.native_widget = | |
470 new OwnershipTestNativeWidgetPlatform(widget.get(), &state); | |
471 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | |
472 widget->Init(params); | |
473 | |
474 // Now delete the Widget, which should delete the NativeWidget. | |
475 widget.reset(); | |
476 | |
477 EXPECT_TRUE(state.widget_deleted); | |
478 EXPECT_TRUE(state.native_widget_deleted); | |
479 | |
480 // TODO(beng): write test for this ownership scenario and the NativeWidget | |
481 // being deleted out from under the Widget. | |
482 } | |
483 | |
484 // Widget owns its NativeWidget, part 2: NativeWidget is a NativeWidget. | |
485 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsViewsNativeWidget) { | |
486 OwnershipTestState state; | |
487 | |
488 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state)); | |
489 Widget::InitParams params(Widget::InitParams::TYPE_POPUP); | |
490 params.native_widget = | |
491 new OwnershipTestNativeWidgetPlatform(widget.get(), &state); | |
492 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | |
493 widget->Init(params); | |
494 | |
495 // Now delete the Widget, which should delete the NativeWidget. | |
496 widget.reset(); | |
497 | |
498 EXPECT_TRUE(state.widget_deleted); | |
499 EXPECT_TRUE(state.native_widget_deleted); | |
500 | |
501 // TODO(beng): write test for this ownership scenario and the NativeWidget | |
502 // being deleted out from under the Widget. | |
503 } | |
504 | |
505 // Widget owns its NativeWidget, part 3: NativeWidget is a NativeWidget, | |
506 // destroy the parent view. | |
507 TEST_F(WidgetOwnershipTest, | |
508 Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView) { | |
509 OwnershipTestState state; | |
510 | |
511 Widget* toplevel = CreateTopLevelPlatformWidget(); | |
512 | |
513 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state)); | |
514 Widget::InitParams params(Widget::InitParams::TYPE_POPUP); | |
515 params.native_widget = | |
516 new OwnershipTestNativeWidgetPlatform(widget.get(), &state); | |
517 params.parent_widget = toplevel; | |
518 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | |
519 widget->Init(params); | |
520 | |
521 // Now close the toplevel, which deletes the view hierarchy. | |
522 toplevel->CloseNow(); | |
523 | |
524 RunPendingMessages(); | |
525 | |
526 // This shouldn't delete the widget because it shouldn't be deleted | |
527 // from the native side. | |
528 EXPECT_FALSE(state.widget_deleted); | |
529 EXPECT_FALSE(state.native_widget_deleted); | |
530 | |
531 // Now delete it explicitly. | |
532 widget.reset(); | |
533 | |
534 EXPECT_TRUE(state.widget_deleted); | |
535 EXPECT_TRUE(state.native_widget_deleted); | |
536 } | |
537 | |
538 // NativeWidget owns its Widget, part 1: NativeWidget is a platform-native | |
539 // widget. | |
540 TEST_F(WidgetOwnershipTest, Ownership_PlatformNativeWidgetOwnsWidget) { | |
541 OwnershipTestState state; | |
542 | |
543 Widget* widget = new OwnershipTestWidget(&state); | |
544 Widget::InitParams params(Widget::InitParams::TYPE_POPUP); | |
545 params.native_widget = | |
546 new OwnershipTestNativeWidgetPlatform(widget, &state); | |
547 widget->Init(params); | |
548 | |
549 // Now destroy the native widget. | |
550 widget->CloseNow(); | |
551 | |
552 EXPECT_TRUE(state.widget_deleted); | |
553 EXPECT_TRUE(state.native_widget_deleted); | |
554 } | |
555 | |
556 // NativeWidget owns its Widget, part 2: NativeWidget is a NativeWidget. | |
557 #if defined(OS_CHROMEOS) && defined(TOOLKIT_USES_GTK) | |
558 // Temporarily disable the test (http://crbug.com/104945). | |
559 TEST_F(WidgetOwnershipTest, DISABLED_Ownership_ViewsNativeWidgetOwnsWidget) { | |
560 #else | |
561 TEST_F(WidgetOwnershipTest, Ownership_ViewsNativeWidgetOwnsWidget) { | |
562 #endif | |
563 OwnershipTestState state; | |
564 | |
565 Widget* toplevel = CreateTopLevelPlatformWidget(); | |
566 | |
567 Widget* widget = new OwnershipTestWidget(&state); | |
568 Widget::InitParams params(Widget::InitParams::TYPE_POPUP); | |
569 params.native_widget = | |
570 new OwnershipTestNativeWidgetPlatform(widget, &state); | |
571 params.parent_widget = toplevel; | |
572 widget->Init(params); | |
573 | |
574 // Now destroy the native widget. This is achieved by closing the toplevel. | |
575 toplevel->CloseNow(); | |
576 | |
577 // The NativeWidget won't be deleted until after a return to the message loop | |
578 // so we have to run pending messages before testing the destruction status. | |
579 RunPendingMessages(); | |
580 | |
581 EXPECT_TRUE(state.widget_deleted); | |
582 EXPECT_TRUE(state.native_widget_deleted); | |
583 } | |
584 | |
585 // NativeWidget owns its Widget, part 3: NativeWidget is a platform-native | |
586 // widget, destroyed out from under it by the OS. | |
587 TEST_F(WidgetOwnershipTest, | |
588 Ownership_PlatformNativeWidgetOwnsWidget_NativeDestroy) { | |
589 OwnershipTestState state; | |
590 | |
591 Widget* widget = new OwnershipTestWidget(&state); | |
592 Widget::InitParams params(Widget::InitParams::TYPE_POPUP); | |
593 params.native_widget = | |
594 new OwnershipTestNativeWidgetPlatform(widget, &state); | |
595 widget->Init(params); | |
596 | |
597 // Now simulate a destroy of the platform native widget from the OS: | |
598 #if defined(USE_AURA) | |
599 delete widget->GetNativeView(); | |
600 #elif defined(OS_WIN) | |
601 DestroyWindow(widget->GetNativeView()); | |
602 #elif defined(TOOLKIT_USES_GTK) | |
603 gtk_widget_destroy(widget->GetNativeView()); | |
604 #endif | |
605 | |
606 EXPECT_TRUE(state.widget_deleted); | |
607 EXPECT_TRUE(state.native_widget_deleted); | |
608 } | |
609 | |
610 // NativeWidget owns its Widget, part 4: NativeWidget is a NativeWidget, | |
611 // destroyed by the view hierarchy that contains it. | |
612 #if defined(OS_CHROMEOS) && defined(TOOLKIT_USES_GTK) | |
613 // Temporarily disable the test (http://crbug.com/104945). | |
614 TEST_F(WidgetOwnershipTest, | |
615 DISABLED_Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy) { | |
616 #else | |
617 TEST_F(WidgetOwnershipTest, | |
618 Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy) { | |
619 #endif | |
620 OwnershipTestState state; | |
621 | |
622 Widget* toplevel = CreateTopLevelPlatformWidget(); | |
623 | |
624 Widget* widget = new OwnershipTestWidget(&state); | |
625 Widget::InitParams params(Widget::InitParams::TYPE_POPUP); | |
626 params.native_widget = | |
627 new OwnershipTestNativeWidgetPlatform(widget, &state); | |
628 params.parent_widget = toplevel; | |
629 widget->Init(params); | |
630 | |
631 // Destroy the widget (achieved by closing the toplevel). | |
632 toplevel->CloseNow(); | |
633 | |
634 // The NativeWidget won't be deleted until after a return to the message loop | |
635 // so we have to run pending messages before testing the destruction status. | |
636 RunPendingMessages(); | |
637 | |
638 EXPECT_TRUE(state.widget_deleted); | |
639 EXPECT_TRUE(state.native_widget_deleted); | |
640 } | |
641 | |
642 // NativeWidget owns its Widget, part 5: NativeWidget is a NativeWidget, | |
643 // we close it directly. | |
644 TEST_F(WidgetOwnershipTest, | |
645 Ownership_ViewsNativeWidgetOwnsWidget_Close) { | |
646 OwnershipTestState state; | |
647 | |
648 Widget* toplevel = CreateTopLevelPlatformWidget(); | |
649 | |
650 Widget* widget = new OwnershipTestWidget(&state); | |
651 Widget::InitParams params(Widget::InitParams::TYPE_POPUP); | |
652 params.native_widget = | |
653 new OwnershipTestNativeWidgetPlatform(widget, &state); | |
654 params.parent_widget = toplevel; | |
655 widget->Init(params); | |
656 | |
657 // Destroy the widget. | |
658 widget->Close(); | |
659 toplevel->CloseNow(); | |
660 | |
661 // The NativeWidget won't be deleted until after a return to the message loop | |
662 // so we have to run pending messages before testing the destruction status. | |
663 RunPendingMessages(); | |
664 | |
665 EXPECT_TRUE(state.widget_deleted); | |
666 EXPECT_TRUE(state.native_widget_deleted); | |
667 } | |
668 | |
669 //////////////////////////////////////////////////////////////////////////////// | |
670 // Widget observer tests. | |
671 // | |
672 | |
673 class WidgetObserverTest : public WidgetTest, | |
674 Widget::Observer { | |
675 public: | |
676 WidgetObserverTest() | |
677 : active_(NULL), | |
678 widget_closed_(NULL), | |
679 widget_activated_(NULL), | |
680 widget_shown_(NULL), | |
681 widget_hidden_(NULL) { | |
682 } | |
683 | |
684 virtual ~WidgetObserverTest() {} | |
685 | |
686 virtual void OnWidgetClosing(Widget* widget) OVERRIDE { | |
687 if (active_ == widget) | |
688 active_ = NULL; | |
689 widget_closed_ = widget; | |
690 } | |
691 | |
692 virtual void OnWidgetActivationChanged(Widget* widget, | |
693 bool active) OVERRIDE { | |
694 if (active) { | |
695 if (widget_activated_) | |
696 widget_activated_->Deactivate(); | |
697 widget_activated_ = widget; | |
698 active_ = widget; | |
699 } else { | |
700 if (widget_activated_ == widget) | |
701 widget_activated_ = NULL; | |
702 widget_deactivated_ = widget; | |
703 } | |
704 } | |
705 | |
706 virtual void OnWidgetVisibilityChanged(Widget* widget, | |
707 bool visible) OVERRIDE { | |
708 if (visible) | |
709 widget_shown_ = widget; | |
710 else | |
711 widget_hidden_ = widget; | |
712 } | |
713 | |
714 void reset() { | |
715 active_ = NULL; | |
716 widget_closed_ = NULL; | |
717 widget_activated_ = NULL; | |
718 widget_deactivated_ = NULL; | |
719 widget_shown_ = NULL; | |
720 widget_hidden_ = NULL; | |
721 } | |
722 | |
723 Widget* NewWidget() { | |
724 Widget* widget = CreateTopLevelNativeWidget(); | |
725 widget->AddObserver(this); | |
726 return widget; | |
727 } | |
728 | |
729 const Widget* active() const { return active_; } | |
730 const Widget* widget_closed() const { return widget_closed_; } | |
731 const Widget* widget_activated() const { return widget_activated_; } | |
732 const Widget* widget_deactivated() const { return widget_deactivated_; } | |
733 const Widget* widget_shown() const { return widget_shown_; } | |
734 const Widget* widget_hidden() const { return widget_hidden_; } | |
735 | |
736 private: | |
737 | |
738 Widget* active_; | |
739 | |
740 Widget* widget_closed_; | |
741 Widget* widget_activated_; | |
742 Widget* widget_deactivated_; | |
743 Widget* widget_shown_; | |
744 Widget* widget_hidden_; | |
745 }; | |
746 | |
747 TEST_F(WidgetObserverTest, DISABLED_ActivationChange) { | |
748 Widget* toplevel = CreateTopLevelPlatformWidget(); | |
749 | |
750 Widget* toplevel1 = NewWidget(); | |
751 Widget* toplevel2 = NewWidget(); | |
752 | |
753 toplevel1->Show(); | |
754 toplevel2->Show(); | |
755 | |
756 reset(); | |
757 | |
758 toplevel1->Activate(); | |
759 | |
760 RunPendingMessages(); | |
761 EXPECT_EQ(toplevel1, widget_activated()); | |
762 | |
763 toplevel2->Activate(); | |
764 RunPendingMessages(); | |
765 EXPECT_EQ(toplevel1, widget_deactivated()); | |
766 EXPECT_EQ(toplevel2, widget_activated()); | |
767 EXPECT_EQ(toplevel2, active()); | |
768 | |
769 toplevel->CloseNow(); | |
770 } | |
771 | |
772 TEST_F(WidgetObserverTest, DISABLED_VisibilityChange) { | |
773 Widget* toplevel = CreateTopLevelPlatformWidget(); | |
774 | |
775 Widget* child1 = NewWidget(); | |
776 Widget* child2 = NewWidget(); | |
777 | |
778 toplevel->Show(); | |
779 child1->Show(); | |
780 child2->Show(); | |
781 | |
782 reset(); | |
783 | |
784 child1->Hide(); | |
785 EXPECT_EQ(child1, widget_hidden()); | |
786 | |
787 child2->Hide(); | |
788 EXPECT_EQ(child2, widget_hidden()); | |
789 | |
790 child1->Show(); | |
791 EXPECT_EQ(child1, widget_shown()); | |
792 | |
793 child2->Show(); | |
794 EXPECT_EQ(child2, widget_shown()); | |
795 | |
796 toplevel->CloseNow(); | |
797 } | |
798 | |
799 #if !defined(USE_AURA) && defined(OS_WIN) | |
800 // Aura needs shell to maximize/fullscreen window. | |
801 // NativeWidgetGtk doesn't implement GetRestoredBounds. | |
802 TEST_F(WidgetTest, GetRestoredBounds) { | |
803 Widget* toplevel = CreateTopLevelPlatformWidget(); | |
804 EXPECT_EQ(toplevel->GetWindowScreenBounds().ToString(), | |
805 toplevel->GetRestoredBounds().ToString()); | |
806 toplevel->Show(); | |
807 toplevel->Maximize(); | |
808 RunPendingMessages(); | |
809 EXPECT_NE(toplevel->GetWindowScreenBounds().ToString(), | |
810 toplevel->GetRestoredBounds().ToString()); | |
811 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0); | |
812 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0); | |
813 | |
814 toplevel->Restore(); | |
815 RunPendingMessages(); | |
816 EXPECT_EQ(toplevel->GetWindowScreenBounds().ToString(), | |
817 toplevel->GetRestoredBounds().ToString()); | |
818 | |
819 toplevel->SetFullscreen(true); | |
820 RunPendingMessages(); | |
821 EXPECT_NE(toplevel->GetWindowScreenBounds().ToString(), | |
822 toplevel->GetRestoredBounds().ToString()); | |
823 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0); | |
824 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0); | |
825 } | |
826 #endif | |
827 | |
828 } // namespace | |
829 } // namespace views | |
OLD | NEW |