diff options
Diffstat (limited to 'chromium/ui/views/mouse_watcher_aura.cc')
-rw-r--r-- | chromium/ui/views/mouse_watcher_aura.cc | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/chromium/ui/views/mouse_watcher_aura.cc b/chromium/ui/views/mouse_watcher_aura.cc new file mode 100644 index 00000000000..3793f0e9671 --- /dev/null +++ b/chromium/ui/views/mouse_watcher_aura.cc @@ -0,0 +1,125 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/views/mouse_watcher.h" + +#include "base/bind.h" +#include "base/compiler_specific.h" +#include "base/event_types.h" +#include "base/memory/weak_ptr.h" +#include "base/message_loop/message_loop.h" +#include "ui/aura/env.h" +#include "ui/aura/window.h" +#include "ui/events/event.h" +#include "ui/events/event_constants.h" +#include "ui/events/event_handler.h" +#include "ui/events/event_utils.h" +#include "ui/gfx/screen.h" + +namespace views { + +// Amount of time between when the mouse moves outside the Host's zone and when +// the listener is notified. +const int kNotifyListenerTimeMs = 300; + +class MouseWatcher::Observer : public ui::EventHandler { + public: + explicit Observer(MouseWatcher* mouse_watcher) + : mouse_watcher_(mouse_watcher), + notify_listener_factory_(this) { + aura::Env::GetInstance()->AddPreTargetHandler(this); + } + + virtual ~Observer() { + aura::Env::GetInstance()->RemovePreTargetHandler(this); + } + + // ui::EventHandler implementation: + virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { + switch (event->type()) { + case ui::ET_MOUSE_MOVED: + case ui::ET_MOUSE_DRAGGED: + HandleMouseEvent(MouseWatcherHost::MOUSE_MOVE); + break; + case ui::ET_MOUSE_EXITED: + HandleMouseEvent(MouseWatcherHost::MOUSE_EXIT); + break; + default: + break; + } + } + + private: + MouseWatcherHost* host() const { return mouse_watcher_->host_.get(); } + + // Called when a mouse event we're interested is seen. + void HandleMouseEvent(MouseWatcherHost::MouseEventType event_type) { + // It's safe to use last_mouse_location() here as this function is invoked + // during event dispatching. + if (!host()->Contains(aura::Env::GetInstance()->last_mouse_location(), + event_type)) { + // Mouse moved outside the host's zone, start a timer to notify the + // listener. + if (!notify_listener_factory_.HasWeakPtrs()) { + base::MessageLoop::current()->PostDelayedTask( + FROM_HERE, + base::Bind(&Observer::NotifyListener, + notify_listener_factory_.GetWeakPtr()), + event_type == MouseWatcherHost::MOUSE_MOVE + ? base::TimeDelta::FromMilliseconds(kNotifyListenerTimeMs) + : mouse_watcher_->notify_on_exit_time_); + } + } else { + // Mouse moved quickly out of the host and then into it again, so cancel + // the timer. + notify_listener_factory_.InvalidateWeakPtrs(); + } + } + + void NotifyListener() { + mouse_watcher_->NotifyListener(); + // WARNING: we've been deleted. + } + + private: + MouseWatcher* mouse_watcher_; + + // A factory that is used to construct a delayed callback to the listener. + base::WeakPtrFactory<Observer> notify_listener_factory_; + + DISALLOW_COPY_AND_ASSIGN(Observer); +}; + +MouseWatcherListener::~MouseWatcherListener() { +} + +MouseWatcherHost::~MouseWatcherHost() { +} + +MouseWatcher::MouseWatcher(MouseWatcherHost* host, + MouseWatcherListener* listener) + : host_(host), + listener_(listener), + notify_on_exit_time_(base::TimeDelta::FromMilliseconds( + kNotifyListenerTimeMs)) { +} + +MouseWatcher::~MouseWatcher() { +} + +void MouseWatcher::Start() { + if (!is_observing()) + observer_.reset(new Observer(this)); +} + +void MouseWatcher::Stop() { + observer_.reset(NULL); +} + +void MouseWatcher::NotifyListener() { + observer_.reset(NULL); + listener_->MouseMovedOutOfHost(); +} + +} // namespace views |