Chromium Code Reviews| OLD | NEW | 
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "views/mouse_watcher.h" | 5 #include "views/mouse_watcher.h" | 
| 6 | 6 | 
| 7 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" | 
| 8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" | 
| 9 #include "base/task.h" | 9 #include "base/task.h" | 
| 10 #include "views/screen.h" | 10 #include "views/screen.h" | 
| 11 #include "views/view.h" | 11 #include "views/view.h" | 
| 12 #include "views/window/window.h" | |
| 12 | 13 | 
| 13 namespace views { | 14 namespace views { | 
| 14 | 15 | 
| 15 // Amount of time between when the mouse moves outside the view's zone and when | 16 // Amount of time between when the mouse moves outside the view's zone and when | 
| 16 // the listener is notified. | 17 // the listener is notified. | 
| 17 static const int kNotifyListenerTimeMs = 300; | 18 static const int kNotifyListenerTimeMs = 300; | 
| 18 | 19 | 
| 19 class MouseWatcher::Observer : public MessageLoopForUI::Observer { | 20 class MouseWatcher::Observer : public MessageLoopForUI::Observer { | 
| 20 public: | 21 public: | 
| 21 explicit Observer(MouseWatcher* mouse_watcher) | 22 explicit Observer(MouseWatcher* mouse_watcher) | 
| (...skipping 18 matching lines...) Expand all Loading... | |
| 40 // WM_MOUSEMOVE: | 41 // WM_MOUSEMOVE: | 
| 41 // For when the mouse moves from the view into the rest of the browser UI, | 42 // For when the mouse moves from the view into the rest of the browser UI, | 
| 42 // i.e. within the bounds of the same windows HWND. | 43 // i.e. within the bounds of the same windows HWND. | 
| 43 // WM_MOUSELEAVE: | 44 // WM_MOUSELEAVE: | 
| 44 // For when the mouse moves out of the bounds of the view's HWND. | 45 // For when the mouse moves out of the bounds of the view's HWND. | 
| 45 // WM_NCMOUSELEAVE: | 46 // WM_NCMOUSELEAVE: | 
| 46 // For notification when the mouse leaves the _non-client_ area. | 47 // For notification when the mouse leaves the _non-client_ area. | 
| 47 // | 48 // | 
| 48 switch (msg.message) { | 49 switch (msg.message) { | 
| 49 case WM_MOUSEMOVE: | 50 case WM_MOUSEMOVE: | 
| 51 HandleGlobalMouseMoveEvent(false); | |
| 52 break; | |
| 50 case WM_MOUSELEAVE: | 53 case WM_MOUSELEAVE: | 
| 51 case WM_NCMOUSELEAVE: | 54 case WM_NCMOUSELEAVE: | 
| 52 HandleGlobalMouseMoveEvent(); | 55 HandleGlobalMouseMoveEvent(true); | 
| 53 break; | 56 break; | 
| 54 } | 57 } | 
| 55 } | 58 } | 
| 56 #else | 59 #else | 
| 57 void WillProcessEvent(GdkEvent* event) { | 60 void WillProcessEvent(GdkEvent* event) { | 
| 58 } | 61 } | 
| 59 | 62 | 
| 60 void DidProcessEvent(GdkEvent* event) { | 63 void DidProcessEvent(GdkEvent* event) { | 
| 61 switch (event->type) { | 64 switch (event->type) { | 
| 62 case GDK_MOTION_NOTIFY: | 65 case GDK_MOTION_NOTIFY: | 
| 66 HandleGlobalMouseMoveEvent(false); | |
| 67 break; | |
| 63 case GDK_LEAVE_NOTIFY: | 68 case GDK_LEAVE_NOTIFY: | 
| 64 HandleGlobalMouseMoveEvent(); | 69 HandleGlobalMouseMoveEvent(true); | 
| 65 break; | 70 break; | 
| 66 default: | 71 default: | 
| 67 break; | 72 break; | 
| 68 } | 73 } | 
| 69 } | 74 } | 
| 70 #endif | 75 #endif | 
| 71 | 76 | 
| 72 private: | 77 private: | 
| 73 views::View* view() { return mouse_watcher_->host_; } | 78 View* view() { return mouse_watcher_->host_; } | 
| 
 
Jay Civelli
2010/08/26 16:10:32
Make it const.
 
 | |
| 74 | 79 | 
| 75 // Returns whether or not the cursor is currently in the view's "zone" which | 80 // Returns whether or not the cursor is currently in the view's "zone" which | 
| 76 // is defined as a slightly larger region than the view. | 81 // is defined as a slightly larger region than the view. | 
| 77 bool IsCursorInViewZone() { | 82 bool IsCursorInViewZone() { | 
| 78 gfx::Rect bounds = view()->GetLocalBounds(true); | 83 gfx::Rect bounds = view()->GetLocalBounds(true); | 
| 79 gfx::Point view_topleft(bounds.origin()); | 84 gfx::Point view_topleft(bounds.origin()); | 
| 80 views::View::ConvertPointToScreen(view(), &view_topleft); | 85 View::ConvertPointToScreen(view(), &view_topleft); | 
| 81 bounds.set_origin(view_topleft); | 86 bounds.set_origin(view_topleft); | 
| 82 bounds.SetRect(view_topleft.x() - mouse_watcher_->hot_zone_insets_.left(), | 87 bounds.SetRect(view_topleft.x() - mouse_watcher_->hot_zone_insets_.left(), | 
| 83 view_topleft.y() - mouse_watcher_->hot_zone_insets_.top(), | 88 view_topleft.y() - mouse_watcher_->hot_zone_insets_.top(), | 
| 84 bounds.width() + mouse_watcher_->hot_zone_insets_.width(), | 89 bounds.width() + mouse_watcher_->hot_zone_insets_.width(), | 
| 85 bounds.height() + mouse_watcher_->hot_zone_insets_.height()); | 90 bounds.height() + mouse_watcher_->hot_zone_insets_.height()); | 
| 86 | 91 | 
| 87 gfx::Point cursor_point = views::Screen::GetCursorScreenPoint(); | 92 gfx::Point cursor_point = Screen::GetCursorScreenPoint(); | 
| 88 | 93 | 
| 89 return bounds.Contains(cursor_point.x(), cursor_point.y()); | 94 return bounds.Contains(cursor_point.x(), cursor_point.y()); | 
| 90 } | 95 } | 
| 91 | 96 | 
| 97 // Returns true if the mouse is over the view's window. | |
| 98 bool IsMouseOverWindow() { | |
| 99 return Screen::GetWindowAtCursorScreenPoint() == | |
| 100 view()->GetWindow()->GetNativeWindow(); | |
| 101 } | |
| 102 | |
| 92 // Called from the message loop observer when a mouse movement has occurred. | 103 // Called from the message loop observer when a mouse movement has occurred. | 
| 93 void HandleGlobalMouseMoveEvent() { | 104 void HandleGlobalMouseMoveEvent(bool check_window) { | 
| 94 if (!IsCursorInViewZone()) { | 105 bool in_view = IsCursorInViewZone(); | 
| 106 if (!in_view || (check_window && !IsMouseOverWindow())) { | |
| 95 // Mouse moved outside the view's zone, start a timer to notify the | 107 // Mouse moved outside the view's zone, start a timer to notify the | 
| 96 // listener. | 108 // listener. | 
| 97 if (notify_listener_factory_.empty()) { | 109 if (notify_listener_factory_.empty()) { | 
| 98 MessageLoop::current()->PostDelayedTask( | 110 MessageLoop::current()->PostDelayedTask( | 
| 99 FROM_HERE, | 111 FROM_HERE, | 
| 100 notify_listener_factory_.NewRunnableMethod( | 112 notify_listener_factory_.NewRunnableMethod( | 
| 101 &Observer::NotifyListener), | 113 &Observer::NotifyListener), | 
| 102 kNotifyListenerTimeMs); | 114 !in_view ? kNotifyListenerTimeMs : | 
| 115 mouse_watcher_->notify_on_exit_time_ms_); | |
| 103 } | 116 } | 
| 104 } else { | 117 } else { | 
| 105 // Mouse moved quickly out of the view and then into it again, so cancel | 118 // Mouse moved quickly out of the view and then into it again, so cancel | 
| 106 // the timer. | 119 // the timer. | 
| 107 notify_listener_factory_.RevokeAll(); | 120 notify_listener_factory_.RevokeAll(); | 
| 108 } | 121 } | 
| 109 } | 122 } | 
| 110 | 123 | 
| 111 void NotifyListener() { | 124 void NotifyListener() { | 
| 112 mouse_watcher_->NotifyListener(); | 125 mouse_watcher_->NotifyListener(); | 
| 113 // WARNING: we've been deleted. | 126 // WARNING: we've been deleted. | 
| 114 } | 127 } | 
| 115 | 128 | 
| 116 private: | 129 private: | 
| 117 MouseWatcher* mouse_watcher_; | 130 MouseWatcher* mouse_watcher_; | 
| 118 | 131 | 
| 119 // A factory that is used to construct a delayed callback to the listener. | 132 // A factory that is used to construct a delayed callback to the listener. | 
| 120 ScopedRunnableMethodFactory<Observer> notify_listener_factory_; | 133 ScopedRunnableMethodFactory<Observer> notify_listener_factory_; | 
| 121 | 134 | 
| 122 DISALLOW_COPY_AND_ASSIGN(Observer); | 135 DISALLOW_COPY_AND_ASSIGN(Observer); | 
| 123 }; | 136 }; | 
| 124 | 137 | 
| 125 MouseWatcherListener::~MouseWatcherListener() { | 138 MouseWatcherListener::~MouseWatcherListener() { | 
| 126 } | 139 } | 
| 127 | 140 | 
| 128 MouseWatcher::MouseWatcher(views::View* host, | 141 MouseWatcher::MouseWatcher(View* host, | 
| 129 MouseWatcherListener* listener, | 142 MouseWatcherListener* listener, | 
| 130 const gfx::Insets& hot_zone_insets) | 143 const gfx::Insets& hot_zone_insets) | 
| 131 : host_(host), | 144 : host_(host), | 
| 132 listener_(listener), | 145 listener_(listener), | 
| 133 hot_zone_insets_(hot_zone_insets) { | 146 hot_zone_insets_(hot_zone_insets), | 
| 147 notify_on_exit_time_ms_(kNotifyListenerTimeMs) { | |
| 134 } | 148 } | 
| 135 | 149 | 
| 136 MouseWatcher::~MouseWatcher() { | 150 MouseWatcher::~MouseWatcher() { | 
| 137 } | 151 } | 
| 138 | 152 | 
| 139 void MouseWatcher::Start() { | 153 void MouseWatcher::Start() { | 
| 140 if (!is_observing()) | 154 if (!is_observing()) | 
| 141 observer_.reset(new Observer(this)); | 155 observer_.reset(new Observer(this)); | 
| 142 } | 156 } | 
| 143 | 157 | 
| 144 void MouseWatcher::Stop() { | 158 void MouseWatcher::Stop() { | 
| 145 observer_.reset(NULL); | 159 observer_.reset(NULL); | 
| 146 } | 160 } | 
| 147 | 161 | 
| 148 void MouseWatcher::NotifyListener() { | 162 void MouseWatcher::NotifyListener() { | 
| 149 observer_.reset(NULL); | 163 observer_.reset(NULL); | 
| 150 listener_->MouseMovedOutOfView(); | 164 listener_->MouseMovedOutOfView(); | 
| 151 } | 165 } | 
| 152 | 166 | 
| 153 } // namespace views | 167 } // namespace views | 
| OLD | NEW |