diff options
author | sadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-01 01:38:56 +0000 |
---|---|---|
committer | sadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-01 01:38:56 +0000 |
commit | 8eef1933e5631f5d150f826dc6ce42baf23d8520 (patch) | |
tree | 249edc631f4595174a868237172ff70f15d8b098 | |
parent | 2da7b8ea8937b49475f39e383bbc7e452582a2e7 (diff) | |
download | chromium_src-8eef1933e5631f5d150f826dc6ce42baf23d8520.zip chromium_src-8eef1933e5631f5d150f826dc6ce42baf23d8520.tar.gz chromium_src-8eef1933e5631f5d150f826dc6ce42baf23d8520.tar.bz2 |
aura: Fix a crash related to nested event-dispatch.
If events are being dispatched from a nested message-loop, and the target of the
outer loop is hidden or moved to another dispatcher during dispatching events in
the inner loop, then reset the target for the outer loop.
BUG=347012
R=sky@chromium.org
Previously landed on r254150 but reverted in r254183 because it broke clang builds.
Review URL: https://codereview.chromium.org/180973007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@254312 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | ui/aura/window_event_dispatcher.cc | 10 | ||||
-rw-r--r-- | ui/aura/window_event_dispatcher_unittest.cc | 106 |
2 files changed, 113 insertions, 3 deletions
diff --git a/ui/aura/window_event_dispatcher.cc b/ui/aura/window_event_dispatcher.cc index 729def8..a071830 100644 --- a/ui/aura/window_event_dispatcher.cc +++ b/ui/aura/window_event_dispatcher.cc @@ -412,6 +412,13 @@ void WindowEventDispatcher::OnWindowHidden(Window* invisible, if (invisible->Contains(mouse_moved_handler_)) mouse_moved_handler_ = NULL; + // If events are being dispatched from a nested message-loop, and the target + // of the outer loop is hidden or moved to another dispatcher during + // dispatching events in the inner loop, then reset the target for the outer + // loop. + if (invisible->Contains(old_dispatch_target_)) + old_dispatch_target_ = NULL; + CleanupGestureState(invisible); // Do not clear the capture, and the |event_dispatch_target_| if the @@ -425,9 +432,6 @@ void WindowEventDispatcher::OnWindowHidden(Window* invisible, if (invisible->Contains(event_dispatch_target_)) event_dispatch_target_ = NULL; - if (invisible->Contains(old_dispatch_target_)) - old_dispatch_target_ = NULL; - // If the ancestor of the capture window is hidden, release the capture. // Note that this may delete the window so do not use capture_window // after this. diff --git a/ui/aura/window_event_dispatcher_unittest.cc b/ui/aura/window_event_dispatcher_unittest.cc index 87e6193..e919c64 100644 --- a/ui/aura/window_event_dispatcher_unittest.cc +++ b/ui/aura/window_event_dispatcher_unittest.cc @@ -1836,4 +1836,110 @@ TEST_F(WindowEventDispatcherTest, HostCancelModeWithFocusedWindowOutside) { client::GetFocusClient(root_window())->GetFocusedWindow()); } +// Dispatches a mouse-move event to |target| when it receives a mouse-move +// event. +class DispatchEventHandler : public ui::EventHandler { + public: + explicit DispatchEventHandler(Window* target) + : target_(target), + dispatched_(false) {} + virtual ~DispatchEventHandler() {} + + bool dispatched() const { return dispatched_; } + private: + // ui::EventHandler: + virtual void OnMouseEvent(ui::MouseEvent* mouse) OVERRIDE { + if (mouse->type() == ui::ET_MOUSE_MOVED) { + ui::MouseEvent move(ui::ET_MOUSE_MOVED, target_->bounds().CenterPoint(), + target_->bounds().CenterPoint(), ui::EF_NONE, ui::EF_NONE); + ui::EventDispatchDetails details = + target_->GetDispatcher()->OnEventFromSource(&move); + ASSERT_FALSE(details.dispatcher_destroyed); + EXPECT_FALSE(details.target_destroyed); + EXPECT_EQ(target_, move.target()); + dispatched_ = true; + } + ui::EventHandler::OnMouseEvent(mouse); + } + + Window* target_; + bool dispatched_; + + DISALLOW_COPY_AND_ASSIGN(DispatchEventHandler); +}; + +// Moves |window| to |root_window| when it receives a mouse-move event. +class MoveWindowHandler : public ui::EventHandler { + public: + MoveWindowHandler(Window* window, Window* root_window) + : window_to_move_(window), + root_window_to_move_to_(root_window) {} + virtual ~MoveWindowHandler() {} + + private: + // ui::EventHandler: + virtual void OnMouseEvent(ui::MouseEvent* mouse) OVERRIDE { + if (mouse->type() == ui::ET_MOUSE_MOVED) { + root_window_to_move_to_->AddChild(window_to_move_); + } + ui::EventHandler::OnMouseEvent(mouse); + } + + Window* window_to_move_; + Window* root_window_to_move_to_; + + DISALLOW_COPY_AND_ASSIGN(MoveWindowHandler); +}; + +#if defined(USE_OZONE) +#define MAYBE_NestedEventDispatchTargetMoved \ + DISABLED_NestedEventDispatchTargetMoved +#else +#define MAYBE_NestedEventDispatchTargetMoved NestedEventDispatchTargetMoved +#endif +// Tests that nested event dispatch works correctly if the target of the older +// event being dispatched is moved to a different dispatcher in response to an +// event in the inner loop. +TEST_F(WindowEventDispatcherTest, MAYBE_NestedEventDispatchTargetMoved) { + scoped_ptr<WindowTreeHost> second_host( + WindowTreeHost::Create(gfx::Rect(20, 30, 100, 50))); + second_host->InitHost(); + Window* second_root = second_host->window(); + + // Create two windows parented to |root_window()|. + test::TestWindowDelegate delegate; + scoped_ptr<Window> first(CreateTestWindowWithDelegate(&delegate, 123, + gfx::Rect(20, 10, 10, 20), root_window())); + scoped_ptr<Window> second(CreateTestWindowWithDelegate(&delegate, 234, + gfx::Rect(40, 10, 50, 20), root_window())); + + // Setup a handler on |first| so that it dispatches an event to |second| when + // |first| receives an event. + DispatchEventHandler dispatch_event(second.get()); + first->AddPreTargetHandler(&dispatch_event); + + // Setup a handler on |second| so that it moves |first| into |second_root| + // when |second| receives an event. + MoveWindowHandler move_window(first.get(), second_root); + second->AddPreTargetHandler(&move_window); + + // Some sanity checks: |first| is inside |root_window()|'s tree. + EXPECT_EQ(root_window(), first->GetRootWindow()); + // The two root windows are different. + EXPECT_NE(root_window(), second_root); + + // Dispatch an event to |first|. + ui::MouseEvent move(ui::ET_MOUSE_MOVED, first->bounds().CenterPoint(), + first->bounds().CenterPoint(), ui::EF_NONE, ui::EF_NONE); + ui::EventDispatchDetails details = dispatcher()->OnEventFromSource(&move); + ASSERT_FALSE(details.dispatcher_destroyed); + EXPECT_TRUE(details.target_destroyed); + EXPECT_EQ(first.get(), move.target()); + EXPECT_TRUE(dispatch_event.dispatched()); + EXPECT_EQ(second_root, first->GetRootWindow()); + + first->RemovePreTargetHandler(&dispatch_event); + second->RemovePreTargetHandler(&move_window); +} + } // namespace aura |