summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-01 01:38:56 +0000
committersadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-01 01:38:56 +0000
commit8eef1933e5631f5d150f826dc6ce42baf23d8520 (patch)
tree249edc631f4595174a868237172ff70f15d8b098
parent2da7b8ea8937b49475f39e383bbc7e452582a2e7 (diff)
downloadchromium_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.cc10
-rw-r--r--ui/aura/window_event_dispatcher_unittest.cc106
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