15c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/mouse_watcher.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/event_types.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/weak_ptr.h"
11ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h"
12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/aura/env.h"
13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/aura/window.h"
14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/events/event.h"
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/events/event_constants.h"
16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/events/event_handler.h"
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/events/event_utils.h"
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/gfx/screen.h"
19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace views {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Amount of time between when the mouse moves outside the Host's zone and when
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the listener is notified.
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kNotifyListenerTimeMs = 300;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class MouseWatcher::Observer : public ui::EventHandler {
27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public:
28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  explicit Observer(MouseWatcher* mouse_watcher)
29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      : mouse_watcher_(mouse_watcher),
30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        notify_listener_factory_(this) {
31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    aura::Env::GetInstance()->AddPreTargetHandler(this);
32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual ~Observer() {
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    aura::Env::GetInstance()->RemovePreTargetHandler(this);
36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // ui::EventHandler implementation:
39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    switch (event->type()) {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ui::ET_MOUSE_MOVED:
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ui::ET_MOUSE_DRAGGED:
43f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        HandleMouseEvent(MouseWatcherHost::MOUSE_MOVE);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ui::ET_MOUSE_EXITED:
46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        HandleMouseEvent(MouseWatcherHost::MOUSE_EXIT);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MouseWatcherHost* host() const { return mouse_watcher_->host_.get(); }
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Called when a mouse event we're interested is seen.
57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  void HandleMouseEvent(MouseWatcherHost::MouseEventType event_type) {
58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // It's safe to use last_mouse_location() here as this function is invoked
59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // during event dispatching.
60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!host()->Contains(aura::Env::GetInstance()->last_mouse_location(),
61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                          event_type)) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Mouse moved outside the host's zone, start a timer to notify the
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // listener.
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!notify_listener_factory_.HasWeakPtrs()) {
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::MessageLoop::current()->PostDelayedTask(
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            FROM_HERE,
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            base::Bind(&Observer::NotifyListener,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       notify_listener_factory_.GetWeakPtr()),
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            event_type == MouseWatcherHost::MOUSE_MOVE
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                ? base::TimeDelta::FromMilliseconds(kNotifyListenerTimeMs)
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                : mouse_watcher_->notify_on_exit_time_);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Mouse moved quickly out of the host and then into it again, so cancel
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the timer.
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      notify_listener_factory_.InvalidateWeakPtrs();
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void NotifyListener() {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mouse_watcher_->NotifyListener();
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // WARNING: we've been deleted.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MouseWatcher* mouse_watcher_;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // A factory that is used to construct a delayed callback to the listener.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::WeakPtrFactory<Observer> notify_listener_factory_;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(Observer);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MouseWatcherListener::~MouseWatcherListener() {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MouseWatcherHost::~MouseWatcherHost() {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MouseWatcher::MouseWatcher(MouseWatcherHost* host,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           MouseWatcherListener* listener)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : host_(host),
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      listener_(listener),
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      notify_on_exit_time_(base::TimeDelta::FromMilliseconds(
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          kNotifyListenerTimeMs)) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MouseWatcher::~MouseWatcher() {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MouseWatcher::Start() {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_observing())
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    observer_.reset(new Observer(this));
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MouseWatcher::Stop() {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observer_.reset(NULL);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MouseWatcher::NotifyListener() {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observer_.reset(NULL);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  listener_->MouseMovedOutOfHost();
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace views
126