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/compositor/layer_animation_observer.h" 17 #include "ui/compositor/scoped_animation_duration_scale_mode.h" 18 #include "ui/compositor/scoped_layer_animation_settings.h" 19 #include "ui/events/event_processor.h" 20 #include "ui/events/event_utils.h" 21 #include "ui/events/test/event_generator.h" 22 #include "ui/gfx/native_widget_types.h" 23 #include "ui/gfx/point.h" 24 #include "ui/views/bubble/bubble_delegate.h" 25 #include "ui/views/controls/textfield/textfield.h" 26 #include "ui/views/test/test_views_delegate.h" 27 #include "ui/views/test/widget_test.h" 28 #include "ui/views/views_delegate.h" 29 #include "ui/views/widget/native_widget_delegate.h" 30 #include "ui/views/widget/root_view.h" 31 #include "ui/views/widget/widget_deletion_observer.h" 32 #include "ui/views/window/dialog_delegate.h" 33 #include "ui/views/window/native_frame_view.h" 34 35 #if defined(OS_WIN) 36 #include "ui/views/win/hwnd_util.h" 37 #endif 38 39 namespace views { 40 namespace test { 41 42 namespace { 43 44 // TODO(tdanderson): This utility function is used in different unittest 45 // files. Move to a common location to avoid 46 // repeated code. 47 gfx::Point ConvertPointFromWidgetToView(View* view, const gfx::Point& p) { 48 gfx::Point tmp(p); 49 View::ConvertPointToTarget(view->GetWidget()->GetRootView(), view, &tmp); 50 return tmp; 51 } 52 53 } // namespace 54 55 // A view that keeps track of the events it receives, optionally consuming them. 56 class EventCountView : public View { 57 public: 58 // Whether to call SetHandled() on events as they are received. For some event 59 // types, this will allow EventCountView to receives future events in the 60 // event sequence, such as a drag. 61 enum HandleMode { 62 PROPAGATE_EVENTS, 63 CONSUME_EVENTS 64 }; 65 66 EventCountView() 67 : last_flags_(0), 68 handle_mode_(PROPAGATE_EVENTS) {} 69 70 virtual ~EventCountView() {} 71 72 int GetEventCount(ui::EventType type) { 73 return event_count_[type]; 74 } 75 76 void ResetCounts() { 77 event_count_.clear(); 78 } 79 80 int last_flags() const { 81 return last_flags_; 82 } 83 84 void set_handle_mode(HandleMode handle_mode) { 85 handle_mode_ = handle_mode; 86 } 87 88 protected: 89 // Overridden from View: 90 virtual void OnMouseMoved(const ui::MouseEvent& event) OVERRIDE { 91 // MouseMove events are not re-dispatched from the RootView. 92 ++event_count_[ui::ET_MOUSE_MOVED]; 93 last_flags_ = 0; 94 } 95 96 // Overridden from ui::EventHandler: 97 virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE { 98 RecordEvent(event); 99 } 100 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { 101 RecordEvent(event); 102 } 103 virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE { 104 RecordEvent(event); 105 } 106 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { 107 RecordEvent(event); 108 } 109 110 private: 111 void RecordEvent(ui::Event* event) { 112 ++event_count_[event->type()]; 113 last_flags_ = event->flags(); 114 if (handle_mode_ == CONSUME_EVENTS) 115 event->SetHandled(); 116 } 117 118 std::map<ui::EventType, int> event_count_; 119 int last_flags_; 120 HandleMode handle_mode_; 121 122 DISALLOW_COPY_AND_ASSIGN(EventCountView); 123 }; 124 125 // A view that keeps track of the events it receives, and consumes all scroll 126 // gesture events and ui::ET_SCROLL events. 127 class ScrollableEventCountView : public EventCountView { 128 public: 129 ScrollableEventCountView() {} 130 virtual ~ScrollableEventCountView() {} 131 132 private: 133 // Overridden from ui::EventHandler: 134 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { 135 EventCountView::OnGestureEvent(event); 136 switch (event->type()) { 137 case ui::ET_GESTURE_SCROLL_BEGIN: 138 case ui::ET_GESTURE_SCROLL_UPDATE: 139 case ui::ET_GESTURE_SCROLL_END: 140 case ui::ET_SCROLL_FLING_START: 141 event->SetHandled(); 142 break; 143 default: 144 break; 145 } 146 } 147 148 virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE { 149 EventCountView::OnScrollEvent(event); 150 if (event->type() == ui::ET_SCROLL) 151 event->SetHandled(); 152 } 153 154 DISALLOW_COPY_AND_ASSIGN(ScrollableEventCountView); 155 }; 156 157 // A view that implements GetMinimumSize. 158 class MinimumSizeFrameView : public NativeFrameView { 159 public: 160 explicit MinimumSizeFrameView(Widget* frame): NativeFrameView(frame) {} 161 virtual ~MinimumSizeFrameView() {} 162 163 private: 164 // Overridden from View: 165 virtual gfx::Size GetMinimumSize() const OVERRIDE { 166 return gfx::Size(300, 400); 167 } 168 169 DISALLOW_COPY_AND_ASSIGN(MinimumSizeFrameView); 170 }; 171 172 // An event handler that simply keeps a count of the different types of events 173 // it receives. 174 class EventCountHandler : public ui::EventHandler { 175 public: 176 EventCountHandler() {} 177 virtual ~EventCountHandler() {} 178 179 int GetEventCount(ui::EventType type) { 180 return event_count_[type]; 181 } 182 183 void ResetCounts() { 184 event_count_.clear(); 185 } 186 187 protected: 188 // Overridden from ui::EventHandler: 189 virtual void OnEvent(ui::Event* event) OVERRIDE { 190 RecordEvent(*event); 191 ui::EventHandler::OnEvent(event); 192 } 193 194 private: 195 void RecordEvent(const ui::Event& event) { 196 ++event_count_[event.type()]; 197 } 198 199 std::map<ui::EventType, int> event_count_; 200 201 DISALLOW_COPY_AND_ASSIGN(EventCountHandler); 202 }; 203 204 // Class that closes the widget (which ends up deleting it immediately) when the 205 // appropriate event is received. 206 class CloseWidgetView : public View { 207 public: 208 explicit CloseWidgetView(ui::EventType event_type) 209 : event_type_(event_type) { 210 } 211 212 // ui::EventHandler override: 213 virtual void OnEvent(ui::Event* event) OVERRIDE { 214 if (event->type() == event_type_) { 215 // Go through NativeWidgetPrivate to simulate what happens if the OS 216 // deletes the NativeWindow out from under us. 217 GetWidget()->native_widget_private()->CloseNow(); 218 } else { 219 View::OnEvent(event); 220 if (!event->IsTouchEvent()) 221 event->SetHandled(); 222 } 223 } 224 225 private: 226 const ui::EventType event_type_; 227 228 DISALLOW_COPY_AND_ASSIGN(CloseWidgetView); 229 }; 230 231 ui::WindowShowState GetWidgetShowState(const Widget* widget) { 232 // Use IsMaximized/IsMinimized/IsFullScreen instead of GetWindowPlacement 233 // because the former is implemented on all platforms but the latter is not. 234 return widget->IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN : 235 widget->IsMaximized() ? ui::SHOW_STATE_MAXIMIZED : 236 widget->IsMinimized() ? ui::SHOW_STATE_MINIMIZED : 237 widget->IsActive() ? ui::SHOW_STATE_NORMAL : 238 ui::SHOW_STATE_INACTIVE; 239 } 240 241 TEST_F(WidgetTest, WidgetInitParams) { 242 // Widgets are not transparent by default. 243 Widget::InitParams init1; 244 EXPECT_EQ(Widget::InitParams::INFER_OPACITY, init1.opacity); 245 } 246 247 //////////////////////////////////////////////////////////////////////////////// 248 // Widget::GetTopLevelWidget tests. 249 250 TEST_F(WidgetTest, GetTopLevelWidget_Native) { 251 // Create a hierarchy of native widgets. 252 Widget* toplevel = CreateTopLevelPlatformWidget(); 253 gfx::NativeView parent = toplevel->GetNativeView(); 254 Widget* child = CreateChildPlatformWidget(parent); 255 256 EXPECT_EQ(toplevel, toplevel->GetTopLevelWidget()); 257 EXPECT_EQ(toplevel, child->GetTopLevelWidget()); 258 259 toplevel->CloseNow(); 260 // |child| should be automatically destroyed with |toplevel|. 261 } 262 263 // Test if a focus manager and an inputmethod work without CHECK failure 264 // when window activation changes. 265 TEST_F(WidgetTest, ChangeActivation) { 266 Widget* top1 = CreateTopLevelPlatformWidget(); 267 // CreateInputMethod before activated 268 top1->GetInputMethod(); 269 top1->Show(); 270 RunPendingMessages(); 271 272 Widget* top2 = CreateTopLevelPlatformWidget(); 273 top2->Show(); 274 RunPendingMessages(); 275 276 top1->Activate(); 277 RunPendingMessages(); 278 279 // Create InputMethod after deactivated. 280 top2->GetInputMethod(); 281 top2->Activate(); 282 RunPendingMessages(); 283 284 top1->Activate(); 285 RunPendingMessages(); 286 287 top1->CloseNow(); 288 top2->CloseNow(); 289 } 290 291 // Tests visibility of child widgets. 292 TEST_F(WidgetTest, Visibility) { 293 Widget* toplevel = CreateTopLevelPlatformWidget(); 294 gfx::NativeView parent = toplevel->GetNativeView(); 295 Widget* child = CreateChildPlatformWidget(parent); 296 297 EXPECT_FALSE(toplevel->IsVisible()); 298 EXPECT_FALSE(child->IsVisible()); 299 300 child->Show(); 301 302 EXPECT_FALSE(toplevel->IsVisible()); 303 EXPECT_FALSE(child->IsVisible()); 304 305 toplevel->Show(); 306 307 EXPECT_TRUE(toplevel->IsVisible()); 308 EXPECT_TRUE(child->IsVisible()); 309 310 toplevel->CloseNow(); 311 // |child| should be automatically destroyed with |toplevel|. 312 } 313 314 //////////////////////////////////////////////////////////////////////////////// 315 // Widget ownership tests. 316 // 317 // Tests various permutations of Widget ownership specified in the 318 // InitParams::Ownership param. 319 320 // A WidgetTest that supplies a toplevel widget for NativeWidget to parent to. 321 class WidgetOwnershipTest : public WidgetTest { 322 public: 323 WidgetOwnershipTest() {} 324 virtual ~WidgetOwnershipTest() {} 325 326 virtual void SetUp() { 327 WidgetTest::SetUp(); 328 desktop_widget_ = CreateTopLevelPlatformWidget(); 329 } 330 331 virtual void TearDown() { 332 desktop_widget_->CloseNow(); 333 WidgetTest::TearDown(); 334 } 335 336 private: 337 Widget* desktop_widget_; 338 339 DISALLOW_COPY_AND_ASSIGN(WidgetOwnershipTest); 340 }; 341 342 // A bag of state to monitor destructions. 343 struct OwnershipTestState { 344 OwnershipTestState() : widget_deleted(false), native_widget_deleted(false) {} 345 346 bool widget_deleted; 347 bool native_widget_deleted; 348 }; 349 350 // A platform NativeWidget subclass that updates a bag of state when it is 351 // destroyed. 352 class OwnershipTestNativeWidget : public PlatformNativeWidget { 353 public: 354 OwnershipTestNativeWidget(internal::NativeWidgetDelegate* delegate, 355 OwnershipTestState* state) 356 : PlatformNativeWidget(delegate), 357 state_(state) { 358 } 359 virtual ~OwnershipTestNativeWidget() { 360 state_->native_widget_deleted = true; 361 } 362 363 private: 364 OwnershipTestState* state_; 365 366 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidget); 367 }; 368 369 // A views NativeWidget subclass that updates a bag of state when it is 370 // destroyed. 371 class OwnershipTestNativeWidgetAura : public NativeWidgetCapture { 372 public: 373 OwnershipTestNativeWidgetAura(internal::NativeWidgetDelegate* delegate, 374 OwnershipTestState* state) 375 : NativeWidgetCapture(delegate), 376 state_(state) { 377 } 378 virtual ~OwnershipTestNativeWidgetAura() { 379 state_->native_widget_deleted = true; 380 } 381 382 private: 383 OwnershipTestState* state_; 384 385 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetAura); 386 }; 387 388 // A Widget subclass that updates a bag of state when it is destroyed. 389 class OwnershipTestWidget : public Widget { 390 public: 391 explicit OwnershipTestWidget(OwnershipTestState* state) : state_(state) {} 392 virtual ~OwnershipTestWidget() { 393 state_->widget_deleted = true; 394 } 395 396 private: 397 OwnershipTestState* state_; 398 399 DISALLOW_COPY_AND_ASSIGN(OwnershipTestWidget); 400 }; 401 402 // Widget owns its NativeWidget, part 1: NativeWidget is a platform-native 403 // widget. 404 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsPlatformNativeWidget) { 405 OwnershipTestState state; 406 407 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state)); 408 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 409 params.native_widget = 410 new OwnershipTestNativeWidgetAura(widget.get(), &state); 411 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 412 widget->Init(params); 413 414 // Now delete the Widget, which should delete the NativeWidget. 415 widget.reset(); 416 417 EXPECT_TRUE(state.widget_deleted); 418 EXPECT_TRUE(state.native_widget_deleted); 419 420 // TODO(beng): write test for this ownership scenario and the NativeWidget 421 // being deleted out from under the Widget. 422 } 423 424 // Widget owns its NativeWidget, part 2: NativeWidget is a NativeWidget. 425 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsViewsNativeWidget) { 426 OwnershipTestState state; 427 428 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state)); 429 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 430 params.native_widget = 431 new OwnershipTestNativeWidgetAura(widget.get(), &state); 432 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 433 widget->Init(params); 434 435 // Now delete the Widget, which should delete the NativeWidget. 436 widget.reset(); 437 438 EXPECT_TRUE(state.widget_deleted); 439 EXPECT_TRUE(state.native_widget_deleted); 440 441 // TODO(beng): write test for this ownership scenario and the NativeWidget 442 // being deleted out from under the Widget. 443 } 444 445 // Widget owns its NativeWidget, part 3: NativeWidget is a NativeWidget, 446 // destroy the parent view. 447 TEST_F(WidgetOwnershipTest, 448 Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView) { 449 OwnershipTestState state; 450 451 Widget* toplevel = CreateTopLevelPlatformWidget(); 452 453 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state)); 454 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 455 params.native_widget = 456 new OwnershipTestNativeWidgetAura(widget.get(), &state); 457 params.parent = toplevel->GetNativeView(); 458 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 459 widget->Init(params); 460 461 // Now close the toplevel, which deletes the view hierarchy. 462 toplevel->CloseNow(); 463 464 RunPendingMessages(); 465 466 // This shouldn't delete the widget because it shouldn't be deleted 467 // from the native side. 468 EXPECT_FALSE(state.widget_deleted); 469 EXPECT_FALSE(state.native_widget_deleted); 470 471 // Now delete it explicitly. 472 widget.reset(); 473 474 EXPECT_TRUE(state.widget_deleted); 475 EXPECT_TRUE(state.native_widget_deleted); 476 } 477 478 // NativeWidget owns its Widget, part 1: NativeWidget is a platform-native 479 // widget. 480 TEST_F(WidgetOwnershipTest, Ownership_PlatformNativeWidgetOwnsWidget) { 481 OwnershipTestState state; 482 483 Widget* widget = new OwnershipTestWidget(&state); 484 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 485 params.native_widget = 486 new OwnershipTestNativeWidgetAura(widget, &state); 487 widget->Init(params); 488 489 // Now destroy the native widget. 490 widget->CloseNow(); 491 492 EXPECT_TRUE(state.widget_deleted); 493 EXPECT_TRUE(state.native_widget_deleted); 494 } 495 496 // NativeWidget owns its Widget, part 2: NativeWidget is a NativeWidget. 497 TEST_F(WidgetOwnershipTest, Ownership_ViewsNativeWidgetOwnsWidget) { 498 OwnershipTestState state; 499 500 Widget* toplevel = CreateTopLevelPlatformWidget(); 501 502 Widget* widget = new OwnershipTestWidget(&state); 503 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 504 params.native_widget = 505 new OwnershipTestNativeWidgetAura(widget, &state); 506 params.parent = toplevel->GetNativeView(); 507 widget->Init(params); 508 509 // Now destroy the native widget. This is achieved by closing the toplevel. 510 toplevel->CloseNow(); 511 512 // The NativeWidget won't be deleted until after a return to the message loop 513 // so we have to run pending messages before testing the destruction status. 514 RunPendingMessages(); 515 516 EXPECT_TRUE(state.widget_deleted); 517 EXPECT_TRUE(state.native_widget_deleted); 518 } 519 520 // NativeWidget owns its Widget, part 3: NativeWidget is a platform-native 521 // widget, destroyed out from under it by the OS. 522 TEST_F(WidgetOwnershipTest, 523 Ownership_PlatformNativeWidgetOwnsWidget_NativeDestroy) { 524 OwnershipTestState state; 525 526 Widget* widget = new OwnershipTestWidget(&state); 527 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 528 params.native_widget = 529 new OwnershipTestNativeWidgetAura(widget, &state); 530 widget->Init(params); 531 532 // Now simulate a destroy of the platform native widget from the OS: 533 SimulateNativeDestroy(widget); 534 535 EXPECT_TRUE(state.widget_deleted); 536 EXPECT_TRUE(state.native_widget_deleted); 537 } 538 539 // NativeWidget owns its Widget, part 4: NativeWidget is a NativeWidget, 540 // destroyed by the view hierarchy that contains it. 541 TEST_F(WidgetOwnershipTest, 542 Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy) { 543 OwnershipTestState state; 544 545 Widget* toplevel = CreateTopLevelPlatformWidget(); 546 547 Widget* widget = new OwnershipTestWidget(&state); 548 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 549 params.native_widget = 550 new OwnershipTestNativeWidgetAura(widget, &state); 551 params.parent = toplevel->GetNativeView(); 552 widget->Init(params); 553 554 // Destroy the widget (achieved by closing the toplevel). 555 toplevel->CloseNow(); 556 557 // The NativeWidget won't be deleted until after a return to the message loop 558 // so we have to run pending messages before testing the destruction status. 559 RunPendingMessages(); 560 561 EXPECT_TRUE(state.widget_deleted); 562 EXPECT_TRUE(state.native_widget_deleted); 563 } 564 565 // NativeWidget owns its Widget, part 5: NativeWidget is a NativeWidget, 566 // we close it directly. 567 TEST_F(WidgetOwnershipTest, 568 Ownership_ViewsNativeWidgetOwnsWidget_Close) { 569 OwnershipTestState state; 570 571 Widget* toplevel = CreateTopLevelPlatformWidget(); 572 573 Widget* widget = new OwnershipTestWidget(&state); 574 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 575 params.native_widget = 576 new OwnershipTestNativeWidgetAura(widget, &state); 577 params.parent = toplevel->GetNativeView(); 578 widget->Init(params); 579 580 // Destroy the widget. 581 widget->Close(); 582 toplevel->CloseNow(); 583 584 // The NativeWidget won't be deleted until after a return to the message loop 585 // so we have to run pending messages before testing the destruction status. 586 RunPendingMessages(); 587 588 EXPECT_TRUE(state.widget_deleted); 589 EXPECT_TRUE(state.native_widget_deleted); 590 } 591 592 // Widget owns its NativeWidget and has a WidgetDelegateView as its contents. 593 TEST_F(WidgetOwnershipTest, 594 Ownership_WidgetOwnsNativeWidgetWithWithWidgetDelegateView) { 595 OwnershipTestState state; 596 597 WidgetDelegateView* delegate_view = new WidgetDelegateView; 598 599 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state)); 600 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 601 params.native_widget = 602 new OwnershipTestNativeWidgetAura(widget.get(), &state); 603 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 604 params.delegate = delegate_view; 605 widget->Init(params); 606 widget->SetContentsView(delegate_view); 607 608 // Now delete the Widget. There should be no crash or use-after-free. 609 widget.reset(); 610 611 EXPECT_TRUE(state.widget_deleted); 612 EXPECT_TRUE(state.native_widget_deleted); 613 } 614 615 //////////////////////////////////////////////////////////////////////////////// 616 // Test to verify using various Widget methods doesn't crash when the underlying 617 // NativeView is destroyed. 618 // 619 class WidgetWithDestroyedNativeViewTest : public ViewsTestBase { 620 public: 621 WidgetWithDestroyedNativeViewTest() {} 622 virtual ~WidgetWithDestroyedNativeViewTest() {} 623 624 void InvokeWidgetMethods(Widget* widget) { 625 widget->GetNativeView(); 626 widget->GetNativeWindow(); 627 ui::Accelerator accelerator; 628 widget->GetAccelerator(0, &accelerator); 629 widget->GetTopLevelWidget(); 630 widget->GetWindowBoundsInScreen(); 631 widget->GetClientAreaBoundsInScreen(); 632 widget->SetBounds(gfx::Rect(0, 0, 100, 80)); 633 widget->SetSize(gfx::Size(10, 11)); 634 widget->SetBoundsConstrained(gfx::Rect(0, 0, 120, 140)); 635 widget->SetVisibilityChangedAnimationsEnabled(false); 636 widget->StackAtTop(); 637 widget->IsClosed(); 638 widget->Close(); 639 widget->Hide(); 640 widget->Activate(); 641 widget->Deactivate(); 642 widget->IsActive(); 643 widget->DisableInactiveRendering(); 644 widget->SetAlwaysOnTop(true); 645 widget->IsAlwaysOnTop(); 646 widget->Maximize(); 647 widget->Minimize(); 648 widget->Restore(); 649 widget->IsMaximized(); 650 widget->IsFullscreen(); 651 widget->SetOpacity(0); 652 widget->SetUseDragFrame(true); 653 widget->FlashFrame(true); 654 widget->IsVisible(); 655 widget->GetThemeProvider(); 656 widget->GetNativeTheme(); 657 widget->GetFocusManager(); 658 widget->GetInputMethod(); 659 widget->SchedulePaintInRect(gfx::Rect(0, 0, 1, 2)); 660 widget->IsMouseEventsEnabled(); 661 widget->SetNativeWindowProperty("xx", widget); 662 widget->GetNativeWindowProperty("xx"); 663 widget->GetFocusTraversable(); 664 widget->GetLayer(); 665 widget->ReorderNativeViews(); 666 widget->SetCapture(widget->GetRootView()); 667 widget->ReleaseCapture(); 668 widget->HasCapture(); 669 widget->GetWorkAreaBoundsInScreen(); 670 widget->IsTranslucentWindowOpacitySupported(); 671 } 672 673 private: 674 DISALLOW_COPY_AND_ASSIGN(WidgetWithDestroyedNativeViewTest); 675 }; 676 677 TEST_F(WidgetWithDestroyedNativeViewTest, Test) { 678 { 679 Widget widget; 680 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 681 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 682 widget.Init(params); 683 widget.Show(); 684 685 widget.native_widget_private()->CloseNow(); 686 InvokeWidgetMethods(&widget); 687 } 688 #if !defined(OS_CHROMEOS) 689 { 690 Widget widget; 691 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 692 params.native_widget = new PlatformDesktopNativeWidget(&widget); 693 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 694 widget.Init(params); 695 widget.Show(); 696 697 widget.native_widget_private()->CloseNow(); 698 InvokeWidgetMethods(&widget); 699 } 700 #endif 701 } 702 703 //////////////////////////////////////////////////////////////////////////////// 704 // Widget observer tests. 705 // 706 707 class WidgetObserverTest : public WidgetTest, public WidgetObserver { 708 public: 709 WidgetObserverTest() 710 : active_(NULL), 711 widget_closed_(NULL), 712 widget_activated_(NULL), 713 widget_shown_(NULL), 714 widget_hidden_(NULL), 715 widget_bounds_changed_(NULL) { 716 } 717 718 virtual ~WidgetObserverTest() {} 719 720 // Overridden from WidgetObserver: 721 virtual void OnWidgetDestroying(Widget* widget) OVERRIDE { 722 if (active_ == widget) 723 active_ = NULL; 724 widget_closed_ = widget; 725 } 726 727 virtual void OnWidgetActivationChanged(Widget* widget, 728 bool active) OVERRIDE { 729 if (active) { 730 if (widget_activated_) 731 widget_activated_->Deactivate(); 732 widget_activated_ = widget; 733 active_ = widget; 734 } else { 735 if (widget_activated_ == widget) 736 widget_activated_ = NULL; 737 widget_deactivated_ = widget; 738 } 739 } 740 741 virtual void OnWidgetVisibilityChanged(Widget* widget, 742 bool visible) OVERRIDE { 743 if (visible) 744 widget_shown_ = widget; 745 else 746 widget_hidden_ = widget; 747 } 748 749 virtual void OnWidgetBoundsChanged(Widget* widget, 750 const gfx::Rect& new_bounds) OVERRIDE { 751 widget_bounds_changed_ = widget; 752 } 753 754 void reset() { 755 active_ = NULL; 756 widget_closed_ = NULL; 757 widget_activated_ = NULL; 758 widget_deactivated_ = NULL; 759 widget_shown_ = NULL; 760 widget_hidden_ = NULL; 761 widget_bounds_changed_ = NULL; 762 } 763 764 Widget* NewWidget() { 765 Widget* widget = CreateTopLevelNativeWidget(); 766 widget->AddObserver(this); 767 return widget; 768 } 769 770 const Widget* active() const { return active_; } 771 const Widget* widget_closed() const { return widget_closed_; } 772 const Widget* widget_activated() const { return widget_activated_; } 773 const Widget* widget_deactivated() const { return widget_deactivated_; } 774 const Widget* widget_shown() const { return widget_shown_; } 775 const Widget* widget_hidden() const { return widget_hidden_; } 776 const Widget* widget_bounds_changed() const { return widget_bounds_changed_; } 777 778 private: 779 Widget* active_; 780 781 Widget* widget_closed_; 782 Widget* widget_activated_; 783 Widget* widget_deactivated_; 784 Widget* widget_shown_; 785 Widget* widget_hidden_; 786 Widget* widget_bounds_changed_; 787 }; 788 789 TEST_F(WidgetObserverTest, DISABLED_ActivationChange) { 790 Widget* toplevel = CreateTopLevelPlatformWidget(); 791 792 Widget* toplevel1 = NewWidget(); 793 Widget* toplevel2 = NewWidget(); 794 795 toplevel1->Show(); 796 toplevel2->Show(); 797 798 reset(); 799 800 toplevel1->Activate(); 801 802 RunPendingMessages(); 803 EXPECT_EQ(toplevel1, widget_activated()); 804 805 toplevel2->Activate(); 806 RunPendingMessages(); 807 EXPECT_EQ(toplevel1, widget_deactivated()); 808 EXPECT_EQ(toplevel2, widget_activated()); 809 EXPECT_EQ(toplevel2, active()); 810 811 toplevel->CloseNow(); 812 } 813 814 TEST_F(WidgetObserverTest, DISABLED_VisibilityChange) { 815 Widget* toplevel = CreateTopLevelPlatformWidget(); 816 817 Widget* child1 = NewWidget(); 818 Widget* child2 = NewWidget(); 819 820 toplevel->Show(); 821 child1->Show(); 822 child2->Show(); 823 824 reset(); 825 826 child1->Hide(); 827 EXPECT_EQ(child1, widget_hidden()); 828 829 child2->Hide(); 830 EXPECT_EQ(child2, widget_hidden()); 831 832 child1->Show(); 833 EXPECT_EQ(child1, widget_shown()); 834 835 child2->Show(); 836 EXPECT_EQ(child2, widget_shown()); 837 838 toplevel->CloseNow(); 839 } 840 841 TEST_F(WidgetObserverTest, DestroyBubble) { 842 Widget* anchor = CreateTopLevelPlatformWidget(); 843 anchor->Show(); 844 845 BubbleDelegateView* bubble_delegate = 846 new BubbleDelegateView(anchor->client_view(), BubbleBorder::NONE); 847 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate)); 848 bubble_widget->Show(); 849 bubble_widget->CloseNow(); 850 851 anchor->Hide(); 852 anchor->CloseNow(); 853 } 854 855 TEST_F(WidgetObserverTest, WidgetBoundsChanged) { 856 Widget* child1 = NewWidget(); 857 Widget* child2 = NewWidget(); 858 859 child1->OnNativeWidgetMove(); 860 EXPECT_EQ(child1, widget_bounds_changed()); 861 862 child2->OnNativeWidgetMove(); 863 EXPECT_EQ(child2, widget_bounds_changed()); 864 865 child1->OnNativeWidgetSizeChanged(gfx::Size()); 866 EXPECT_EQ(child1, widget_bounds_changed()); 867 868 child2->OnNativeWidgetSizeChanged(gfx::Size()); 869 EXPECT_EQ(child2, widget_bounds_changed()); 870 } 871 872 // Tests that SetBounds() and GetWindowBoundsInScreen() is symmetric when the 873 // widget is visible and not maximized or fullscreen. 874 TEST_F(WidgetTest, GetWindowBoundsInScreen) { 875 // Choose test coordinates away from edges and dimensions that are "small" 876 // (but not too small) to ensure the OS doesn't try to adjust them. 877 const gfx::Rect kTestBounds(150, 150, 400, 300); 878 const gfx::Size kTestSize(200, 180); 879 880 // First test a toplevel widget. 881 Widget* widget = CreateTopLevelPlatformWidget(); 882 widget->Show(); 883 884 EXPECT_NE(kTestSize.ToString(), 885 widget->GetWindowBoundsInScreen().size().ToString()); 886 widget->SetSize(kTestSize); 887 EXPECT_EQ(kTestSize.ToString(), 888 widget->GetWindowBoundsInScreen().size().ToString()); 889 890 EXPECT_NE(kTestBounds.ToString(), 891 widget->GetWindowBoundsInScreen().ToString()); 892 widget->SetBounds(kTestBounds); 893 EXPECT_EQ(kTestBounds.ToString(), 894 widget->GetWindowBoundsInScreen().ToString()); 895 896 // Changing just the size should not change the origin. 897 widget->SetSize(kTestSize); 898 EXPECT_EQ(kTestBounds.origin().ToString(), 899 widget->GetWindowBoundsInScreen().origin().ToString()); 900 901 widget->CloseNow(); 902 903 // Same tests with a frameless window. 904 widget = CreateTopLevelFramelessPlatformWidget(); 905 widget->Show(); 906 907 EXPECT_NE(kTestSize.ToString(), 908 widget->GetWindowBoundsInScreen().size().ToString()); 909 widget->SetSize(kTestSize); 910 EXPECT_EQ(kTestSize.ToString(), 911 widget->GetWindowBoundsInScreen().size().ToString()); 912 913 EXPECT_NE(kTestBounds.ToString(), 914 widget->GetWindowBoundsInScreen().ToString()); 915 widget->SetBounds(kTestBounds); 916 EXPECT_EQ(kTestBounds.ToString(), 917 widget->GetWindowBoundsInScreen().ToString()); 918 919 // For a frameless widget, the client bounds should also match. 920 EXPECT_EQ(kTestBounds.ToString(), 921 widget->GetClientAreaBoundsInScreen().ToString()); 922 923 // Verify origin is stable for a frameless window as well. 924 widget->SetSize(kTestSize); 925 EXPECT_EQ(kTestBounds.origin().ToString(), 926 widget->GetWindowBoundsInScreen().origin().ToString()); 927 928 widget->CloseNow(); 929 } 930 931 #if defined(false) 932 // Aura needs shell to maximize/fullscreen window. 933 // NativeWidgetGtk doesn't implement GetRestoredBounds. 934 TEST_F(WidgetTest, GetRestoredBounds) { 935 Widget* toplevel = CreateTopLevelPlatformWidget(); 936 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(), 937 toplevel->GetRestoredBounds().ToString()); 938 toplevel->Show(); 939 toplevel->Maximize(); 940 RunPendingMessages(); 941 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(), 942 toplevel->GetRestoredBounds().ToString()); 943 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0); 944 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0); 945 946 toplevel->Restore(); 947 RunPendingMessages(); 948 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(), 949 toplevel->GetRestoredBounds().ToString()); 950 951 toplevel->SetFullscreen(true); 952 RunPendingMessages(); 953 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(), 954 toplevel->GetRestoredBounds().ToString()); 955 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0); 956 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0); 957 } 958 #endif 959 960 // Test that window state is not changed after getting out of full screen. 961 TEST_F(WidgetTest, ExitFullscreenRestoreState) { 962 Widget* toplevel = CreateTopLevelPlatformWidget(); 963 964 toplevel->Show(); 965 RunPendingMessages(); 966 967 // This should be a normal state window. 968 EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel)); 969 970 toplevel->SetFullscreen(true); 971 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel)); 972 toplevel->SetFullscreen(false); 973 EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel)); 974 975 // And it should still be in normal state after getting out of full screen. 976 EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel)); 977 978 // Now, make it maximized. 979 toplevel->Maximize(); 980 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel)); 981 982 toplevel->SetFullscreen(true); 983 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel)); 984 toplevel->SetFullscreen(false); 985 EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel)); 986 987 // And it stays maximized after getting out of full screen. 988 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel)); 989 990 // Clean up. 991 toplevel->Close(); 992 RunPendingMessages(); 993 } 994 995 // The key-event propagation from Widget happens differently on aura and 996 // non-aura systems because of the difference in IME. So this test works only on 997 // aura. 998 TEST_F(WidgetTest, KeyboardInputEvent) { 999 Widget* toplevel = CreateTopLevelPlatformWidget(); 1000 View* container = toplevel->client_view(); 1001 1002 Textfield* textfield = new Textfield(); 1003 textfield->SetText(base::ASCIIToUTF16("some text")); 1004 container->AddChildView(textfield); 1005 toplevel->Show(); 1006 textfield->RequestFocus(); 1007 1008 // The press gets handled. The release doesn't have an effect. 1009 ui::KeyEvent backspace_p(ui::ET_KEY_PRESSED, ui::VKEY_DELETE, ui::EF_NONE); 1010 toplevel->OnKeyEvent(&backspace_p); 1011 EXPECT_TRUE(backspace_p.stopped_propagation()); 1012 ui::KeyEvent backspace_r(ui::ET_KEY_RELEASED, ui::VKEY_DELETE, ui::EF_NONE); 1013 toplevel->OnKeyEvent(&backspace_r); 1014 EXPECT_FALSE(backspace_r.handled()); 1015 1016 toplevel->Close(); 1017 } 1018 1019 // Verifies bubbles result in a focus lost when shown. 1020 // TODO(msw): this tests relies on focus, it needs to be in 1021 // interactive_ui_tests. 1022 TEST_F(WidgetTest, DISABLED_FocusChangesOnBubble) { 1023 // Create a widget, show and activate it and focus the contents view. 1024 View* contents_view = new View; 1025 contents_view->SetFocusable(true); 1026 Widget widget; 1027 Widget::InitParams init_params = 1028 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); 1029 init_params.bounds = gfx::Rect(0, 0, 200, 200); 1030 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 1031 #if !defined(OS_CHROMEOS) 1032 init_params.native_widget = new PlatformDesktopNativeWidget(&widget); 1033 #endif 1034 widget.Init(init_params); 1035 widget.SetContentsView(contents_view); 1036 widget.Show(); 1037 widget.Activate(); 1038 contents_view->RequestFocus(); 1039 EXPECT_TRUE(contents_view->HasFocus()); 1040 1041 // Show a bubble. 1042 BubbleDelegateView* bubble_delegate_view = 1043 new BubbleDelegateView(contents_view, BubbleBorder::TOP_LEFT); 1044 bubble_delegate_view->SetFocusable(true); 1045 BubbleDelegateView::CreateBubble(bubble_delegate_view)->Show(); 1046 bubble_delegate_view->RequestFocus(); 1047 1048 // |contents_view_| should no longer have focus. 1049 EXPECT_FALSE(contents_view->HasFocus()); 1050 EXPECT_TRUE(bubble_delegate_view->HasFocus()); 1051 1052 bubble_delegate_view->GetWidget()->CloseNow(); 1053 1054 // Closing the bubble should result in focus going back to the contents view. 1055 EXPECT_TRUE(contents_view->HasFocus()); 1056 } 1057 1058 class TestBubbleDelegateView : public BubbleDelegateView { 1059 public: 1060 TestBubbleDelegateView(View* anchor) 1061 : BubbleDelegateView(anchor, BubbleBorder::NONE), 1062 reset_controls_called_(false) {} 1063 virtual ~TestBubbleDelegateView() {} 1064 1065 virtual bool ShouldShowCloseButton() const OVERRIDE { 1066 reset_controls_called_ = true; 1067 return true; 1068 } 1069 1070 mutable bool reset_controls_called_; 1071 }; 1072 1073 TEST_F(WidgetTest, BubbleControlsResetOnInit) { 1074 Widget* anchor = CreateTopLevelPlatformWidget(); 1075 anchor->Show(); 1076 1077 TestBubbleDelegateView* bubble_delegate = 1078 new TestBubbleDelegateView(anchor->client_view()); 1079 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate)); 1080 EXPECT_TRUE(bubble_delegate->reset_controls_called_); 1081 bubble_widget->Show(); 1082 bubble_widget->CloseNow(); 1083 1084 anchor->Hide(); 1085 anchor->CloseNow(); 1086 } 1087 1088 // Desktop native widget Aura tests are for non Chrome OS platforms. 1089 #if !defined(OS_CHROMEOS) 1090 // Test to ensure that after minimize, view width is set to zero. 1091 TEST_F(WidgetTest, TestViewWidthAfterMinimizingWidget) { 1092 // Create a widget. 1093 Widget widget; 1094 Widget::InitParams init_params = 1095 CreateParams(Widget::InitParams::TYPE_WINDOW); 1096 init_params.show_state = ui::SHOW_STATE_NORMAL; 1097 gfx::Rect initial_bounds(0, 0, 300, 400); 1098 init_params.bounds = initial_bounds; 1099 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 1100 init_params.native_widget = new PlatformDesktopNativeWidget(&widget); 1101 widget.Init(init_params); 1102 NonClientView* non_client_view = widget.non_client_view(); 1103 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget); 1104 non_client_view->SetFrameView(frame_view); 1105 widget.Show(); 1106 widget.Minimize(); 1107 EXPECT_EQ(0, frame_view->width()); 1108 } 1109 1110 // This class validates whether paints are received for a visible Widget. 1111 // To achieve this it overrides the Show and Close methods on the Widget class 1112 // and sets state whether subsequent paints are expected. 1113 class DesktopAuraTestValidPaintWidget : public views::Widget { 1114 public: 1115 DesktopAuraTestValidPaintWidget() 1116 : expect_paint_(true), 1117 received_paint_while_hidden_(false) { 1118 } 1119 1120 virtual ~DesktopAuraTestValidPaintWidget() { 1121 } 1122 1123 virtual void Show() OVERRIDE { 1124 expect_paint_ = true; 1125 views::Widget::Show(); 1126 } 1127 1128 virtual void Close() OVERRIDE { 1129 expect_paint_ = false; 1130 views::Widget::Close(); 1131 } 1132 1133 void Hide() { 1134 expect_paint_ = false; 1135 views::Widget::Hide(); 1136 } 1137 1138 virtual void OnNativeWidgetPaint(gfx::Canvas* canvas) OVERRIDE { 1139 EXPECT_TRUE(expect_paint_); 1140 if (!expect_paint_) 1141 received_paint_while_hidden_ = true; 1142 views::Widget::OnNativeWidgetPaint(canvas); 1143 } 1144 1145 bool received_paint_while_hidden() const { 1146 return received_paint_while_hidden_; 1147 } 1148 1149 private: 1150 bool expect_paint_; 1151 bool received_paint_while_hidden_; 1152 }; 1153 1154 TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterCloseTest) { 1155 View* contents_view = new View; 1156 contents_view->SetFocusable(true); 1157 DesktopAuraTestValidPaintWidget widget; 1158 Widget::InitParams init_params = 1159 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); 1160 init_params.bounds = gfx::Rect(0, 0, 200, 200); 1161 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 1162 init_params.native_widget = new PlatformDesktopNativeWidget(&widget); 1163 widget.Init(init_params); 1164 widget.SetContentsView(contents_view); 1165 widget.Show(); 1166 widget.Activate(); 1167 RunPendingMessages(); 1168 widget.SchedulePaintInRect(init_params.bounds); 1169 widget.Close(); 1170 RunPendingMessages(); 1171 EXPECT_FALSE(widget.received_paint_while_hidden()); 1172 } 1173 1174 TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterHideTest) { 1175 View* contents_view = new View; 1176 contents_view->SetFocusable(true); 1177 DesktopAuraTestValidPaintWidget widget; 1178 Widget::InitParams init_params = 1179 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); 1180 init_params.bounds = gfx::Rect(0, 0, 200, 200); 1181 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 1182 init_params.native_widget = new PlatformDesktopNativeWidget(&widget); 1183 widget.Init(init_params); 1184 widget.SetContentsView(contents_view); 1185 widget.Show(); 1186 widget.Activate(); 1187 RunPendingMessages(); 1188 widget.SchedulePaintInRect(init_params.bounds); 1189 widget.Hide(); 1190 RunPendingMessages(); 1191 EXPECT_FALSE(widget.received_paint_while_hidden()); 1192 widget.Close(); 1193 } 1194 1195 // Test to ensure that the aura Window's visiblity state is set to visible if 1196 // the underlying widget is hidden and then shown. 1197 TEST_F(WidgetTest, TestWindowVisibilityAfterHide) { 1198 // Create a widget. 1199 Widget widget; 1200 Widget::InitParams init_params = 1201 CreateParams(Widget::InitParams::TYPE_WINDOW); 1202 init_params.show_state = ui::SHOW_STATE_NORMAL; 1203 gfx::Rect initial_bounds(0, 0, 300, 400); 1204 init_params.bounds = initial_bounds; 1205 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 1206 init_params.native_widget = new PlatformDesktopNativeWidget(&widget); 1207 widget.Init(init_params); 1208 NonClientView* non_client_view = widget.non_client_view(); 1209 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget); 1210 non_client_view->SetFrameView(frame_view); 1211 1212 widget.Hide(); 1213 EXPECT_FALSE(IsNativeWindowVisible(widget.GetNativeWindow())); 1214 widget.Show(); 1215 EXPECT_TRUE(IsNativeWindowVisible(widget.GetNativeWindow())); 1216 } 1217 1218 // The following code verifies we can correctly destroy a Widget from a mouse 1219 // enter/exit. We could test move/drag/enter/exit but in general we don't run 1220 // nested message loops from such events, nor has the code ever really dealt 1221 // with this situation. 1222 1223 // Generates two moves (first generates enter, second real move), a press, drag 1224 // and release stopping at |last_event_type|. 1225 void GenerateMouseEvents(Widget* widget, ui::EventType last_event_type) { 1226 const gfx::Rect screen_bounds(widget->GetWindowBoundsInScreen()); 1227 ui::MouseEvent move_event(ui::ET_MOUSE_MOVED, screen_bounds.CenterPoint(), 1228 screen_bounds.CenterPoint(), 0, 0); 1229 ui::EventProcessor* dispatcher = WidgetTest::GetEventProcessor(widget); 1230 ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&move_event); 1231 if (last_event_type == ui::ET_MOUSE_ENTERED || details.dispatcher_destroyed) 1232 return; 1233 details = dispatcher->OnEventFromSource(&move_event); 1234 if (last_event_type == ui::ET_MOUSE_MOVED || details.dispatcher_destroyed) 1235 return; 1236 1237 ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, screen_bounds.CenterPoint(), 1238 screen_bounds.CenterPoint(), 0, 0); 1239 details = dispatcher->OnEventFromSource(&press_event); 1240 if (last_event_type == ui::ET_MOUSE_PRESSED || details.dispatcher_destroyed) 1241 return; 1242 1243 gfx::Point end_point(screen_bounds.CenterPoint()); 1244 end_point.Offset(1, 1); 1245 ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, end_point, end_point, 0, 0); 1246 details = dispatcher->OnEventFromSource(&drag_event); 1247 if (last_event_type == ui::ET_MOUSE_DRAGGED || details.dispatcher_destroyed) 1248 return; 1249 1250 ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, end_point, end_point, 0, 1251 0); 1252 details = dispatcher->OnEventFromSource(&release_event); 1253 if (details.dispatcher_destroyed) 1254 return; 1255 } 1256 1257 // Creates a widget and invokes GenerateMouseEvents() with |last_event_type|. 1258 void RunCloseWidgetDuringDispatchTest(WidgetTest* test, 1259 ui::EventType last_event_type) { 1260 // |widget| is deleted by CloseWidgetView. 1261 Widget* widget = new Widget; 1262 Widget::InitParams params = 1263 test->CreateParams(Widget::InitParams::TYPE_POPUP); 1264 params.native_widget = new PlatformDesktopNativeWidget(widget); 1265 params.bounds = gfx::Rect(0, 0, 50, 100); 1266 widget->Init(params); 1267 widget->SetContentsView(new CloseWidgetView(last_event_type)); 1268 widget->Show(); 1269 GenerateMouseEvents(widget, last_event_type); 1270 } 1271 1272 // Verifies deleting the widget from a mouse pressed event doesn't crash. 1273 TEST_F(WidgetTest, CloseWidgetDuringMousePress) { 1274 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_PRESSED); 1275 } 1276 1277 // Verifies deleting the widget from a mouse released event doesn't crash. 1278 TEST_F(WidgetTest, CloseWidgetDuringMouseReleased) { 1279 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_RELEASED); 1280 } 1281 1282 #endif // !defined(OS_CHROMEOS) 1283 1284 // Tests that wheel events generated from scroll events are targetted to the 1285 // views under the cursor when the focused view does not processed them. 1286 TEST_F(WidgetTest, WheelEventsFromScrollEventTarget) { 1287 EventCountView* cursor_view = new EventCountView; 1288 cursor_view->SetBounds(60, 0, 50, 40); 1289 1290 Widget* widget = CreateTopLevelPlatformWidget(); 1291 widget->GetRootView()->AddChildView(cursor_view); 1292 1293 // Generate a scroll event on the cursor view. 1294 ui::ScrollEvent scroll(ui::ET_SCROLL, 1295 gfx::Point(65, 5), 1296 ui::EventTimeForNow(), 1297 0, 1298 0, 20, 1299 0, 20, 1300 2); 1301 widget->OnScrollEvent(&scroll); 1302 1303 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_SCROLL)); 1304 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL)); 1305 1306 cursor_view->ResetCounts(); 1307 1308 ui::ScrollEvent scroll2(ui::ET_SCROLL, 1309 gfx::Point(5, 5), 1310 ui::EventTimeForNow(), 1311 0, 1312 0, 20, 1313 0, 20, 1314 2); 1315 widget->OnScrollEvent(&scroll2); 1316 1317 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_SCROLL)); 1318 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL)); 1319 1320 widget->CloseNow(); 1321 } 1322 1323 // Tests that if a scroll-begin gesture is not handled, then subsequent scroll 1324 // events are not dispatched to any view. 1325 TEST_F(WidgetTest, GestureScrollEventDispatching) { 1326 EventCountView* noscroll_view = new EventCountView; 1327 EventCountView* scroll_view = new ScrollableEventCountView; 1328 1329 noscroll_view->SetBounds(0, 0, 50, 40); 1330 scroll_view->SetBounds(60, 0, 40, 40); 1331 1332 Widget* widget = CreateTopLevelPlatformWidget(); 1333 widget->GetRootView()->AddChildView(noscroll_view); 1334 widget->GetRootView()->AddChildView(scroll_view); 1335 1336 { 1337 ui::GestureEvent begin( 1338 5, 1339 5, 1340 0, 1341 base::TimeDelta(), 1342 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN)); 1343 widget->OnGestureEvent(&begin); 1344 ui::GestureEvent update( 1345 25, 1346 15, 1347 0, 1348 base::TimeDelta(), 1349 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10)); 1350 widget->OnGestureEvent(&update); 1351 ui::GestureEvent end(25, 1352 15, 1353 0, 1354 base::TimeDelta(), 1355 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END)); 1356 widget->OnGestureEvent(&end); 1357 1358 EXPECT_EQ(1, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN)); 1359 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE)); 1360 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END)); 1361 } 1362 1363 { 1364 ui::GestureEvent begin( 1365 65, 1366 5, 1367 0, 1368 base::TimeDelta(), 1369 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN)); 1370 widget->OnGestureEvent(&begin); 1371 ui::GestureEvent update( 1372 85, 1373 15, 1374 0, 1375 base::TimeDelta(), 1376 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10)); 1377 widget->OnGestureEvent(&update); 1378 ui::GestureEvent end(85, 1379 15, 1380 0, 1381 base::TimeDelta(), 1382 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END)); 1383 widget->OnGestureEvent(&end); 1384 1385 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN)); 1386 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE)); 1387 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END)); 1388 } 1389 1390 widget->CloseNow(); 1391 } 1392 1393 // Tests that event-handlers installed on the RootView get triggered correctly. 1394 // TODO(tdanderson): Clean up this test as part of crbug.com/355680. 1395 TEST_F(WidgetTest, EventHandlersOnRootView) { 1396 Widget* widget = CreateTopLevelNativeWidget(); 1397 View* root_view = widget->GetRootView(); 1398 1399 scoped_ptr<EventCountView> view(new EventCountView()); 1400 view->set_owned_by_client(); 1401 view->SetBounds(0, 0, 20, 20); 1402 root_view->AddChildView(view.get()); 1403 1404 EventCountHandler h1; 1405 root_view->AddPreTargetHandler(&h1); 1406 1407 EventCountHandler h2; 1408 root_view->AddPostTargetHandler(&h2); 1409 1410 widget->SetBounds(gfx::Rect(0, 0, 100, 100)); 1411 widget->Show(); 1412 1413 // Dispatch a ui::ET_SCROLL event. The event remains unhandled and should 1414 // bubble up the views hierarchy to be re-dispatched on the root view. 1415 ui::ScrollEvent scroll(ui::ET_SCROLL, 1416 gfx::Point(5, 5), 1417 ui::EventTimeForNow(), 1418 0, 1419 0, 20, 1420 0, 20, 1421 2); 1422 widget->OnScrollEvent(&scroll); 1423 EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL)); 1424 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL)); 1425 EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL)); 1426 1427 // Unhandled scroll events are turned into wheel events and re-dispatched. 1428 EXPECT_EQ(1, h1.GetEventCount(ui::ET_MOUSEWHEEL)); 1429 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSEWHEEL)); 1430 EXPECT_EQ(1, h2.GetEventCount(ui::ET_MOUSEWHEEL)); 1431 1432 h1.ResetCounts(); 1433 view->ResetCounts(); 1434 h2.ResetCounts(); 1435 1436 // Dispatch a ui::ET_SCROLL_FLING_START event. The event remains unhandled and 1437 // should bubble up the views hierarchy to be re-dispatched on the root view. 1438 ui::ScrollEvent fling(ui::ET_SCROLL_FLING_START, 1439 gfx::Point(5, 5), 1440 ui::EventTimeForNow(), 1441 0, 1442 0, 20, 1443 0, 20, 1444 2); 1445 widget->OnScrollEvent(&fling); 1446 EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL_FLING_START)); 1447 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL_FLING_START)); 1448 EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL_FLING_START)); 1449 1450 // Unhandled scroll events which are not of type ui::ET_SCROLL should not 1451 // be turned into wheel events and re-dispatched. 1452 EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL)); 1453 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL)); 1454 EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL)); 1455 1456 h1.ResetCounts(); 1457 view->ResetCounts(); 1458 h2.ResetCounts(); 1459 1460 // Change the handle mode of |view| so that events are marked as handled at 1461 // the target phase. 1462 view->set_handle_mode(EventCountView::CONSUME_EVENTS); 1463 1464 // Dispatch a ui::ET_GESTURE_TAP_DOWN and a ui::ET_GESTURE_TAP_CANCEL event. 1465 // The events are handled at the target phase and should not reach the 1466 // post-target handler. 1467 ui::GestureEvent tap_down(5, 1468 5, 1469 0, 1470 ui::EventTimeForNow(), 1471 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN)); 1472 widget->OnGestureEvent(&tap_down); 1473 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_DOWN)); 1474 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_TAP_DOWN)); 1475 EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_DOWN)); 1476 1477 ui::GestureEvent tap_cancel( 1478 5, 1479 5, 1480 0, 1481 ui::EventTimeForNow(), 1482 ui::GestureEventDetails(ui::ET_GESTURE_TAP_CANCEL)); 1483 widget->OnGestureEvent(&tap_cancel); 1484 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_CANCEL)); 1485 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_TAP_CANCEL)); 1486 EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_CANCEL)); 1487 1488 h1.ResetCounts(); 1489 view->ResetCounts(); 1490 h2.ResetCounts(); 1491 1492 // Dispatch a ui::ET_SCROLL event. The event is handled at the target phase 1493 // and should not reach the post-target handler. 1494 ui::ScrollEvent consumed_scroll(ui::ET_SCROLL, 1495 gfx::Point(5, 5), 1496 ui::EventTimeForNow(), 1497 0, 1498 0, 20, 1499 0, 20, 1500 2); 1501 widget->OnScrollEvent(&consumed_scroll); 1502 EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL)); 1503 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL)); 1504 EXPECT_EQ(0, h2.GetEventCount(ui::ET_SCROLL)); 1505 1506 // Handled scroll events are not turned into wheel events and re-dispatched. 1507 EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL)); 1508 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL)); 1509 EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL)); 1510 1511 widget->CloseNow(); 1512 } 1513 1514 TEST_F(WidgetTest, SynthesizeMouseMoveEvent) { 1515 Widget* widget = CreateTopLevelNativeWidget(); 1516 View* root_view = widget->GetRootView(); 1517 1518 EventCountView* v1 = new EventCountView(); 1519 v1->SetBounds(0, 0, 10, 10); 1520 root_view->AddChildView(v1); 1521 EventCountView* v2 = new EventCountView(); 1522 v2->SetBounds(0, 10, 10, 10); 1523 root_view->AddChildView(v2); 1524 1525 gfx::Point cursor_location(5, 5); 1526 ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location, 1527 ui::EF_NONE, ui::EF_NONE); 1528 widget->OnMouseEvent(&move); 1529 1530 EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_ENTERED)); 1531 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED)); 1532 1533 delete v1; 1534 v2->SetBounds(0, 0, 10, 10); 1535 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED)); 1536 1537 widget->SynthesizeMouseMoveEvent(); 1538 EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_ENTERED)); 1539 } 1540 1541 namespace { 1542 1543 // ui::EventHandler which handles all mouse press events. 1544 class MousePressEventConsumer : public ui::EventHandler { 1545 public: 1546 explicit MousePressEventConsumer() { 1547 } 1548 1549 virtual ~MousePressEventConsumer() { 1550 } 1551 1552 private: 1553 // ui::EventHandler: 1554 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { 1555 if (event->type() == ui::ET_MOUSE_PRESSED) 1556 event->SetHandled(); 1557 } 1558 1559 DISALLOW_COPY_AND_ASSIGN(MousePressEventConsumer); 1560 }; 1561 1562 } // namespace 1563 1564 // Test that mouse presses and mouse releases are dispatched normally when a 1565 // touch is down. 1566 TEST_F(WidgetTest, MouseEventDispatchWhileTouchIsDown) { 1567 Widget* widget = CreateTopLevelNativeWidget(); 1568 widget->Show(); 1569 widget->SetSize(gfx::Size(300, 300)); 1570 1571 EventCountView* event_count_view = new EventCountView(); 1572 event_count_view->SetBounds(0, 0, 300, 300); 1573 widget->GetRootView()->AddChildView(event_count_view); 1574 1575 MousePressEventConsumer consumer; 1576 event_count_view->AddPostTargetHandler(&consumer); 1577 1578 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow()); 1579 generator.PressTouch(); 1580 generator.ClickLeftButton(); 1581 1582 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_PRESSED)); 1583 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_RELEASED)); 1584 1585 widget->CloseNow(); 1586 } 1587 1588 // Used by SingleWindowClosing to count number of times WindowClosing() has 1589 // been invoked. 1590 class ClosingDelegate : public WidgetDelegate { 1591 public: 1592 ClosingDelegate() : count_(0), widget_(NULL) {} 1593 1594 int count() const { return count_; } 1595 1596 void set_widget(views::Widget* widget) { widget_ = widget; } 1597 1598 // WidgetDelegate overrides: 1599 virtual Widget* GetWidget() OVERRIDE { return widget_; } 1600 virtual const Widget* GetWidget() const OVERRIDE { return widget_; } 1601 virtual void WindowClosing() OVERRIDE { 1602 count_++; 1603 } 1604 1605 private: 1606 int count_; 1607 views::Widget* widget_; 1608 1609 DISALLOW_COPY_AND_ASSIGN(ClosingDelegate); 1610 }; 1611 1612 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget 1613 // is closed. 1614 TEST_F(WidgetTest, SingleWindowClosing) { 1615 scoped_ptr<ClosingDelegate> delegate(new ClosingDelegate()); 1616 Widget* widget = new Widget(); // Destroyed by CloseNow() below. 1617 Widget::InitParams init_params = 1618 CreateParams(Widget::InitParams::TYPE_WINDOW); 1619 init_params.bounds = gfx::Rect(0, 0, 200, 200); 1620 init_params.delegate = delegate.get(); 1621 #if !defined(OS_CHROMEOS) 1622 init_params.native_widget = new PlatformDesktopNativeWidget(widget); 1623 #endif 1624 widget->Init(init_params); 1625 EXPECT_EQ(0, delegate->count()); 1626 widget->CloseNow(); 1627 EXPECT_EQ(1, delegate->count()); 1628 } 1629 1630 class WidgetWindowTitleTest : public WidgetTest { 1631 protected: 1632 void RunTest(bool desktop_native_widget) { 1633 Widget* widget = new Widget(); // Destroyed by CloseNow() below. 1634 Widget::InitParams init_params = 1635 CreateParams(Widget::InitParams::TYPE_WINDOW); 1636 widget->Init(init_params); 1637 1638 #if !defined(OS_CHROMEOS) 1639 if (desktop_native_widget) 1640 init_params.native_widget = new PlatformDesktopNativeWidget(widget); 1641 #else 1642 DCHECK(!desktop_native_widget) 1643 << "DesktopNativeWidget does not exist on non-Aura or on ChromeOS."; 1644 #endif 1645 1646 internal::NativeWidgetPrivate* native_widget = 1647 widget->native_widget_private(); 1648 1649 base::string16 empty; 1650 base::string16 s1(base::UTF8ToUTF16("Title1")); 1651 base::string16 s2(base::UTF8ToUTF16("Title2")); 1652 base::string16 s3(base::UTF8ToUTF16("TitleLong")); 1653 1654 // The widget starts with no title, setting empty should not change 1655 // anything. 1656 EXPECT_FALSE(native_widget->SetWindowTitle(empty)); 1657 // Setting the title to something non-empty should cause a change. 1658 EXPECT_TRUE(native_widget->SetWindowTitle(s1)); 1659 // Setting the title to something else with the same length should cause a 1660 // change. 1661 EXPECT_TRUE(native_widget->SetWindowTitle(s2)); 1662 // Setting the title to something else with a different length should cause 1663 // a change. 1664 EXPECT_TRUE(native_widget->SetWindowTitle(s3)); 1665 // Setting the title to the same thing twice should not cause a change. 1666 EXPECT_FALSE(native_widget->SetWindowTitle(s3)); 1667 1668 widget->CloseNow(); 1669 } 1670 }; 1671 1672 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_NativeWidget) { 1673 // Use the default NativeWidget. 1674 bool desktop_native_widget = false; 1675 RunTest(desktop_native_widget); 1676 } 1677 1678 // DesktopNativeWidget does not exist on non-Aura or on ChromeOS. 1679 #if !defined(OS_CHROMEOS) 1680 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_DesktopNativeWidget) { 1681 // Override to use a DesktopNativeWidget. 1682 bool desktop_native_widget = true; 1683 RunTest(desktop_native_widget); 1684 } 1685 #endif // !OS_CHROMEOS 1686 1687 TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) { 1688 Widget* widget = new Widget; 1689 Widget::InitParams params = 1690 CreateParams(views::Widget::InitParams::TYPE_POPUP); 1691 widget->Init(params); 1692 1693 widget->SetContentsView(new CloseWidgetView(ui::ET_MOUSE_PRESSED)); 1694 1695 widget->SetSize(gfx::Size(100, 100)); 1696 widget->Show(); 1697 1698 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow()); 1699 1700 WidgetDeletionObserver deletion_observer(widget); 1701 generator.ClickLeftButton(); 1702 EXPECT_FALSE(deletion_observer.IsWidgetAlive()); 1703 1704 // Yay we did not crash! 1705 } 1706 1707 TEST_F(WidgetTest, WidgetDeleted_InDispatchGestureEvent) { 1708 Widget* widget = new Widget; 1709 Widget::InitParams params = 1710 CreateParams(views::Widget::InitParams::TYPE_POPUP); 1711 widget->Init(params); 1712 1713 widget->SetContentsView(new CloseWidgetView(ui::ET_GESTURE_TAP_DOWN)); 1714 1715 widget->SetSize(gfx::Size(100, 100)); 1716 widget->Show(); 1717 1718 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow()); 1719 1720 WidgetDeletionObserver deletion_observer(widget); 1721 generator.GestureTapAt(widget->GetWindowBoundsInScreen().CenterPoint()); 1722 EXPECT_FALSE(deletion_observer.IsWidgetAlive()); 1723 1724 // Yay we did not crash! 1725 } 1726 1727 // See description of RunGetNativeThemeFromDestructor() for details. 1728 class GetNativeThemeFromDestructorView : public WidgetDelegateView { 1729 public: 1730 GetNativeThemeFromDestructorView() {} 1731 virtual ~GetNativeThemeFromDestructorView() { 1732 VerifyNativeTheme(); 1733 } 1734 1735 virtual View* GetContentsView() OVERRIDE { 1736 return this; 1737 } 1738 1739 private: 1740 void VerifyNativeTheme() { 1741 ASSERT_TRUE(GetNativeTheme() != NULL); 1742 } 1743 1744 DISALLOW_COPY_AND_ASSIGN(GetNativeThemeFromDestructorView); 1745 }; 1746 1747 // Verifies GetNativeTheme() from the destructor of a WidgetDelegateView doesn't 1748 // crash. |is_first_run| is true if this is the first call. A return value of 1749 // true indicates this should be run again with a value of false. 1750 // First run uses DesktopNativeWidgetAura (if possible). Second run doesn't. 1751 bool RunGetNativeThemeFromDestructor(const Widget::InitParams& in_params, 1752 bool is_first_run) { 1753 bool needs_second_run = false; 1754 // Destroyed by CloseNow() below. 1755 Widget* widget = new Widget; 1756 Widget::InitParams params(in_params); 1757 // Deletes itself when the Widget is destroyed. 1758 params.delegate = new GetNativeThemeFromDestructorView; 1759 #if !defined(OS_CHROMEOS) 1760 if (is_first_run) { 1761 params.native_widget = new PlatformDesktopNativeWidget(widget); 1762 needs_second_run = true; 1763 } 1764 #endif 1765 widget->Init(params); 1766 widget->CloseNow(); 1767 return needs_second_run; 1768 } 1769 1770 // See description of RunGetNativeThemeFromDestructor() for details. 1771 TEST_F(WidgetTest, GetNativeThemeFromDestructor) { 1772 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 1773 if (RunGetNativeThemeFromDestructor(params, true)) 1774 RunGetNativeThemeFromDestructor(params, false); 1775 } 1776 1777 // Used by HideCloseDestroy. Allows setting a boolean when the widget is 1778 // destroyed. 1779 class CloseDestroysWidget : public Widget { 1780 public: 1781 explicit CloseDestroysWidget(bool* destroyed) 1782 : destroyed_(destroyed) { 1783 } 1784 1785 virtual ~CloseDestroysWidget() { 1786 if (destroyed_) { 1787 *destroyed_ = true; 1788 base::MessageLoop::current()->QuitNow(); 1789 } 1790 } 1791 1792 void Detach() { destroyed_ = NULL; } 1793 1794 private: 1795 // If non-null set to true from destructor. 1796 bool* destroyed_; 1797 1798 DISALLOW_COPY_AND_ASSIGN(CloseDestroysWidget); 1799 }; 1800 1801 // An observer that registers that an animation has ended. 1802 class AnimationEndObserver : public ui::ImplicitAnimationObserver { 1803 public: 1804 AnimationEndObserver() : animation_completed_(false) {} 1805 virtual ~AnimationEndObserver() {} 1806 1807 bool animation_completed() const { return animation_completed_; } 1808 1809 // ui::ImplicitAnimationObserver: 1810 virtual void OnImplicitAnimationsCompleted() OVERRIDE { 1811 animation_completed_ = true; 1812 } 1813 1814 private: 1815 bool animation_completed_; 1816 1817 DISALLOW_COPY_AND_ASSIGN(AnimationEndObserver); 1818 }; 1819 1820 // An observer that registers the bounds of a widget on destruction. 1821 class WidgetBoundsObserver : public WidgetObserver { 1822 public: 1823 WidgetBoundsObserver() {} 1824 virtual ~WidgetBoundsObserver() {} 1825 1826 gfx::Rect bounds() { return bounds_; } 1827 1828 // WidgetObserver: 1829 virtual void OnWidgetDestroying(Widget* widget) OVERRIDE { 1830 bounds_ = widget->GetWindowBoundsInScreen(); 1831 } 1832 1833 private: 1834 gfx::Rect bounds_; 1835 1836 DISALLOW_COPY_AND_ASSIGN(WidgetBoundsObserver); 1837 }; 1838 1839 // Verifies Close() results in destroying. 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(OS_CHROMEOS) 1847 params.native_widget = new PlatformDesktopNativeWidget(widget); 1848 #endif 1849 widget->Init(params); 1850 widget->Show(); 1851 widget->Hide(); 1852 widget->Close(); 1853 EXPECT_FALSE(destroyed); 1854 // Run the message loop as Close() asynchronously deletes. 1855 base::RunLoop().Run(); 1856 EXPECT_TRUE(destroyed); 1857 // Close() should destroy the widget. If not we'll cleanup to avoid leaks. 1858 if (!destroyed) { 1859 widget->Detach(); 1860 widget->CloseNow(); 1861 } 1862 } 1863 1864 // Tests that killing a widget while animating it does not crash. 1865 TEST_F(WidgetTest, CloseWidgetWhileAnimating) { 1866 scoped_ptr<Widget> widget(new Widget); 1867 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 1868 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 1869 params.bounds = gfx::Rect(50, 50, 250, 250); 1870 widget->Init(params); 1871 AnimationEndObserver animation_observer; 1872 WidgetBoundsObserver widget_observer; 1873 gfx::Rect bounds(0, 0, 50, 50); 1874 { 1875 // Normal animations for tests have ZERO_DURATION, make sure we are actually 1876 // animating the movement. 1877 ui::ScopedAnimationDurationScaleMode animation_scale_mode( 1878 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); 1879 ui::ScopedLayerAnimationSettings animation_settings( 1880 widget->GetLayer()->GetAnimator()); 1881 animation_settings.AddObserver(&animation_observer); 1882 widget->AddObserver(&widget_observer); 1883 widget->Show(); 1884 1885 // Animate the bounds change. 1886 widget->SetBounds(bounds); 1887 widget.reset(); 1888 EXPECT_FALSE(animation_observer.animation_completed()); 1889 } 1890 EXPECT_TRUE(animation_observer.animation_completed()); 1891 EXPECT_EQ(widget_observer.bounds(), bounds); 1892 } 1893 1894 // A view that consumes mouse-pressed event and gesture-tap-down events. 1895 class RootViewTestView : public View { 1896 public: 1897 RootViewTestView(): View() {} 1898 1899 private: 1900 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE { 1901 return true; 1902 } 1903 1904 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { 1905 if (event->type() == ui::ET_GESTURE_TAP_DOWN) 1906 event->SetHandled(); 1907 } 1908 }; 1909 1910 // Checks if RootView::*_handler_ fields are unset when widget is hidden. 1911 // Fails on chromium.webkit Windows bot, see crbug.com/264872. 1912 #if defined(OS_WIN) 1913 #define MAYBE_DisableTestRootViewHandlersWhenHidden\ 1914 DISABLED_TestRootViewHandlersWhenHidden 1915 #else 1916 #define MAYBE_DisableTestRootViewHandlersWhenHidden\ 1917 TestRootViewHandlersWhenHidden 1918 #endif 1919 TEST_F(WidgetTest, MAYBE_DisableTestRootViewHandlersWhenHidden) { 1920 Widget* widget = CreateTopLevelNativeWidget(); 1921 widget->SetBounds(gfx::Rect(0, 0, 300, 300)); 1922 View* view = new RootViewTestView(); 1923 view->SetBounds(0, 0, 300, 300); 1924 internal::RootView* root_view = 1925 static_cast<internal::RootView*>(widget->GetRootView()); 1926 root_view->AddChildView(view); 1927 1928 // Check RootView::mouse_pressed_handler_. 1929 widget->Show(); 1930 EXPECT_EQ(NULL, GetMousePressedHandler(root_view)); 1931 gfx::Point click_location(45, 15); 1932 ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location, 1933 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); 1934 widget->OnMouseEvent(&press); 1935 EXPECT_EQ(view, GetMousePressedHandler(root_view)); 1936 widget->Hide(); 1937 EXPECT_EQ(NULL, GetMousePressedHandler(root_view)); 1938 1939 // Check RootView::mouse_move_handler_. 1940 widget->Show(); 1941 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view)); 1942 gfx::Point move_location(45, 15); 1943 ui::MouseEvent move(ui::ET_MOUSE_MOVED, move_location, move_location, 0, 0); 1944 widget->OnMouseEvent(&move); 1945 EXPECT_EQ(view, GetMouseMoveHandler(root_view)); 1946 widget->Hide(); 1947 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view)); 1948 1949 // Check RootView::gesture_handler_. 1950 widget->Show(); 1951 EXPECT_EQ(NULL, GetGestureHandler(root_view)); 1952 ui::GestureEvent tap_down(15, 1953 15, 1954 0, 1955 base::TimeDelta(), 1956 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN)); 1957 widget->OnGestureEvent(&tap_down); 1958 EXPECT_EQ(view, GetGestureHandler(root_view)); 1959 widget->Hide(); 1960 EXPECT_EQ(NULL, GetGestureHandler(root_view)); 1961 1962 widget->Close(); 1963 } 1964 1965 // Convenience to make constructing a GestureEvent simpler. 1966 class GestureEventForTest : public ui::GestureEvent { 1967 public: 1968 GestureEventForTest(ui::EventType type, int x, int y) 1969 : GestureEvent(x, 1970 y, 1971 0, 1972 base::TimeDelta(), 1973 ui::GestureEventDetails(type)) {} 1974 1975 GestureEventForTest(ui::GestureEventDetails details, int x, int y) 1976 : GestureEvent(x, y, 0, base::TimeDelta(), details) {} 1977 }; 1978 1979 // Tests that the |gesture_handler_| member in RootView is always NULL 1980 // after the dispatch of a ui::ET_GESTURE_END event corresponding to 1981 // the release of the final touch point on the screen and that 1982 // ui::ET_GESTURE_END events corresponding to the removal of any other touch 1983 // point are never dispatched to a view. Also verifies that 1984 // ui::ET_GESTURE_BEGIN is never dispatched to a view and does not change the 1985 // value of |gesture_handler_|. 1986 TEST_F(WidgetTest, GestureBeginAndEndEvents) { 1987 Widget* widget = CreateTopLevelNativeWidget(); 1988 widget->SetBounds(gfx::Rect(0, 0, 300, 300)); 1989 EventCountView* view = new EventCountView(); 1990 view->SetBounds(0, 0, 300, 300); 1991 internal::RootView* root_view = 1992 static_cast<internal::RootView*>(widget->GetRootView()); 1993 root_view->AddChildView(view); 1994 widget->Show(); 1995 1996 // If no gesture handler is set, dispatching a ui::ET_GESTURE_END or 1997 // ui::ET_GESTURE_BEGIN event should not set the gesture handler and 1998 // the events should remain unhandled because the handle mode of |view| 1999 // indicates that events should not be consumed. 2000 EXPECT_EQ(NULL, GetGestureHandler(root_view)); 2001 GestureEventForTest end(ui::ET_GESTURE_END, 15, 15); 2002 widget->OnGestureEvent(&end); 2003 EXPECT_FALSE(end.handled()); 2004 EXPECT_EQ(NULL, GetGestureHandler(root_view)); 2005 2006 GestureEventForTest begin(ui::ET_GESTURE_BEGIN, 15, 15); 2007 widget->OnGestureEvent(&begin); 2008 EXPECT_FALSE(begin.handled()); 2009 EXPECT_EQ(NULL, GetGestureHandler(root_view)); 2010 2011 // Change the handle mode of |view| to indicate that it would like 2012 // to handle all events. 2013 view->set_handle_mode(EventCountView::CONSUME_EVENTS); 2014 2015 // If no gesture handler is set, dispatching only a ui::ET_GESTURE_BEGIN 2016 // should not set the gesture handler and should not be marked as handled 2017 // because it is never dispatched. 2018 begin = GestureEventForTest(ui::ET_GESTURE_BEGIN, 15, 15); 2019 widget->OnGestureEvent(&begin); 2020 EXPECT_FALSE(begin.handled()); 2021 EXPECT_EQ(NULL, GetGestureHandler(root_view)); 2022 2023 // If no gesture handler is set, dispatching only a ui::ET_GESTURE_BEGIN 2024 // corresponding to a second touch point should not set the gesture handler 2025 // and should not be marked as handled because it is never dispatched. 2026 ui::GestureEventDetails details(ui::ET_GESTURE_END); 2027 details.set_touch_points(2); 2028 GestureEventForTest end_second_touch_point(details, 15, 15); 2029 widget->OnGestureEvent(&end_second_touch_point); 2030 EXPECT_FALSE(end_second_touch_point.handled()); 2031 EXPECT_EQ(NULL, GetGestureHandler(root_view)); 2032 2033 // If no gesture handler is set, dispatching only a ui::ET_GESTURE_END 2034 // event corresponding to the final touch point should not set the gesture 2035 // handler. Furthermore, it should not be marked as handled because it was 2036 // not dispatched (GESTURE_END events are only dispatched in cases where 2037 // a gesture handler is already set). 2038 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15); 2039 widget->OnGestureEvent(&end); 2040 EXPECT_FALSE(end.handled()); 2041 EXPECT_EQ(NULL, GetGestureHandler(root_view)); 2042 2043 // If the gesture handler has been set by a previous gesture, then it should 2044 // remain unchanged on a ui::ET_GESTURE_BEGIN or a ui::ET_GESTURE_END 2045 // corresponding to a second touch point. It should be reset to NULL by a 2046 // ui::ET_GESTURE_END corresponding to the final touch point. 2047 GestureEventForTest tap(ui::ET_GESTURE_TAP, 15, 15); 2048 widget->OnGestureEvent(&tap); 2049 EXPECT_TRUE(tap.handled()); 2050 EXPECT_EQ(view, GetGestureHandler(root_view)); 2051 2052 begin = GestureEventForTest(ui::ET_GESTURE_BEGIN, 15, 15); 2053 widget->OnGestureEvent(&begin); 2054 EXPECT_FALSE(begin.handled()); 2055 EXPECT_EQ(view, GetGestureHandler(root_view)); 2056 2057 end_second_touch_point = GestureEventForTest(details, 15, 15); 2058 widget->OnGestureEvent(&end_second_touch_point); 2059 EXPECT_FALSE(end_second_touch_point.handled()); 2060 EXPECT_EQ(view, GetGestureHandler(root_view)); 2061 2062 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15); 2063 widget->OnGestureEvent(&end); 2064 EXPECT_TRUE(end.handled()); 2065 EXPECT_EQ(NULL, GetGestureHandler(root_view)); 2066 2067 // If the gesture handler has been set by a previous gesture, then 2068 // it should remain unchanged on a ui::ET_GESTURE_BEGIN or a 2069 // ui::ET_GESTURE_END corresponding to a second touch point and be reset 2070 // to NULL by a ui::ET_GESTURE_END corresponding to the final touch point, 2071 // even when the gesture handler has indicated that it would not like to 2072 // handle any further events. 2073 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 15, 15); 2074 widget->OnGestureEvent(&tap); 2075 EXPECT_TRUE(tap.handled()); 2076 EXPECT_EQ(view, GetGestureHandler(root_view)); 2077 2078 // Change the handle mode of |view| to indicate that it does not want 2079 // to handle any further events. 2080 view->set_handle_mode(EventCountView::PROPAGATE_EVENTS); 2081 2082 begin = GestureEventForTest(ui::ET_GESTURE_BEGIN, 15, 15); 2083 widget->OnGestureEvent(&begin); 2084 EXPECT_FALSE(begin.handled()); 2085 EXPECT_EQ(view, GetGestureHandler(root_view)); 2086 2087 end_second_touch_point = GestureEventForTest(details, 15, 15); 2088 widget->OnGestureEvent(&end_second_touch_point); 2089 EXPECT_FALSE(end_second_touch_point.handled()); 2090 EXPECT_EQ(view, GetGestureHandler(root_view)); 2091 2092 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15); 2093 widget->OnGestureEvent(&end); 2094 EXPECT_FALSE(end.handled()); 2095 EXPECT_EQ(NULL, GetGestureHandler(root_view)); 2096 2097 widget->Close(); 2098 } 2099 2100 // Tests that a (non-scroll) gesture event is dispatched to the correct views 2101 // in a view hierarchy and that the default gesture handler in RootView is set 2102 // correctly. 2103 TEST_F(WidgetTest, GestureEventDispatch) { 2104 Widget* widget = CreateTopLevelNativeWidget(); 2105 widget->SetBounds(gfx::Rect(0, 0, 300, 300)); 2106 2107 // Define a hierarchy of four views (coordinates are in 2108 // their parent coordinate space). 2109 // v1 (0, 0, 300, 300) 2110 // v2 (0, 0, 100, 100) 2111 // v3 (0, 0, 50, 50) 2112 // v4(0, 0, 10, 10) 2113 EventCountView* v1 = new EventCountView(); 2114 v1->SetBounds(0, 0, 300, 300); 2115 EventCountView* v2 = new EventCountView(); 2116 v2->SetBounds(0, 0, 100, 100); 2117 EventCountView* v3 = new EventCountView(); 2118 v3->SetBounds(0, 0, 50, 50); 2119 EventCountView* v4 = new EventCountView(); 2120 v4->SetBounds(0, 0, 10, 10); 2121 internal::RootView* root_view = 2122 static_cast<internal::RootView*>(widget->GetRootView()); 2123 root_view->AddChildView(v1); 2124 v1->AddChildView(v2); 2125 v2->AddChildView(v3); 2126 v3->AddChildView(v4); 2127 2128 widget->Show(); 2129 2130 // No gesture handler is set in the root view and none of the views in the 2131 // view hierarchy handle a ui::ET_GESTURE_TAP event. In this case the tap 2132 // event should be dispatched to all views in the hierarchy, the gesture 2133 // handler should remain unset, and the event should remain unhandled. 2134 GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5); 2135 EXPECT_EQ(NULL, GetGestureHandler(root_view)); 2136 widget->OnGestureEvent(&tap); 2137 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_TAP)); 2138 EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_TAP)); 2139 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP)); 2140 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP)); 2141 EXPECT_EQ(NULL, GetGestureHandler(root_view)); 2142 EXPECT_FALSE(tap.handled()); 2143 2144 // No gesture handler is set in the root view and |v1|, |v2|, and |v3| all 2145 // handle a ui::ET_GESTURE_TAP event. In this case the tap event should be 2146 // dispatched to |v4| and |v3|, the gesture handler should be set to |v3|, 2147 // and the event should be marked as handled. 2148 v1->ResetCounts(); 2149 v2->ResetCounts(); 2150 v3->ResetCounts(); 2151 v4->ResetCounts(); 2152 v1->set_handle_mode(EventCountView::CONSUME_EVENTS); 2153 v2->set_handle_mode(EventCountView::CONSUME_EVENTS); 2154 v3->set_handle_mode(EventCountView::CONSUME_EVENTS); 2155 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5); 2156 widget->OnGestureEvent(&tap); 2157 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP)); 2158 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP)); 2159 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP)); 2160 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP)); 2161 EXPECT_EQ(v3, GetGestureHandler(root_view)); 2162 EXPECT_TRUE(tap.handled()); 2163 2164 // The gesture handler is set to |v3| and all views handle all gesture event 2165 // types. In this case subsequent gesture events should only be dispatched to 2166 // |v3| and marked as handled. The gesture handler should remain as |v3|. 2167 v1->ResetCounts(); 2168 v2->ResetCounts(); 2169 v3->ResetCounts(); 2170 v4->ResetCounts(); 2171 v4->set_handle_mode(EventCountView::CONSUME_EVENTS); 2172 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5); 2173 widget->OnGestureEvent(&tap); 2174 EXPECT_TRUE(tap.handled()); 2175 GestureEventForTest show_press(ui::ET_GESTURE_SHOW_PRESS, 5, 5); 2176 widget->OnGestureEvent(&show_press); 2177 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5); 2178 widget->OnGestureEvent(&tap); 2179 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP)); 2180 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP)); 2181 EXPECT_EQ(2, v3->GetEventCount(ui::ET_GESTURE_TAP)); 2182 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP)); 2183 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SHOW_PRESS)); 2184 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SHOW_PRESS)); 2185 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SHOW_PRESS)); 2186 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SHOW_PRESS)); 2187 EXPECT_TRUE(tap.handled()); 2188 EXPECT_TRUE(show_press.handled()); 2189 EXPECT_EQ(v3, GetGestureHandler(root_view)); 2190 2191 // The gesture handler is set to |v3|, but |v3| does not handle 2192 // ui::ET_GESTURE_TAP events. In this case a tap gesture should be dispatched 2193 // only to |v3|, but the event should remain unhandled. The gesture handler 2194 // should remain as |v3|. 2195 v1->ResetCounts(); 2196 v2->ResetCounts(); 2197 v3->ResetCounts(); 2198 v4->ResetCounts(); 2199 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS); 2200 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5); 2201 widget->OnGestureEvent(&tap); 2202 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP)); 2203 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP)); 2204 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP)); 2205 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP)); 2206 EXPECT_FALSE(tap.handled()); 2207 EXPECT_EQ(v3, GetGestureHandler(root_view)); 2208 2209 widget->Close(); 2210 } 2211 2212 // Tests that gesture scroll events will change the default gesture handler in 2213 // RootView if the current handler to which they are dispatched does not handle 2214 // gesture scroll events. 2215 TEST_F(WidgetTest, ScrollGestureEventDispatch) { 2216 Widget* widget = CreateTopLevelNativeWidget(); 2217 widget->SetBounds(gfx::Rect(0, 0, 300, 300)); 2218 2219 // Define a hierarchy of four views (coordinates are in 2220 // their parent coordinate space). 2221 // v1 (0, 0, 300, 300) 2222 // v2 (0, 0, 100, 100) 2223 // v3 (0, 0, 50, 50) 2224 // v4(0, 0, 10, 10) 2225 EventCountView* v1 = new EventCountView(); 2226 v1->SetBounds(0, 0, 300, 300); 2227 EventCountView* v2 = new EventCountView(); 2228 v2->SetBounds(0, 0, 100, 100); 2229 EventCountView* v3 = new EventCountView(); 2230 v3->SetBounds(0, 0, 50, 50); 2231 EventCountView* v4 = new EventCountView(); 2232 v4->SetBounds(0, 0, 10, 10); 2233 internal::RootView* root_view = 2234 static_cast<internal::RootView*>(widget->GetRootView()); 2235 root_view->AddChildView(v1); 2236 v1->AddChildView(v2); 2237 v2->AddChildView(v3); 2238 v3->AddChildView(v4); 2239 2240 widget->Show(); 2241 2242 // Change the handle mode of |v3| to indicate that it would like to handle 2243 // gesture events. 2244 v3->set_handle_mode(EventCountView::CONSUME_EVENTS); 2245 2246 // When no gesture handler is set, dispatching a ui::ET_GESTURE_TAP_DOWN 2247 // should bubble up the views hierarchy until it reaches the first view 2248 // that will handle it (|v3|) and then sets the handler to |v3|. 2249 EXPECT_EQ(NULL, GetGestureHandler(root_view)); 2250 GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, 5, 5); 2251 widget->OnGestureEvent(&tap_down); 2252 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_DOWN)); 2253 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_DOWN)); 2254 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_DOWN)); 2255 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP_DOWN)); 2256 EXPECT_EQ(v3, GetGestureHandler(root_view)); 2257 EXPECT_TRUE(tap_down.handled()); 2258 v1->ResetCounts(); 2259 v2->ResetCounts(); 2260 v3->ResetCounts(); 2261 v4->ResetCounts(); 2262 2263 // A ui::ET_GESTURE_TAP_CANCEL event should be dispatched to |v3| directly. 2264 GestureEventForTest tap_cancel(ui::ET_GESTURE_TAP_CANCEL, 5, 5); 2265 widget->OnGestureEvent(&tap_cancel); 2266 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_CANCEL)); 2267 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_CANCEL)); 2268 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_CANCEL)); 2269 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP_CANCEL)); 2270 EXPECT_EQ(v3, GetGestureHandler(root_view)); 2271 EXPECT_TRUE(tap_cancel.handled()); 2272 v1->ResetCounts(); 2273 v2->ResetCounts(); 2274 v3->ResetCounts(); 2275 v4->ResetCounts(); 2276 2277 // Change the handle mode of |v3| to indicate that it would no longer like 2278 // to handle events, and change the mode of |v1| to indicate that it would 2279 // like to handle events. 2280 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS); 2281 v1->set_handle_mode(EventCountView::CONSUME_EVENTS); 2282 2283 // Dispatch a ui::ET_GESTURE_SCROLL_BEGIN event. Because the current gesture 2284 // handler (|v3|) does not handle scroll events, the event should bubble up 2285 // the views hierarchy until it reaches the first view that will handle 2286 // it (|v1|) and then sets the handler to |v1|. 2287 GestureEventForTest scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN, 5, 5); 2288 widget->OnGestureEvent(&scroll_begin); 2289 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN)); 2290 EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN)); 2291 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN)); 2292 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN)); 2293 EXPECT_EQ(v1, GetGestureHandler(root_view)); 2294 EXPECT_TRUE(scroll_begin.handled()); 2295 v1->ResetCounts(); 2296 v2->ResetCounts(); 2297 v3->ResetCounts(); 2298 v4->ResetCounts(); 2299 2300 // A ui::ET_GESTURE_SCROLL_UPDATE event should be dispatched to |v1| 2301 // directly. 2302 GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, 5, 5); 2303 widget->OnGestureEvent(&scroll_update); 2304 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE)); 2305 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE)); 2306 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE)); 2307 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE)); 2308 EXPECT_EQ(v1, GetGestureHandler(root_view)); 2309 EXPECT_TRUE(scroll_update.handled()); 2310 v1->ResetCounts(); 2311 v2->ResetCounts(); 2312 v3->ResetCounts(); 2313 v4->ResetCounts(); 2314 2315 // A ui::ET_GESTURE_SCROLL_END event should be dispatched to |v1| 2316 // directly and should not reset the gesture handler. 2317 GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, 5, 5); 2318 widget->OnGestureEvent(&scroll_end); 2319 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_END)); 2320 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_END)); 2321 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_END)); 2322 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_END)); 2323 EXPECT_EQ(v1, GetGestureHandler(root_view)); 2324 EXPECT_TRUE(scroll_end.handled()); 2325 v1->ResetCounts(); 2326 v2->ResetCounts(); 2327 v3->ResetCounts(); 2328 v4->ResetCounts(); 2329 2330 // A ui::ET_GESTURE_PINCH_BEGIN event (which is a non-scroll event) should 2331 // still be dispatched to |v1| directly. 2332 GestureEventForTest pinch_begin(ui::ET_GESTURE_PINCH_BEGIN, 5, 5); 2333 widget->OnGestureEvent(&pinch_begin); 2334 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN)); 2335 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN)); 2336 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN)); 2337 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN)); 2338 EXPECT_EQ(v1, GetGestureHandler(root_view)); 2339 EXPECT_TRUE(pinch_begin.handled()); 2340 v1->ResetCounts(); 2341 v2->ResetCounts(); 2342 v3->ResetCounts(); 2343 v4->ResetCounts(); 2344 2345 // A ui::ET_GESTURE_END event should be dispatched to |v1| and should 2346 // set the gesture handler to NULL. 2347 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5); 2348 widget->OnGestureEvent(&end); 2349 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_END)); 2350 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END)); 2351 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END)); 2352 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END)); 2353 EXPECT_EQ(NULL, GetGestureHandler(root_view)); 2354 EXPECT_TRUE(end.handled()); 2355 2356 widget->Close(); 2357 } 2358 2359 // A class used in WidgetTest.GestureEventLocationWhileBubbling to verify 2360 // that when a gesture event bubbles up a View hierarchy, the location 2361 // of a gesture event seen by each View is in the local coordinate space 2362 // of that View. 2363 class GestureLocationView : public EventCountView { 2364 public: 2365 GestureLocationView() {} 2366 virtual ~GestureLocationView() {} 2367 2368 void set_expected_location(gfx::Point expected_location) { 2369 expected_location_ = expected_location; 2370 } 2371 2372 // EventCountView: 2373 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { 2374 EventCountView::OnGestureEvent(event); 2375 2376 // Verify that the location of |event| is in the local coordinate 2377 // space of |this|. 2378 EXPECT_EQ(expected_location_, event->location()); 2379 } 2380 2381 private: 2382 // The expected location of a gesture event dispatched to |this|. 2383 gfx::Point expected_location_; 2384 2385 DISALLOW_COPY_AND_ASSIGN(GestureLocationView); 2386 }; 2387 2388 // Verifies that the location of a gesture event is always in the local 2389 // coordinate space of the View receiving the event while bubbling. 2390 TEST_F(WidgetTest, GestureEventLocationWhileBubbling) { 2391 Widget* widget = CreateTopLevelNativeWidget(); 2392 widget->SetBounds(gfx::Rect(0, 0, 300, 300)); 2393 2394 // Define a hierarchy of three views (coordinates shown below are in the 2395 // coordinate space of the root view, but the coordinates used for 2396 // SetBounds() are in their parent coordinate space). 2397 // v1 (50, 50, 150, 150) 2398 // v2 (100, 70, 50, 80) 2399 // v3 (120, 100, 10, 10) 2400 GestureLocationView* v1 = new GestureLocationView(); 2401 v1->SetBounds(50, 50, 150, 150); 2402 GestureLocationView* v2 = new GestureLocationView(); 2403 v2->SetBounds(50, 20, 50, 80); 2404 GestureLocationView* v3 = new GestureLocationView(); 2405 v3->SetBounds(20, 30, 10, 10); 2406 internal::RootView* root_view = 2407 static_cast<internal::RootView*>(widget->GetRootView()); 2408 root_view->AddChildView(v1); 2409 v1->AddChildView(v2); 2410 v2->AddChildView(v3); 2411 2412 widget->Show(); 2413 2414 // Define a GESTURE_TAP event located at (125, 105) in root view coordinates. 2415 // This event is contained within all of |v1|, |v2|, and |v3|. 2416 gfx::Point location_in_root(125, 105); 2417 GestureEventForTest tap( 2418 ui::ET_GESTURE_TAP, location_in_root.x(), location_in_root.y()); 2419 2420 // Calculate the location of the event in the local coordinate spaces 2421 // of each of the views. 2422 gfx::Point location_in_v1(ConvertPointFromWidgetToView(v1, location_in_root)); 2423 EXPECT_EQ(gfx::Point(75, 55), location_in_v1); 2424 gfx::Point location_in_v2(ConvertPointFromWidgetToView(v2, location_in_root)); 2425 EXPECT_EQ(gfx::Point(25, 35), location_in_v2); 2426 gfx::Point location_in_v3(ConvertPointFromWidgetToView(v3, location_in_root)); 2427 EXPECT_EQ(gfx::Point(5, 5), location_in_v3); 2428 2429 // Dispatch the event. When each view receives the event, its location should 2430 // be in the local coordinate space of that view (see the check made by 2431 // GestureLocationView). After dispatch is complete the event's location 2432 // should be in the root coordinate space. 2433 v1->set_expected_location(location_in_v1); 2434 v2->set_expected_location(location_in_v2); 2435 v3->set_expected_location(location_in_v3); 2436 widget->OnGestureEvent(&tap); 2437 EXPECT_EQ(location_in_root, tap.location()); 2438 2439 // Verify that each view did in fact see the event. 2440 EventCountView* view1 = v1; 2441 EventCountView* view2 = v2; 2442 EventCountView* view3 = v3; 2443 EXPECT_EQ(1, view1->GetEventCount(ui::ET_GESTURE_TAP)); 2444 EXPECT_EQ(1, view2->GetEventCount(ui::ET_GESTURE_TAP)); 2445 EXPECT_EQ(1, view3->GetEventCount(ui::ET_GESTURE_TAP)); 2446 2447 widget->Close(); 2448 } 2449 2450 // Verifies that disabled views are permitted to be set as the default gesture 2451 // handler in RootView. Also verifies that gesture events targeted to a disabled 2452 // view are not actually dispatched to the view, but are still marked as 2453 // handled. 2454 TEST_F(WidgetTest, DisabledGestureEventTarget) { 2455 Widget* widget = CreateTopLevelNativeWidget(); 2456 widget->SetBounds(gfx::Rect(0, 0, 300, 300)); 2457 2458 // Define a hierarchy of four views (coordinates are in 2459 // their parent coordinate space). 2460 // v1 (0, 0, 300, 300) 2461 // v2 (0, 0, 100, 100) 2462 // v3 (0, 0, 50, 50) 2463 // v4(0, 0, 10, 10) 2464 EventCountView* v1 = new EventCountView(); 2465 v1->SetBounds(0, 0, 300, 300); 2466 EventCountView* v2 = new EventCountView(); 2467 v2->SetBounds(0, 0, 100, 100); 2468 EventCountView* v3 = new EventCountView(); 2469 v3->SetBounds(0, 0, 50, 50); 2470 EventCountView* v4 = new EventCountView(); 2471 v4->SetBounds(0, 0, 10, 10); 2472 internal::RootView* root_view = 2473 static_cast<internal::RootView*>(widget->GetRootView()); 2474 root_view->AddChildView(v1); 2475 v1->AddChildView(v2); 2476 v2->AddChildView(v3); 2477 v3->AddChildView(v4); 2478 2479 widget->Show(); 2480 2481 // |v1|, |v2|, and |v3| all handle gesture events but |v3| is marked as 2482 // disabled. 2483 v1->set_handle_mode(EventCountView::CONSUME_EVENTS); 2484 v2->set_handle_mode(EventCountView::CONSUME_EVENTS); 2485 v3->set_handle_mode(EventCountView::CONSUME_EVENTS); 2486 v3->SetEnabled(false); 2487 2488 // No gesture handler is set in the root view, so it should remain unset 2489 // after a GESTURE_END. GESTURE_END events are not dispatched unless 2490 // a gesture handler is already set in the root view, so none of the 2491 // views should see this event and it should not be marked as handled. 2492 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5); 2493 widget->OnGestureEvent(&end); 2494 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END)); 2495 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END)); 2496 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END)); 2497 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END)); 2498 EXPECT_EQ(NULL, GetGestureHandler(root_view)); 2499 EXPECT_FALSE(end.handled()); 2500 v1->ResetCounts(); 2501 v2->ResetCounts(); 2502 v3->ResetCounts(); 2503 v4->ResetCounts(); 2504 2505 // No gesture handler is set in the root view. In this case the tap event 2506 // should be dispatched only to |v4|, the gesture handler should be set to 2507 // |v3|, and the event should be marked as handled. 2508 GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5); 2509 widget->OnGestureEvent(&tap); 2510 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP)); 2511 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP)); 2512 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP)); 2513 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP)); 2514 EXPECT_EQ(v3, GetGestureHandler(root_view)); 2515 EXPECT_TRUE(tap.handled()); 2516 v1->ResetCounts(); 2517 v2->ResetCounts(); 2518 v3->ResetCounts(); 2519 v4->ResetCounts(); 2520 2521 // A subsequent gesture event should be marked as handled but not dispatched. 2522 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5); 2523 widget->OnGestureEvent(&tap); 2524 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP)); 2525 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP)); 2526 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP)); 2527 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP)); 2528 EXPECT_EQ(v3, GetGestureHandler(root_view)); 2529 EXPECT_TRUE(tap.handled()); 2530 v1->ResetCounts(); 2531 v2->ResetCounts(); 2532 v3->ResetCounts(); 2533 v4->ResetCounts(); 2534 2535 // A GESTURE_END should reset the default gesture handler to NULL. It should 2536 // also not be dispatched to |v3| but still marked as handled. 2537 end = GestureEventForTest(ui::ET_GESTURE_END, 5, 5); 2538 widget->OnGestureEvent(&end); 2539 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END)); 2540 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END)); 2541 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END)); 2542 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END)); 2543 EXPECT_EQ(NULL, GetGestureHandler(root_view)); 2544 EXPECT_TRUE(end.handled()); 2545 v1->ResetCounts(); 2546 v2->ResetCounts(); 2547 v3->ResetCounts(); 2548 v4->ResetCounts(); 2549 2550 // Change the handle mode of |v3| to indicate that it would no longer like 2551 // to handle events which are dispatched to it. 2552 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS); 2553 2554 // No gesture handler is set in the root view. In this case the tap event 2555 // should be dispatched only to |v4| and the event should be marked as 2556 // handled. Furthermore, the gesture handler should be set to 2557 // |v3|; even though |v3| does not explicitly handle events, it is a 2558 // valid target for the tap event because it is disabled. 2559 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5); 2560 widget->OnGestureEvent(&tap); 2561 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP)); 2562 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP)); 2563 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP)); 2564 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP)); 2565 EXPECT_EQ(v3, GetGestureHandler(root_view)); 2566 EXPECT_TRUE(tap.handled()); 2567 v1->ResetCounts(); 2568 v2->ResetCounts(); 2569 v3->ResetCounts(); 2570 v4->ResetCounts(); 2571 2572 // A GESTURE_END should reset the default gesture handler to NULL. It should 2573 // also not be dispatched to |v3| but still marked as handled. 2574 end = GestureEventForTest(ui::ET_GESTURE_END, 5, 5); 2575 widget->OnGestureEvent(&end); 2576 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END)); 2577 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END)); 2578 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END)); 2579 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END)); 2580 EXPECT_EQ(NULL, GetGestureHandler(root_view)); 2581 EXPECT_TRUE(end.handled()); 2582 2583 widget->Close(); 2584 } 2585 2586 // Test the result of Widget::GetAllChildWidgets(). 2587 TEST_F(WidgetTest, GetAllChildWidgets) { 2588 // Create the following widget hierarchy: 2589 // 2590 // toplevel 2591 // +-- w1 2592 // +-- w11 2593 // +-- w2 2594 // +-- w21 2595 // +-- w22 2596 Widget* toplevel = CreateTopLevelPlatformWidget(); 2597 Widget* w1 = CreateChildPlatformWidget(toplevel->GetNativeView()); 2598 Widget* w11 = CreateChildPlatformWidget(w1->GetNativeView()); 2599 Widget* w2 = CreateChildPlatformWidget(toplevel->GetNativeView()); 2600 Widget* w21 = CreateChildPlatformWidget(w2->GetNativeView()); 2601 Widget* w22 = CreateChildPlatformWidget(w2->GetNativeView()); 2602 2603 std::set<Widget*> expected; 2604 expected.insert(toplevel); 2605 expected.insert(w1); 2606 expected.insert(w11); 2607 expected.insert(w2); 2608 expected.insert(w21); 2609 expected.insert(w22); 2610 2611 std::set<Widget*> widgets; 2612 Widget::GetAllChildWidgets(toplevel->GetNativeView(), &widgets); 2613 2614 EXPECT_EQ(expected.size(), widgets.size()); 2615 EXPECT_TRUE(std::equal(expected.begin(), expected.end(), widgets.begin())); 2616 } 2617 2618 // Used by DestroyChildWidgetsInOrder. On destruction adds the supplied name to 2619 // a vector. 2620 class DestroyedTrackingView : public View { 2621 public: 2622 DestroyedTrackingView(const std::string& name, 2623 std::vector<std::string>* add_to) 2624 : name_(name), 2625 add_to_(add_to) { 2626 } 2627 2628 virtual ~DestroyedTrackingView() { 2629 add_to_->push_back(name_); 2630 } 2631 2632 private: 2633 const std::string name_; 2634 std::vector<std::string>* add_to_; 2635 2636 DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingView); 2637 }; 2638 2639 class WidgetChildDestructionTest : public WidgetTest { 2640 public: 2641 WidgetChildDestructionTest() {} 2642 2643 // Creates a top level and a child, destroys the child and verifies the views 2644 // of the child are destroyed before the views of the parent. 2645 void RunDestroyChildWidgetsTest(bool top_level_has_desktop_native_widget_aura, 2646 bool child_has_desktop_native_widget_aura) { 2647 // When a View is destroyed its name is added here. 2648 std::vector<std::string> destroyed; 2649 2650 Widget* top_level = new Widget; 2651 Widget::InitParams params = 2652 CreateParams(views::Widget::InitParams::TYPE_WINDOW); 2653 #if !defined(OS_CHROMEOS) 2654 if (top_level_has_desktop_native_widget_aura) 2655 params.native_widget = new PlatformDesktopNativeWidget(top_level); 2656 #endif 2657 top_level->Init(params); 2658 top_level->GetRootView()->AddChildView( 2659 new DestroyedTrackingView("parent", &destroyed)); 2660 top_level->Show(); 2661 2662 Widget* child = new Widget; 2663 Widget::InitParams child_params = 2664 CreateParams(views::Widget::InitParams::TYPE_POPUP); 2665 child_params.parent = top_level->GetNativeView(); 2666 #if !defined(OS_CHROMEOS) 2667 if (child_has_desktop_native_widget_aura) 2668 child_params.native_widget = new PlatformDesktopNativeWidget(child); 2669 #endif 2670 child->Init(child_params); 2671 child->GetRootView()->AddChildView( 2672 new DestroyedTrackingView("child", &destroyed)); 2673 child->Show(); 2674 2675 // Should trigger destruction of the child too. 2676 top_level->native_widget_private()->CloseNow(); 2677 2678 // Child should be destroyed first. 2679 ASSERT_EQ(2u, destroyed.size()); 2680 EXPECT_EQ("child", destroyed[0]); 2681 EXPECT_EQ("parent", destroyed[1]); 2682 } 2683 2684 private: 2685 DISALLOW_COPY_AND_ASSIGN(WidgetChildDestructionTest); 2686 }; 2687 2688 #if !defined(OS_CHROMEOS) 2689 // See description of RunDestroyChildWidgetsTest(). Parent uses 2690 // DesktopNativeWidgetAura. 2691 TEST_F(WidgetChildDestructionTest, 2692 DestroyChildWidgetsInOrderWithDesktopNativeWidget) { 2693 RunDestroyChildWidgetsTest(true, false); 2694 } 2695 2696 // See description of RunDestroyChildWidgetsTest(). Both parent and child use 2697 // DesktopNativeWidgetAura. 2698 TEST_F(WidgetChildDestructionTest, 2699 DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth) { 2700 RunDestroyChildWidgetsTest(true, true); 2701 } 2702 #endif // !defined(OS_CHROMEOS) 2703 2704 // See description of RunDestroyChildWidgetsTest(). 2705 TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) { 2706 RunDestroyChildWidgetsTest(false, false); 2707 } 2708 2709 #if !defined(OS_CHROMEOS) 2710 // Provides functionality to create a window modal dialog. 2711 class ModalDialogDelegate : public DialogDelegateView { 2712 public: 2713 ModalDialogDelegate() {} 2714 virtual ~ModalDialogDelegate() {} 2715 2716 // WidgetDelegate overrides. 2717 virtual ui::ModalType GetModalType() const OVERRIDE { 2718 return ui::MODAL_TYPE_WINDOW; 2719 } 2720 2721 private: 2722 DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate); 2723 }; 2724 2725 // This test verifies that whether mouse events when a modal dialog is 2726 // displayed are eaten or recieved by the dialog. 2727 TEST_F(WidgetTest, WindowMouseModalityTest) { 2728 // Create a top level widget. 2729 Widget top_level_widget; 2730 Widget::InitParams init_params = 2731 CreateParams(Widget::InitParams::TYPE_WINDOW); 2732 init_params.show_state = ui::SHOW_STATE_NORMAL; 2733 gfx::Rect initial_bounds(0, 0, 500, 500); 2734 init_params.bounds = initial_bounds; 2735 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 2736 init_params.native_widget = 2737 new PlatformDesktopNativeWidget(&top_level_widget); 2738 top_level_widget.Init(init_params); 2739 top_level_widget.Show(); 2740 EXPECT_TRUE(top_level_widget.IsVisible()); 2741 2742 // Create a view and validate that a mouse moves makes it to the view. 2743 EventCountView* widget_view = new EventCountView(); 2744 widget_view->SetBounds(0, 0, 10, 10); 2745 top_level_widget.GetRootView()->AddChildView(widget_view); 2746 2747 gfx::Point cursor_location_main(5, 5); 2748 ui::MouseEvent move_main(ui::ET_MOUSE_MOVED, 2749 cursor_location_main, 2750 cursor_location_main, 2751 ui::EF_NONE, 2752 ui::EF_NONE); 2753 ui::EventDispatchDetails details = 2754 GetEventProcessor(&top_level_widget)->OnEventFromSource(&move_main); 2755 ASSERT_FALSE(details.dispatcher_destroyed); 2756 2757 EXPECT_EQ(1, widget_view->GetEventCount(ui::ET_MOUSE_ENTERED)); 2758 widget_view->ResetCounts(); 2759 2760 // Create a modal dialog and validate that a mouse down message makes it to 2761 // the main view within the dialog. 2762 2763 // This instance will be destroyed when the dialog is destroyed. 2764 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate; 2765 2766 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget( 2767 dialog_delegate, NULL, top_level_widget.GetNativeView()); 2768 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200)); 2769 EventCountView* dialog_widget_view = new EventCountView(); 2770 dialog_widget_view->SetBounds(0, 0, 50, 50); 2771 modal_dialog_widget->GetRootView()->AddChildView(dialog_widget_view); 2772 modal_dialog_widget->Show(); 2773 EXPECT_TRUE(modal_dialog_widget->IsVisible()); 2774 2775 gfx::Point cursor_location_dialog(100, 100); 2776 ui::MouseEvent mouse_down_dialog(ui::ET_MOUSE_PRESSED, 2777 cursor_location_dialog, 2778 cursor_location_dialog, 2779 ui::EF_NONE, 2780 ui::EF_NONE); 2781 details = GetEventProcessor(&top_level_widget)->OnEventFromSource( 2782 &mouse_down_dialog); 2783 ASSERT_FALSE(details.dispatcher_destroyed); 2784 EXPECT_EQ(1, dialog_widget_view->GetEventCount(ui::ET_MOUSE_PRESSED)); 2785 2786 // Send a mouse move message to the main window. It should not be received by 2787 // the main window as the modal dialog is still active. 2788 gfx::Point cursor_location_main2(6, 6); 2789 ui::MouseEvent mouse_down_main(ui::ET_MOUSE_MOVED, 2790 cursor_location_main2, 2791 cursor_location_main2, 2792 ui::EF_NONE, 2793 ui::EF_NONE); 2794 details = GetEventProcessor(&top_level_widget)->OnEventFromSource( 2795 &mouse_down_main); 2796 ASSERT_FALSE(details.dispatcher_destroyed); 2797 EXPECT_EQ(0, widget_view->GetEventCount(ui::ET_MOUSE_MOVED)); 2798 2799 modal_dialog_widget->CloseNow(); 2800 top_level_widget.CloseNow(); 2801 } 2802 2803 // Verifies nativeview visbility matches that of Widget visibility when 2804 // SetFullscreen is invoked. 2805 TEST_F(WidgetTest, FullscreenStatePropagated) { 2806 Widget::InitParams init_params = 2807 CreateParams(Widget::InitParams::TYPE_WINDOW); 2808 init_params.show_state = ui::SHOW_STATE_NORMAL; 2809 init_params.bounds = gfx::Rect(0, 0, 500, 500); 2810 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 2811 2812 { 2813 Widget top_level_widget; 2814 top_level_widget.Init(init_params); 2815 top_level_widget.SetFullscreen(true); 2816 EXPECT_EQ(top_level_widget.IsVisible(), 2817 IsNativeWindowVisible(top_level_widget.GetNativeWindow())); 2818 top_level_widget.CloseNow(); 2819 } 2820 #if !defined(OS_CHROMEOS) 2821 { 2822 Widget top_level_widget; 2823 init_params.native_widget = 2824 new PlatformDesktopNativeWidget(&top_level_widget); 2825 top_level_widget.Init(init_params); 2826 top_level_widget.SetFullscreen(true); 2827 EXPECT_EQ(top_level_widget.IsVisible(), 2828 IsNativeWindowVisible(top_level_widget.GetNativeWindow())); 2829 top_level_widget.CloseNow(); 2830 } 2831 #endif 2832 } 2833 #if defined(OS_WIN) 2834 2835 // Provides functionality to test widget activation via an activation flag 2836 // which can be set by an accessor. 2837 class ModalWindowTestWidgetDelegate : public WidgetDelegate { 2838 public: 2839 ModalWindowTestWidgetDelegate() 2840 : widget_(NULL), 2841 can_activate_(true) {} 2842 2843 virtual ~ModalWindowTestWidgetDelegate() {} 2844 2845 // Overridden from WidgetDelegate: 2846 virtual void DeleteDelegate() OVERRIDE { 2847 delete this; 2848 } 2849 virtual Widget* GetWidget() OVERRIDE { 2850 return widget_; 2851 } 2852 virtual const Widget* GetWidget() const OVERRIDE { 2853 return widget_; 2854 } 2855 virtual bool CanActivate() const OVERRIDE { 2856 return can_activate_; 2857 } 2858 virtual bool ShouldAdvanceFocusToTopLevelWidget() const OVERRIDE { 2859 return true; 2860 } 2861 2862 void set_can_activate(bool can_activate) { 2863 can_activate_ = can_activate; 2864 } 2865 2866 void set_widget(Widget* widget) { 2867 widget_ = widget; 2868 } 2869 2870 private: 2871 Widget* widget_; 2872 bool can_activate_; 2873 2874 DISALLOW_COPY_AND_ASSIGN(ModalWindowTestWidgetDelegate); 2875 }; 2876 2877 // Tests whether we can activate the top level widget when a modal dialog is 2878 // active. 2879 TEST_F(WidgetTest, WindowModalityActivationTest) { 2880 // Destroyed when the top level widget created below is destroyed. 2881 ModalWindowTestWidgetDelegate* widget_delegate = 2882 new ModalWindowTestWidgetDelegate; 2883 // Create a top level widget. 2884 Widget top_level_widget; 2885 Widget::InitParams init_params = 2886 CreateParams(Widget::InitParams::TYPE_WINDOW); 2887 init_params.show_state = ui::SHOW_STATE_NORMAL; 2888 gfx::Rect initial_bounds(0, 0, 500, 500); 2889 init_params.bounds = initial_bounds; 2890 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 2891 init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget); 2892 init_params.delegate = widget_delegate; 2893 top_level_widget.Init(init_params); 2894 widget_delegate->set_widget(&top_level_widget); 2895 top_level_widget.Show(); 2896 EXPECT_TRUE(top_level_widget.IsVisible()); 2897 2898 HWND win32_window = views::HWNDForWidget(&top_level_widget); 2899 EXPECT_TRUE(::IsWindow(win32_window)); 2900 2901 // This instance will be destroyed when the dialog is destroyed. 2902 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate; 2903 2904 // We should be able to activate the window even if the WidgetDelegate 2905 // says no, when a modal dialog is active. 2906 widget_delegate->set_can_activate(false); 2907 2908 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget( 2909 dialog_delegate, NULL, top_level_widget.GetNativeWindow()); 2910 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200)); 2911 modal_dialog_widget->Show(); 2912 EXPECT_TRUE(modal_dialog_widget->IsVisible()); 2913 2914 LRESULT activate_result = ::SendMessage( 2915 win32_window, 2916 WM_MOUSEACTIVATE, 2917 reinterpret_cast<WPARAM>(win32_window), 2918 MAKELPARAM(WM_LBUTTONDOWN, HTCLIENT)); 2919 EXPECT_EQ(activate_result, MA_ACTIVATE); 2920 2921 modal_dialog_widget->CloseNow(); 2922 top_level_widget.CloseNow(); 2923 } 2924 #endif // defined(OS_WIN) 2925 #endif // !defined(OS_CHROMEOS) 2926 2927 TEST_F(WidgetTest, ShowCreatesActiveWindow) { 2928 Widget* widget = CreateTopLevelPlatformWidget(); 2929 2930 widget->Show(); 2931 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL); 2932 2933 widget->CloseNow(); 2934 } 2935 2936 // OSX does not have a per-application "active" window such as provided by 2937 // ::GetActiveWindow() on Windows. There is only a system-wide "keyWindow" which 2938 // is updated asynchronously. 2939 #if defined(OS_MACOSX) 2940 #define MAYBE_ShowInactive DISABLED_ShowInactive 2941 #else 2942 #define MAYBE_ShowInactive ShowInactive 2943 #endif 2944 TEST_F(WidgetTest, MAYBE_ShowInactive) { 2945 Widget* widget = CreateTopLevelPlatformWidget(); 2946 2947 widget->ShowInactive(); 2948 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_INACTIVE); 2949 2950 widget->CloseNow(); 2951 } 2952 2953 TEST_F(WidgetTest, InactiveBeforeShow) { 2954 Widget* widget = CreateTopLevelPlatformWidget(); 2955 2956 EXPECT_FALSE(widget->IsActive()); 2957 EXPECT_FALSE(widget->IsVisible()); 2958 2959 widget->Show(); 2960 2961 EXPECT_TRUE(widget->IsActive()); 2962 EXPECT_TRUE(widget->IsVisible()); 2963 2964 widget->CloseNow(); 2965 } 2966 2967 TEST_F(WidgetTest, ShowInactiveAfterShow) { 2968 // Create 2 widgets to ensure window layering does not change. 2969 Widget* widget = CreateTopLevelPlatformWidget(); 2970 Widget* widget2 = CreateTopLevelPlatformWidget(); 2971 2972 widget2->Show(); 2973 EXPECT_FALSE(widget->IsActive()); 2974 EXPECT_TRUE(widget2->IsVisible()); 2975 EXPECT_TRUE(widget2->IsActive()); 2976 2977 widget->Show(); 2978 EXPECT_TRUE(widget->IsActive()); 2979 EXPECT_FALSE(widget2->IsActive()); 2980 widget->ShowInactive(); 2981 EXPECT_TRUE(widget->IsActive()); 2982 EXPECT_FALSE(widget2->IsActive()); 2983 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL); 2984 2985 widget2->CloseNow(); 2986 widget->CloseNow(); 2987 } 2988 2989 TEST_F(WidgetTest, ShowAfterShowInactive) { 2990 Widget* widget = CreateTopLevelPlatformWidget(); 2991 2992 widget->ShowInactive(); 2993 widget->Show(); 2994 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL); 2995 2996 widget->CloseNow(); 2997 } 2998 2999 #if !defined(OS_CHROMEOS) 3000 TEST_F(WidgetTest, InactiveWidgetDoesNotGrabActivation) { 3001 Widget* widget = CreateTopLevelPlatformWidget(); 3002 widget->Show(); 3003 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL); 3004 3005 Widget widget2; 3006 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 3007 params.native_widget = new PlatformDesktopNativeWidget(&widget2); 3008 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 3009 widget2.Init(params); 3010 widget2.Show(); 3011 3012 EXPECT_EQ(GetWidgetShowState(&widget2), ui::SHOW_STATE_INACTIVE); 3013 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL); 3014 3015 widget->CloseNow(); 3016 widget2.CloseNow(); 3017 } 3018 #endif // !defined(OS_CHROMEOS) 3019 3020 namespace { 3021 3022 class FullscreenAwareFrame : public views::NonClientFrameView { 3023 public: 3024 explicit FullscreenAwareFrame(views::Widget* widget) 3025 : widget_(widget), fullscreen_layout_called_(false) {} 3026 virtual ~FullscreenAwareFrame() {} 3027 3028 // views::NonClientFrameView overrides: 3029 virtual gfx::Rect GetBoundsForClientView() const OVERRIDE { 3030 return gfx::Rect(); 3031 } 3032 virtual gfx::Rect GetWindowBoundsForClientBounds( 3033 const gfx::Rect& client_bounds) const OVERRIDE { 3034 return gfx::Rect(); 3035 } 3036 virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE { 3037 return HTNOWHERE; 3038 } 3039 virtual void GetWindowMask(const gfx::Size& size, 3040 gfx::Path* window_mask) OVERRIDE {} 3041 virtual void ResetWindowControls() OVERRIDE {} 3042 virtual void UpdateWindowIcon() OVERRIDE {} 3043 virtual void UpdateWindowTitle() OVERRIDE {} 3044 virtual void SizeConstraintsChanged() OVERRIDE {} 3045 3046 // views::View overrides: 3047 virtual void Layout() OVERRIDE { 3048 if (widget_->IsFullscreen()) 3049 fullscreen_layout_called_ = true; 3050 } 3051 3052 bool fullscreen_layout_called() const { return fullscreen_layout_called_; } 3053 3054 private: 3055 views::Widget* widget_; 3056 bool fullscreen_layout_called_; 3057 3058 DISALLOW_COPY_AND_ASSIGN(FullscreenAwareFrame); 3059 }; 3060 3061 } // namespace 3062 3063 // Tests that frame Layout is called when a widget goes fullscreen without 3064 // changing its size or title. 3065 TEST_F(WidgetTest, FullscreenFrameLayout) { 3066 Widget* widget = CreateTopLevelPlatformWidget(); 3067 FullscreenAwareFrame* frame = new FullscreenAwareFrame(widget); 3068 widget->non_client_view()->SetFrameView(frame); // Owns |frame|. 3069 3070 widget->Maximize(); 3071 RunPendingMessages(); 3072 3073 EXPECT_FALSE(frame->fullscreen_layout_called()); 3074 widget->SetFullscreen(true); 3075 widget->Show(); 3076 RunPendingMessages(); 3077 EXPECT_TRUE(frame->fullscreen_layout_called()); 3078 3079 widget->CloseNow(); 3080 } 3081 3082 #if !defined(OS_CHROMEOS) 3083 namespace { 3084 3085 // Trivial WidgetObserverTest that invokes Widget::IsActive() from 3086 // OnWindowDestroying. 3087 class IsActiveFromDestroyObserver : public WidgetObserver { 3088 public: 3089 IsActiveFromDestroyObserver() {} 3090 virtual ~IsActiveFromDestroyObserver() {} 3091 virtual void OnWidgetDestroying(Widget* widget) OVERRIDE { 3092 widget->IsActive(); 3093 } 3094 3095 private: 3096 DISALLOW_COPY_AND_ASSIGN(IsActiveFromDestroyObserver); 3097 }; 3098 3099 } // namespace 3100 3101 // Verifies Widget::IsActive() invoked from 3102 // WidgetObserver::OnWidgetDestroying() in a child widget doesn't crash. 3103 TEST_F(WidgetTest, IsActiveFromDestroy) { 3104 // Create two widgets, one a child of the other. 3105 IsActiveFromDestroyObserver observer; 3106 Widget parent_widget; 3107 Widget::InitParams parent_params = 3108 CreateParams(Widget::InitParams::TYPE_POPUP); 3109 parent_params.native_widget = new PlatformDesktopNativeWidget(&parent_widget); 3110 parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 3111 parent_widget.Init(parent_params); 3112 parent_widget.Show(); 3113 3114 Widget child_widget; 3115 Widget::InitParams child_params = 3116 CreateParams(Widget::InitParams::TYPE_POPUP); 3117 child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 3118 child_params.context = parent_widget.GetNativeWindow(); 3119 child_widget.Init(child_params); 3120 child_widget.AddObserver(&observer); 3121 child_widget.Show(); 3122 3123 parent_widget.CloseNow(); 3124 } 3125 #endif // !defined(OS_CHROMEOS) 3126 3127 // Tests that events propagate through from the dispatcher with the correct 3128 // event type, and that the different platforms behave the same. 3129 TEST_F(WidgetTest, MouseEventTypesViaGenerator) { 3130 EventCountView* view = new EventCountView; 3131 view->set_handle_mode(EventCountView::CONSUME_EVENTS); 3132 view->SetBounds(10, 10, 50, 40); 3133 3134 Widget* widget = CreateTopLevelFramelessPlatformWidget(); 3135 widget->GetRootView()->AddChildView(view); 3136 3137 widget->SetBounds(gfx::Rect(0, 0, 100, 80)); 3138 widget->Show(); 3139 3140 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow()); 3141 generator.set_current_location(gfx::Point(20, 20)); 3142 3143 generator.ClickLeftButton(); 3144 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_PRESSED)); 3145 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED)); 3146 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags()); 3147 3148 generator.PressRightButton(); 3149 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED)); 3150 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED)); 3151 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags()); 3152 3153 generator.ReleaseRightButton(); 3154 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED)); 3155 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_RELEASED)); 3156 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags()); 3157 3158 // Test mouse move events. 3159 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_MOVED)); 3160 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_ENTERED)); 3161 3162 // Move the mouse within the view (20, 20) -> (30, 30). 3163 generator.MoveMouseTo(gfx::Point(30, 30)); 3164 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_MOVED)); 3165 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED)); 3166 EXPECT_EQ(ui::EF_NONE, view->last_flags()); 3167 3168 // Move it again - entered count shouldn't change. 3169 generator.MoveMouseTo(gfx::Point(31, 31)); 3170 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED)); 3171 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED)); 3172 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_EXITED)); 3173 3174 // Move it off the view. 3175 generator.MoveMouseTo(gfx::Point(5, 5)); 3176 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED)); 3177 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED)); 3178 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED)); 3179 3180 // Move it back on. 3181 generator.MoveMouseTo(gfx::Point(20, 20)); 3182 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_MOVED)); 3183 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_ENTERED)); 3184 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED)); 3185 3186 // Drargging. Cover HasCapture() and NativeWidgetPrivate::IsMouseButtonDown(). 3187 generator.DragMouseTo(gfx::Point(40, 40)); 3188 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_PRESSED)); 3189 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_RELEASED)); 3190 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_DRAGGED)); 3191 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags()); 3192 3193 widget->CloseNow(); 3194 } 3195 3196 // Tests that the root view is correctly set up for Widget types that do not 3197 // require a non-client view, before any other views are added to the widget. 3198 // That is, before Widget::ReorderNativeViews() is called which, if called with 3199 // a root view not set, could cause the root view to get resized to the widget. 3200 TEST_F(WidgetTest, NonClientWindowValidAfterInit) { 3201 Widget* widget = CreateTopLevelFramelessPlatformWidget(); 3202 View* root_view = widget->GetRootView(); 3203 3204 // Size the root view to exceed the widget bounds. 3205 const gfx::Rect test_rect(0, 0, 500, 500); 3206 root_view->SetBoundsRect(test_rect); 3207 3208 EXPECT_NE(test_rect.size(), widget->GetWindowBoundsInScreen().size()); 3209 3210 EXPECT_EQ(test_rect, root_view->bounds()); 3211 widget->ReorderNativeViews(); 3212 EXPECT_EQ(test_rect, root_view->bounds()); 3213 3214 widget->CloseNow(); 3215 } 3216 3217 } // namespace test 3218 } // namespace views 3219