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