| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/views/widget/root_view.h" | 5 #include "ui/views/widget/root_view.h" |
| 6 | 6 |
| 7 #include "base/macros.h" | 7 #include "base/macros.h" |
| 8 #include "base/memory/ptr_util.h" | 8 #include "base/memory/ptr_util.h" |
| 9 #include "ui/events/event_utils.h" | 9 #include "ui/events/event_utils.h" |
| 10 #include "ui/views/context_menu_controller.h" | 10 #include "ui/views/context_menu_controller.h" |
| (...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 371 bool view_destroyed = false; | 371 bool view_destroyed = false; |
| 372 View* child = new DeleteViewOnEvent(ui::ET_MOUSE_EXITED, &view_destroyed); | 372 View* child = new DeleteViewOnEvent(ui::ET_MOUSE_EXITED, &view_destroyed); |
| 373 content->AddChildView(child); | 373 content->AddChildView(child); |
| 374 child->SetBounds(10, 10, 500, 500); | 374 child->SetBounds(10, 10, 500, 500); |
| 375 | 375 |
| 376 internal::RootView* root_view = | 376 internal::RootView* root_view = |
| 377 static_cast<internal::RootView*>(widget.GetRootView()); | 377 static_cast<internal::RootView*>(widget.GetRootView()); |
| 378 | 378 |
| 379 // Generate a mouse move event which ensures that the mouse_moved_handler_ | 379 // Generate a mouse move event which ensures that the mouse_moved_handler_ |
| 380 // member is set in the RootView class. | 380 // member is set in the RootView class. |
| 381 ui::MouseEvent moved_event(ui::ET_MOUSE_MOVED, gfx::Point(15, 15), | 381 ui::MouseEvent moved_event( |
| 382 gfx::Point(15, 15), ui::EventTimeForNow(), 0, | 382 ui::ET_MOUSE_MOVED, gfx::Point(15, 15), gfx::Point(15, 15), |
| 383 0); | 383 ui::EventTimeForNow(), 0, 0, |
| 384 ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE)); |
| 384 root_view->OnMouseMoved(moved_event); | 385 root_view->OnMouseMoved(moved_event); |
| 385 ASSERT_FALSE(view_destroyed); | 386 ASSERT_FALSE(view_destroyed); |
| 386 | 387 |
| 387 // Generate a mouse exit event which in turn will delete the child view which | 388 // Generate a mouse exit event which in turn will delete the child view which |
| 388 // was the target of the mouse move event above. This should not crash when | 389 // was the target of the mouse move event above. This should not crash when |
| 389 // the mouse exit handler returns from the child. | 390 // the mouse exit handler returns from the child. |
| 390 ui::MouseEvent exit_event(ui::ET_MOUSE_EXITED, gfx::Point(), gfx::Point(), | 391 ui::MouseEvent exit_event( |
| 391 ui::EventTimeForNow(), 0, 0); | 392 ui::ET_MOUSE_EXITED, gfx::Point(), gfx::Point(), ui::EventTimeForNow(), 0, |
| 393 0, ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE)); |
| 392 root_view->OnMouseExited(exit_event); | 394 root_view->OnMouseExited(exit_event); |
| 393 | 395 |
| 394 EXPECT_TRUE(view_destroyed); | 396 EXPECT_TRUE(view_destroyed); |
| 395 EXPECT_FALSE(content->has_children()); | 397 EXPECT_FALSE(content->has_children()); |
| 396 } | 398 } |
| 397 | 399 |
| 398 // Verifies deleting a View in OnMouseEntered() doesn't crash. | 400 // Verifies deleting a View in OnMouseEntered() doesn't crash. |
| 399 TEST_F(RootViewTest, DeleteViewOnMouseEnterDispatch) { | 401 TEST_F(RootViewTest, DeleteViewOnMouseEnterDispatch) { |
| 400 Widget widget; | 402 Widget widget; |
| 401 Widget::InitParams init_params = | 403 Widget::InitParams init_params = |
| 402 CreateParams(Widget::InitParams::TYPE_POPUP); | 404 CreateParams(Widget::InitParams::TYPE_POPUP); |
| 403 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 405 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
| 404 widget.Init(init_params); | 406 widget.Init(init_params); |
| 405 widget.SetBounds(gfx::Rect(10, 10, 500, 500)); | 407 widget.SetBounds(gfx::Rect(10, 10, 500, 500)); |
| 406 | 408 |
| 407 View* content = new View; | 409 View* content = new View; |
| 408 widget.SetContentsView(content); | 410 widget.SetContentsView(content); |
| 409 | 411 |
| 410 bool view_destroyed = false; | 412 bool view_destroyed = false; |
| 411 View* child = new DeleteViewOnEvent(ui::ET_MOUSE_ENTERED, &view_destroyed); | 413 View* child = new DeleteViewOnEvent(ui::ET_MOUSE_ENTERED, &view_destroyed); |
| 412 content->AddChildView(child); | 414 content->AddChildView(child); |
| 413 | 415 |
| 414 // Make |child| smaller than the containing Widget and RootView. | 416 // Make |child| smaller than the containing Widget and RootView. |
| 415 child->SetBounds(100, 100, 100, 100); | 417 child->SetBounds(100, 100, 100, 100); |
| 416 | 418 |
| 417 internal::RootView* root_view = | 419 internal::RootView* root_view = |
| 418 static_cast<internal::RootView*>(widget.GetRootView()); | 420 static_cast<internal::RootView*>(widget.GetRootView()); |
| 419 | 421 |
| 420 // Move the mouse within |widget| but outside of |child|. | 422 // Move the mouse within |widget| but outside of |child|. |
| 421 ui::MouseEvent moved_event(ui::ET_MOUSE_MOVED, gfx::Point(15, 15), | 423 ui::MouseEvent moved_event( |
| 422 gfx::Point(15, 15), ui::EventTimeForNow(), 0, | 424 ui::ET_MOUSE_MOVED, gfx::Point(15, 15), gfx::Point(15, 15), |
| 423 0); | 425 ui::EventTimeForNow(), 0, 0, |
| 426 ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE)); |
| 424 root_view->OnMouseMoved(moved_event); | 427 root_view->OnMouseMoved(moved_event); |
| 425 ASSERT_FALSE(view_destroyed); | 428 ASSERT_FALSE(view_destroyed); |
| 426 | 429 |
| 427 // Move the mouse within |child|, which should dispatch a mouse enter event to | 430 // Move the mouse within |child|, which should dispatch a mouse enter event to |
| 428 // |child| and destroy the view. This should not crash when the mouse enter | 431 // |child| and destroy the view. This should not crash when the mouse enter |
| 429 // handler returns from the child. | 432 // handler returns from the child. |
| 430 ui::MouseEvent moved_event2(ui::ET_MOUSE_MOVED, gfx::Point(115, 115), | 433 ui::MouseEvent moved_event2( |
| 431 gfx::Point(115, 115), ui::EventTimeForNow(), 0, | 434 ui::ET_MOUSE_MOVED, gfx::Point(115, 115), gfx::Point(115, 115), |
| 432 0); | 435 ui::EventTimeForNow(), 0, 0, |
| 436 ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE)); |
| 433 root_view->OnMouseMoved(moved_event2); | 437 root_view->OnMouseMoved(moved_event2); |
| 434 | 438 |
| 435 EXPECT_TRUE(view_destroyed); | 439 EXPECT_TRUE(view_destroyed); |
| 436 EXPECT_FALSE(content->has_children()); | 440 EXPECT_FALSE(content->has_children()); |
| 437 } | 441 } |
| 438 | 442 |
| 439 namespace { | 443 namespace { |
| 440 | 444 |
| 441 // View class which deletes its owning Widget when it gets a mouse exit event. | 445 // View class which deletes its owning Widget when it gets a mouse exit event. |
| 442 class DeleteWidgetOnMouseExit : public View { | 446 class DeleteWidgetOnMouseExit : public View { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 475 content->AddChildView(child); | 479 content->AddChildView(child); |
| 476 widget->SetContentsView(content); | 480 widget->SetContentsView(content); |
| 477 | 481 |
| 478 // Make |child| smaller than the containing Widget and RootView. | 482 // Make |child| smaller than the containing Widget and RootView. |
| 479 child->SetBounds(100, 100, 100, 100); | 483 child->SetBounds(100, 100, 100, 100); |
| 480 | 484 |
| 481 internal::RootView* root_view = | 485 internal::RootView* root_view = |
| 482 static_cast<internal::RootView*>(widget->GetRootView()); | 486 static_cast<internal::RootView*>(widget->GetRootView()); |
| 483 | 487 |
| 484 // Move the mouse within |child|. | 488 // Move the mouse within |child|. |
| 485 ui::MouseEvent moved_event(ui::ET_MOUSE_MOVED, gfx::Point(115, 115), | 489 ui::MouseEvent moved_event( |
| 486 gfx::Point(115, 115), ui::EventTimeForNow(), 0, | 490 ui::ET_MOUSE_MOVED, gfx::Point(115, 115), gfx::Point(115, 115), |
| 487 0); | 491 ui::EventTimeForNow(), 0, 0, |
| 492 ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE)); |
| 488 root_view->OnMouseMoved(moved_event); | 493 root_view->OnMouseMoved(moved_event); |
| 489 ASSERT_TRUE(widget_deletion_observer.IsWidgetAlive()); | 494 ASSERT_TRUE(widget_deletion_observer.IsWidgetAlive()); |
| 490 | 495 |
| 491 // Move the mouse outside of |child| which should dispatch a mouse exit event | 496 // Move the mouse outside of |child| which should dispatch a mouse exit event |
| 492 // to |child| and destroy the widget. This should not crash when the mouse | 497 // to |child| and destroy the widget. This should not crash when the mouse |
| 493 // exit handler returns from the child. | 498 // exit handler returns from the child. |
| 494 ui::MouseEvent move_event2(ui::ET_MOUSE_MOVED, gfx::Point(15, 15), | 499 ui::MouseEvent move_event2( |
| 495 gfx::Point(15, 15), ui::EventTimeForNow(), 0, 0); | 500 ui::ET_MOUSE_MOVED, gfx::Point(15, 15), gfx::Point(15, 15), |
| 501 ui::EventTimeForNow(), 0, 0, |
| 502 ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE)); |
| 496 root_view->OnMouseMoved(move_event2); | 503 root_view->OnMouseMoved(move_event2); |
| 497 EXPECT_FALSE(widget_deletion_observer.IsWidgetAlive()); | 504 EXPECT_FALSE(widget_deletion_observer.IsWidgetAlive()); |
| 498 } | 505 } |
| 499 | 506 |
| 500 // Test that there is no crash if a View deletes its parent widget as a result | 507 // Test that there is no crash if a View deletes its parent widget as a result |
| 501 // of a mouse exited event which was propagated from one of its children. | 508 // of a mouse exited event which was propagated from one of its children. |
| 502 TEST_F(RootViewTest, DeleteWidgetOnMouseExitDispatchFromChild) { | 509 TEST_F(RootViewTest, DeleteWidgetOnMouseExitDispatchFromChild) { |
| 503 Widget* widget = new Widget; | 510 Widget* widget = new Widget; |
| 504 Widget::InitParams init_params = | 511 Widget::InitParams init_params = |
| 505 CreateParams(Widget::InitParams::TYPE_POPUP); | 512 CreateParams(Widget::InitParams::TYPE_POPUP); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 520 child->SetBounds(100, 100, 100, 100); | 527 child->SetBounds(100, 100, 100, 100); |
| 521 subchild->SetBounds(0, 0, 100, 100); | 528 subchild->SetBounds(0, 0, 100, 100); |
| 522 | 529 |
| 523 // Make mouse enter and exit events get propagated from |subchild| to |child|. | 530 // Make mouse enter and exit events get propagated from |subchild| to |child|. |
| 524 child->set_notify_enter_exit_on_child(true); | 531 child->set_notify_enter_exit_on_child(true); |
| 525 | 532 |
| 526 internal::RootView* root_view = | 533 internal::RootView* root_view = |
| 527 static_cast<internal::RootView*>(widget->GetRootView()); | 534 static_cast<internal::RootView*>(widget->GetRootView()); |
| 528 | 535 |
| 529 // Move the mouse within |subchild| and |child|. | 536 // Move the mouse within |subchild| and |child|. |
| 530 ui::MouseEvent moved_event(ui::ET_MOUSE_MOVED, gfx::Point(115, 115), | 537 ui::MouseEvent moved_event( |
| 531 gfx::Point(115, 115), ui::EventTimeForNow(), 0, 0); | 538 ui::ET_MOUSE_MOVED, gfx::Point(115, 115), gfx::Point(115, 115), |
| 539 ui::EventTimeForNow(), 0, 0, |
| 540 ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE)); |
| 532 root_view->OnMouseMoved(moved_event); | 541 root_view->OnMouseMoved(moved_event); |
| 533 ASSERT_TRUE(widget_deletion_observer.IsWidgetAlive()); | 542 ASSERT_TRUE(widget_deletion_observer.IsWidgetAlive()); |
| 534 | 543 |
| 535 // Move the mouse outside of |subchild| and |child| which should dispatch a | 544 // Move the mouse outside of |subchild| and |child| which should dispatch a |
| 536 // mouse exit event to |subchild| and destroy the widget. This should not | 545 // mouse exit event to |subchild| and destroy the widget. This should not |
| 537 // crash when the mouse exit handler returns from |subchild|. | 546 // crash when the mouse exit handler returns from |subchild|. |
| 538 ui::MouseEvent move_event2(ui::ET_MOUSE_MOVED, gfx::Point(15, 15), | 547 ui::MouseEvent move_event2( |
| 539 gfx::Point(15, 15), ui::EventTimeForNow(), 0, 0); | 548 ui::ET_MOUSE_MOVED, gfx::Point(15, 15), gfx::Point(15, 15), |
| 549 ui::EventTimeForNow(), 0, 0, |
| 550 ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE)); |
| 540 root_view->OnMouseMoved(move_event2); | 551 root_view->OnMouseMoved(move_event2); |
| 541 EXPECT_FALSE(widget_deletion_observer.IsWidgetAlive()); | 552 EXPECT_FALSE(widget_deletion_observer.IsWidgetAlive()); |
| 542 } | 553 } |
| 543 | 554 |
| 544 namespace { | 555 namespace { |
| 545 class RootViewTestDialogDelegate : public DialogDelegateView { | 556 class RootViewTestDialogDelegate : public DialogDelegateView { |
| 546 public: | 557 public: |
| 547 RootViewTestDialogDelegate() {} | 558 RootViewTestDialogDelegate() {} |
| 548 | 559 |
| 549 int layout_count() const { return layout_count_; } | 560 int layout_count() const { return layout_count_; } |
| (...skipping 29 matching lines...) Expand all Loading... |
| 579 // Also test Aura desktop Widget codepaths. | 590 // Also test Aura desktop Widget codepaths. |
| 580 views_delegate()->set_use_desktop_native_widgets(true); | 591 views_delegate()->set_use_desktop_native_widgets(true); |
| 581 delegate = new RootViewTestDialogDelegate(); | 592 delegate = new RootViewTestDialogDelegate(); |
| 582 widget = DialogDelegate::CreateDialogWidget(delegate, GetContext(), nullptr); | 593 widget = DialogDelegate::CreateDialogWidget(delegate, GetContext(), nullptr); |
| 583 EXPECT_EQ(1, delegate->layout_count()); | 594 EXPECT_EQ(1, delegate->layout_count()); |
| 584 widget->CloseNow(); | 595 widget->CloseNow(); |
| 585 } | 596 } |
| 586 | 597 |
| 587 } // namespace test | 598 } // namespace test |
| 588 } // namespace views | 599 } // namespace views |
| OLD | NEW |