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