summaryrefslogtreecommitdiff
path: root/chromium/ui/aura/root_window.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/ui/aura/root_window.cc')
-rw-r--r--chromium/ui/aura/root_window.cc139
1 files changed, 76 insertions, 63 deletions
diff --git a/chromium/ui/aura/root_window.cc b/chromium/ui/aura/root_window.cc
index 43366f001aa..303ec90f18e 100644
--- a/chromium/ui/aura/root_window.cc
+++ b/chromium/ui/aura/root_window.cc
@@ -6,7 +6,6 @@
#include <vector>
-#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/debug/trace_event.h"
@@ -25,7 +24,6 @@
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
#include "ui/aura/window_tracker.h"
-#include "ui/base/events/event.h"
#include "ui/base/gestures/gesture_recognizer.h"
#include "ui/base/gestures/gesture_types.h"
#include "ui/base/hit_test.h"
@@ -34,6 +32,7 @@
#include "ui/compositor/dip_util.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animator.h"
+#include "ui/events/event.h"
#include "ui/gfx/display.h"
#include "ui/gfx/point3_f.h"
#include "ui/gfx/point_conversions.h"
@@ -149,7 +148,6 @@ RootWindow::RootWindow(const CreateParams& params)
last_cursor_(ui::kCursorNull),
mouse_pressed_handler_(NULL),
mouse_moved_handler_(NULL),
- mouse_event_dispatch_target_(NULL),
event_dispatch_target_(NULL),
gesture_recognizer_(ui::GestureRecognizer::Create(this)),
synthesize_mouse_move_(false),
@@ -171,6 +169,8 @@ RootWindow::RootWindow(const CreateParams& params)
}
RootWindow::~RootWindow() {
+ TRACE_EVENT0("shutdown", "RootWindow::Destructor");
+
compositor_->RemoveObserver(this);
// Make sure to destroy the compositor before terminating so that state is
// cleared and we don't hit asserts.
@@ -216,6 +216,8 @@ void RootWindow::PrepareForShutdown() {
}
void RootWindow::RepostEvent(const ui::LocatedEvent& event) {
+ DCHECK(event.type() == ui::ET_MOUSE_PRESSED ||
+ event.type() == ui::ET_GESTURE_TAP_DOWN);
// We allow for only one outstanding repostable event. This is used
// in exiting context menus. A dropped repost request is allowed.
if (event.type() == ui::ET_MOUSE_PRESSED) {
@@ -231,7 +233,8 @@ void RootWindow::RepostEvent(const ui::LocatedEvent& event) {
} else {
DCHECK(event.type() == ui::ET_GESTURE_TAP_DOWN);
held_repostable_event_.reset();
- // TODO(sschmitz): add similar code for gesture events.
+ // TODO(rbyers): Reposing of gestures is tricky to get
+ // right, so it's not yet supported. crbug.com/170987.
}
}
@@ -276,6 +279,13 @@ void RootWindow::SetCursor(gfx::NativeCursor cursor) {
}
void RootWindow::OnCursorVisibilityChanged(bool show) {
+ // Clear any existing mouse hover effects when the cursor becomes invisible.
+ // Note we do not need to dispatch a mouse enter when the cursor becomes
+ // visible because that can only happen in response to a mouse event, which
+ // will trigger its own mouse enter.
+ if (!show)
+ DispatchMouseExitAtPoint(GetLastMouseLocationInRoot());
+
host_->OnCursorVisibilityChanged(show);
}
@@ -378,13 +388,13 @@ void RootWindow::DispatchMouseExitToHidingWindow(Window* window) {
// |window| is the capture window.
gfx::Point last_mouse_location = GetLastMouseLocationInRoot();
if (window->Contains(mouse_moved_handler_) &&
- window->ContainsPointInRoot(last_mouse_location)) {
- ui::MouseEvent event(ui::ET_MOUSE_EXITED,
- last_mouse_location,
- last_mouse_location,
- ui::EF_NONE);
- DispatchMouseEnterOrExit(event, ui::ET_MOUSE_EXITED);
- }
+ window->ContainsPointInRoot(last_mouse_location))
+ DispatchMouseExitAtPoint(last_mouse_location);
+}
+
+void RootWindow::DispatchMouseExitAtPoint(const gfx::Point& point) {
+ ui::MouseEvent event(ui::ET_MOUSE_EXITED, point, point, ui::EF_NONE);
+ DispatchMouseEnterOrExit(event, ui::ET_MOUSE_EXITED);
}
void RootWindow::OnWindowVisibilityChanged(Window* window, bool is_visible) {
@@ -422,9 +432,7 @@ void RootWindow::RemoveRootWindowObserver(RootWindowObserver* observer) {
}
void RootWindow::PostNativeEvent(const base::NativeEvent& native_event) {
-#if !defined(OS_MACOSX)
host_->PostNativeEvent(native_event);
-#endif
}
void RootWindow::ConvertPointToNativeScreen(gfx::Point* point) const {
@@ -441,13 +449,13 @@ void RootWindow::ConvertPointFromNativeScreen(gfx::Point* point) const {
void RootWindow::ConvertPointToHost(gfx::Point* point) const {
gfx::Point3F point_3f(*point);
- GetRootTransform().TransformPoint(point_3f);
+ GetRootTransform().TransformPoint(&point_3f);
*point = gfx::ToFlooredPoint(point_3f.AsPointF());
}
void RootWindow::ConvertPointFromHost(gfx::Point* point) const {
gfx::Point3F point_3f(*point);
- GetInverseRootTransform().TransformPoint(point_3f);
+ GetInverseRootTransform().TransformPoint(&point_3f);
*point = gfx::ToFlooredPoint(point_3f.AsPointF());
}
@@ -499,15 +507,6 @@ void RootWindow::SetFocusWhenShown(bool focused) {
host_->SetFocusWhenShown(focused);
}
-bool RootWindow::CopyAreaToSkCanvas(const gfx::Rect& source_bounds,
- const gfx::Point& dest_offset,
- SkCanvas* canvas) {
- DCHECK(canvas);
- DCHECK(bounds().Contains(source_bounds));
- gfx::Rect source_pixels = ui::ConvertRectToPixel(layer(), source_bounds);
- return host_->CopyAreaToSkCanvas(source_pixels, dest_offset, canvas);
-}
-
gfx::Point RootWindow::GetLastMouseLocationInRoot() const {
gfx::Point location = Env::GetInstance()->last_mouse_location();
client::ScreenPositionClient* client = client::GetScreenPositionClient(this);
@@ -654,6 +653,14 @@ bool RootWindow::CanReceiveEvents() const {
void RootWindow::UpdateCapture(Window* old_capture,
Window* new_capture) {
+ if (!new_capture && old_capture && old_capture->GetRootWindow() != this) {
+ // If we no longer contain the window that had capture make sure we clean
+ // state in the GestureRecognizer. Since we don't contain the window we'll
+ // never get notification of its destruction and clean up state.
+ // We do this early on as OnCaptureLost() may delete |old_capture|.
+ gesture_recognizer_->CleanupStateForConsumer(old_capture);
+ }
+
if (old_capture && old_capture->GetRootWindow() == this &&
old_capture->delegate()) {
// Send a capture changed event with bogus location data.
@@ -674,9 +681,8 @@ void RootWindow::UpdateCapture(Window* old_capture,
}
if (new_capture) {
- // Make all subsequent mouse events and touch go to the capture window. We
- // shouldn't need to send an event here as OnCaptureLost should take care of
- // that.
+ // Make all subsequent mouse events go to the capture window. We shouldn't
+ // need to send an event here as OnCaptureLost() should take care of that.
if (mouse_moved_handler_ || Env::GetInstance()->is_mouse_button_down())
mouse_moved_handler_ = new_capture;
} else {
@@ -698,12 +704,6 @@ bool RootWindow::QueryMouseLocationForTest(gfx::Point* point) const {
return host_->QueryMouseLocation(point);
}
-void RootWindow::ClearMouseHandlers() {
- mouse_pressed_handler_ = NULL;
- mouse_moved_handler_ = NULL;
- mouse_event_dispatch_target_ = NULL;
-}
-
////////////////////////////////////////////////////////////////////////////////
// RootWindow, private:
@@ -724,22 +724,6 @@ void RootWindow::MoveCursorToInternal(const gfx::Point& root_location,
synthesize_mouse_move_ = false;
}
-void RootWindow::HandleMouseMoved(const ui::MouseEvent& event, Window* target) {
- if (target == mouse_moved_handler_)
- return;
-
- DispatchMouseEnterOrExit(event, ui::ET_MOUSE_EXITED);
-
- if (mouse_event_dispatch_target_ != target) {
- mouse_moved_handler_ = NULL;
- return;
- }
-
- mouse_moved_handler_ = target;
-
- DispatchMouseEnterOrExit(event, ui::ET_MOUSE_ENTERED);
-}
-
void RootWindow::DispatchMouseEnterOrExit(const ui::MouseEvent& event,
ui::EventType type) {
if (!mouse_moved_handler_ || !mouse_moved_handler_->delegate())
@@ -825,15 +809,13 @@ void RootWindow::OnWindowHidden(Window* invisible, WindowHiddenReason reason) {
mouse_pressed_handler_ = NULL;
if (invisible->Contains(mouse_moved_handler_))
mouse_moved_handler_ = NULL;
- if (invisible->Contains(mouse_event_dispatch_target_))
- mouse_event_dispatch_target_ = NULL;
CleanupGestureRecognizerState(invisible);
}
void RootWindow::CleanupGestureRecognizerState(Window* window) {
gesture_recognizer_->CleanupStateForConsumer(window);
- Windows windows = window->children();
+ const Windows& windows = window->children();
for (Windows::const_iterator iter = windows.begin();
iter != windows.end();
++iter) {
@@ -973,7 +955,8 @@ void RootWindow::OnHostLostWindowCapture() {
}
void RootWindow::OnHostLostMouseGrab() {
- ClearMouseHandlers();
+ mouse_pressed_handler_ = NULL;
+ mouse_moved_handler_ = NULL;
}
void RootWindow::OnHostPaint(const gfx::Rect& damage_rect) {
@@ -1038,21 +1021,46 @@ bool RootWindow::DispatchMouseEventToTarget(ui::MouseEvent* event,
ui::EF_LEFT_MOUSE_BUTTON |
ui::EF_MIDDLE_MOUSE_BUTTON |
ui::EF_RIGHT_MOUSE_BUTTON;
- base::AutoReset<Window*> reset(&mouse_event_dispatch_target_, target);
+ // WARNING: because of nested message loops |this| may be deleted after
+ // dispatching any event. Do not use AutoReset or the like here.
+ WindowTracker destroyed_tracker;
+ destroyed_tracker.Add(this);
SetLastMouseLocation(this, event->location());
synthesize_mouse_move_ = false;
switch (event->type()) {
case ui::ET_MOUSE_EXITED:
if (!target) {
DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED);
+ if (!destroyed_tracker.Contains(this))
+ return false;
mouse_moved_handler_ = NULL;
}
break;
case ui::ET_MOUSE_MOVED:
- mouse_event_dispatch_target_ = target;
- HandleMouseMoved(*event, target);
- if (mouse_event_dispatch_target_ != target)
- return false;
+ // Send an exit to the current |mouse_moved_handler_| and an enter to
+ // |target|. Take care that both us and |target| aren't destroyed during
+ // dispatch.
+ if (target != mouse_moved_handler_) {
+ aura::Window* old_mouse_moved_handler = mouse_moved_handler_;
+ if (target)
+ destroyed_tracker.Add(target);
+ DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED);
+ if (!destroyed_tracker.Contains(this))
+ return false;
+ // If the |mouse_moved_handler_| changes out from under us, assume a
+ // nested message loop ran and we don't need to do anything.
+ if (mouse_moved_handler_ != old_mouse_moved_handler)
+ return false;
+ if (destroyed_tracker.Contains(target)) {
+ destroyed_tracker.Remove(target);
+ mouse_moved_handler_ = target;
+ DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_ENTERED);
+ if (!destroyed_tracker.Contains(this))
+ return false;
+ } else {
+ mouse_moved_handler_ = NULL;
+ }
+ }
break;
case ui::ET_MOUSE_PRESSED:
// Don't set the mouse pressed handler for non client mouse down events.
@@ -1072,14 +1080,19 @@ bool RootWindow::DispatchMouseEventToTarget(ui::MouseEvent* event,
default:
break;
}
+ bool result;
if (target) {
event->ConvertLocationToTarget(static_cast<Window*>(this), target);
if (IsNonClientLocation(target, event->location()))
event->set_flags(event->flags() | ui::EF_IS_NON_CLIENT);
ProcessEvent(target, event);
- return event->handled();
+ if (!destroyed_tracker.Contains(this))
+ return false;
+ result = event->handled();
+ } else {
+ result = false;
}
- return false;
+ return result;
}
bool RootWindow::DispatchTouchEventImpl(ui::TouchEvent* event) {
@@ -1153,11 +1166,11 @@ void RootWindow::DispatchHeldEvents() {
if (held_repostable_event_->type() == ui::ET_MOUSE_PRESSED) {
ui::MouseEvent mouse_event(
static_cast<const ui::MouseEvent&>(*held_repostable_event_.get()));
- held_repostable_event_.reset(); // must be reset before dispatch
+ held_repostable_event_.reset(); // must be reset before dispatch
DispatchMouseEventRepost(&mouse_event);
} else {
- DCHECK(held_repostable_event_->type() == ui::ET_GESTURE_TAP_DOWN);
- // TODO(sschmitz): add similar code for gesture events
+ // TODO(rbyers): GESTURE_TAP_DOWN not yet supported: crbug.com/170987.
+ NOTREACHED();
}
held_repostable_event_.reset();
}