Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(94)

Side by Side Diff: ui/views/mouse_watcher.cc

Issue 9309110: Refactored MouseWatcher to allow regions other than Views to (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Review nits Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/views/mouse_watcher.h ('k') | ui/views/mouse_watcher_view_host.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 "ui/views/mouse_watcher.h" 5 #include "ui/views/mouse_watcher.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/compiler_specific.h" 8 #include "base/compiler_specific.h"
9 #include "base/event_types.h" 9 #include "base/event_types.h"
10 #include "base/memory/weak_ptr.h" 10 #include "base/memory/weak_ptr.h"
11 #include "base/message_loop.h" 11 #include "base/message_loop.h"
12 #include "ui/base/events.h" 12 #include "ui/base/events.h"
13 #include "ui/gfx/screen.h" 13 #include "ui/gfx/screen.h"
14 #include "ui/views/view.h"
15 #include "ui/views/widget/widget.h"
16 14
17 namespace views { 15 namespace views {
18 16
19 // Amount of time between when the mouse moves outside the view's zone and when 17 // Amount of time between when the mouse moves outside the Host's zone and when
20 // the listener is notified. 18 // the listener is notified.
21 const int kNotifyListenerTimeMs = 300; 19 const int kNotifyListenerTimeMs = 300;
22 20
23 class MouseWatcher::Observer : public MessageLoopForUI::Observer { 21 class MouseWatcher::Observer : public MessageLoopForUI::Observer {
24 public: 22 public:
25 explicit Observer(MouseWatcher* mouse_watcher) 23 explicit Observer(MouseWatcher* mouse_watcher)
26 : mouse_watcher_(mouse_watcher), 24 : mouse_watcher_(mouse_watcher),
27 ALLOW_THIS_IN_INITIALIZER_LIST(notify_listener_factory_(this)) { 25 ALLOW_THIS_IN_INITIALIZER_LIST(notify_listener_factory_(this)) {
28 MessageLoopForUI::current()->AddObserver(this); 26 MessageLoopForUI::current()->AddObserver(this);
29 } 27 }
30 28
31 ~Observer() { 29 ~Observer() {
32 MessageLoopForUI::current()->RemoveObserver(this); 30 MessageLoopForUI::current()->RemoveObserver(this);
33 } 31 }
34 32
35 // MessageLoop::Observer implementation: 33 // MessageLoop::Observer implementation:
36 #if defined(OS_WIN) 34 #if defined(OS_WIN)
37 virtual base::EventStatus WillProcessEvent( 35 virtual base::EventStatus WillProcessEvent(
38 const base::NativeEvent& event) OVERRIDE { 36 const base::NativeEvent& event) OVERRIDE {
39 return base::EVENT_CONTINUE; 37 return base::EVENT_CONTINUE;
40 } 38 }
41 39
42 virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE { 40 virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE {
43 // We spy on three different Windows messages here to see if the mouse has 41 // We spy on three different Windows messages here to see if the mouse has
44 // moved out of the bounds of the view. The messages are: 42 // moved out of the bounds of the current view. The messages are:
45 // 43 //
46 // WM_MOUSEMOVE: 44 // WM_MOUSEMOVE:
47 // For when the mouse moves from the view into the rest of the browser UI, 45 // For when the mouse moves from the view into the rest of the browser UI,
48 // i.e. within the bounds of the same windows HWND. 46 // i.e. within the bounds of the same windows HWND.
49 // WM_MOUSELEAVE: 47 // WM_MOUSELEAVE:
50 // For when the mouse moves out of the bounds of the view's HWND. 48 // For when the mouse moves out of the bounds of the view's HWND.
51 // WM_NCMOUSELEAVE: 49 // WM_NCMOUSELEAVE:
52 // For notification when the mouse leaves the _non-client_ area. 50 // For notification when the mouse leaves the _non-client_ area.
53 // 51 //
54 switch (event.message) { 52 switch (event.message) {
55 case WM_MOUSEMOVE: 53 case WM_MOUSEMOVE:
56 HandleGlobalMouseMoveEvent(false); 54 HandleGlobalMouseMoveEvent(MouseWatcherHost::MOUSE_MOVE);
57 break; 55 break;
58 case WM_MOUSELEAVE: 56 case WM_MOUSELEAVE:
59 case WM_NCMOUSELEAVE: 57 case WM_NCMOUSELEAVE:
60 HandleGlobalMouseMoveEvent(true); 58 HandleGlobalMouseMoveEvent(MouseWatcherHost::MOUSE_EXIT);
61 break; 59 break;
62 } 60 }
63 } 61 }
64 #elif defined(USE_WAYLAND) 62 #elif defined(USE_WAYLAND)
65 virtual MessageLoopForUI::Observer::EventStatus WillProcessEvent( 63 virtual MessageLoopForUI::Observer::EventStatus WillProcessEvent(
66 base::wayland::WaylandEvent* event) OVERRIDE { 64 base::wayland::WaylandEvent* event) OVERRIDE {
67 switch (event->type) { 65 switch (event->type) {
68 case base::wayland::WAYLAND_MOTION: 66 case base::wayland::WAYLAND_MOTION:
69 HandleGlobalMouseMoveEvent(false); 67 HandleGlobalMouseMoveEvent(MouseWatcherHost::MOUSE_MOVE);
70 break; 68 break;
71 case base::wayland::WAYLAND_POINTER_FOCUS: 69 case base::wayland::WAYLAND_POINTER_FOCUS:
72 if (!event->pointer_focus.state) 70 if (!event->pointer_focus.state)
73 HandleGlobalMouseMoveEvent(true); 71 HandleGlobalMouseMoveEvent(MouseWatcherHost::MOUSE_EXIT);
74 break; 72 break;
75 default: 73 default:
76 break; 74 break;
77 } 75 }
78 return EVENT_CONTINUE; 76 return EVENT_CONTINUE;
79 } 77 }
80 #elif defined(USE_AURA) 78 #elif defined(USE_AURA)
81 virtual base::EventStatus WillProcessEvent( 79 virtual base::EventStatus WillProcessEvent(
82 const base::NativeEvent& event) OVERRIDE { 80 const base::NativeEvent& event) OVERRIDE {
83 return base::EVENT_CONTINUE; 81 return base::EVENT_CONTINUE;
84 } 82 }
85 virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE { 83 virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE {
86 switch (ui::EventTypeFromNative(event)) { 84 switch (ui::EventTypeFromNative(event)) {
87 case ui::ET_MOUSE_MOVED: 85 case ui::ET_MOUSE_MOVED:
88 case ui::ET_MOUSE_DRAGGED: 86 case ui::ET_MOUSE_DRAGGED:
89 // DRAGGED is a special case of MOVED. See events_win.cc/events_x.cc. 87 // DRAGGED is a special case of MOVED. See events_win.cc/events_x.cc.
90 HandleGlobalMouseMoveEvent(false); 88 HandleGlobalMouseMoveEvent(MouseWatcherHost::MOUSE_MOVE);
91 break; 89 break;
92 case ui::ET_MOUSE_EXITED: 90 case ui::ET_MOUSE_EXITED:
93 HandleGlobalMouseMoveEvent(true); 91 HandleGlobalMouseMoveEvent(MouseWatcherHost::MOUSE_EXIT);
94 break; 92 break;
95 default: 93 default:
96 break; 94 break;
97 } 95 }
98 } 96 }
99 #elif defined(TOOLKIT_USES_GTK) 97 #elif defined(TOOLKIT_USES_GTK)
100 virtual void WillProcessEvent(GdkEvent* event) OVERRIDE { 98 virtual void WillProcessEvent(GdkEvent* event) OVERRIDE {
101 } 99 }
102 100
103 virtual void DidProcessEvent(GdkEvent* event) OVERRIDE { 101 virtual void DidProcessEvent(GdkEvent* event) OVERRIDE {
104 switch (event->type) { 102 switch (event->type) {
105 case GDK_MOTION_NOTIFY: 103 case GDK_MOTION_NOTIFY:
106 HandleGlobalMouseMoveEvent(false); 104 HandleGlobalMouseMoveEvent(MOUSE_MOVE);
107 break; 105 break;
108 case GDK_LEAVE_NOTIFY: 106 case GDK_LEAVE_NOTIFY:
109 HandleGlobalMouseMoveEvent(true); 107 HandleGlobalMouseMoveEvent(MOUSE_EXIT);
110 break; 108 break;
111 default: 109 default:
112 break; 110 break;
113 } 111 }
114 } 112 }
115 #endif 113 #endif
116 114
117 private: 115 private:
118 View* view() const { return mouse_watcher_->host_; } 116 MouseWatcherHost* host() const { return mouse_watcher_->host_.get(); }
119
120 // Returns whether or not the cursor is currently in the view's "zone" which
121 // is defined as a slightly larger region than the view.
122 bool IsCursorInViewZone() {
123 gfx::Rect bounds = view()->GetLocalBounds();
124 gfx::Point view_topleft(bounds.origin());
125 View::ConvertPointToScreen(view(), &view_topleft);
126 bounds.set_origin(view_topleft);
127 bounds.SetRect(view_topleft.x() - mouse_watcher_->hot_zone_insets_.left(),
128 view_topleft.y() - mouse_watcher_->hot_zone_insets_.top(),
129 bounds.width() + mouse_watcher_->hot_zone_insets_.width(),
130 bounds.height() + mouse_watcher_->hot_zone_insets_.height());
131
132 gfx::Point cursor_point = gfx::Screen::GetCursorScreenPoint();
133
134 return bounds.Contains(cursor_point.x(), cursor_point.y());
135 }
136
137 // Returns true if the mouse is over the view's window.
138 bool IsMouseOverWindow() {
139 Widget* widget = view()->GetWidget();
140 if (!widget)
141 return false;
142
143 return gfx::Screen::GetWindowAtCursorScreenPoint() ==
144 widget->GetNativeWindow();
145 }
146 117
147 // Called from the message loop observer when a mouse movement has occurred. 118 // Called from the message loop observer when a mouse movement has occurred.
148 void HandleGlobalMouseMoveEvent(bool check_window) { 119 void HandleGlobalMouseMoveEvent(MouseWatcherHost::MouseEventType event_type) {
149 bool in_view = IsCursorInViewZone(); 120 bool contained = host()->Contains(
150 if (!in_view || (check_window && !IsMouseOverWindow())) { 121 gfx::Screen::GetCursorScreenPoint(), event_type);
151 // Mouse moved outside the view's zone, start a timer to notify the 122 if (!contained) {
123 // Mouse moved outside the host's zone, start a timer to notify the
152 // listener. 124 // listener.
153 if (!notify_listener_factory_.HasWeakPtrs()) { 125 if (!notify_listener_factory_.HasWeakPtrs()) {
154 MessageLoop::current()->PostDelayedTask( 126 MessageLoop::current()->PostDelayedTask(
155 FROM_HERE, 127 FROM_HERE,
156 base::Bind(&Observer::NotifyListener, 128 base::Bind(&Observer::NotifyListener,
157 notify_listener_factory_.GetWeakPtr()), 129 notify_listener_factory_.GetWeakPtr()),
158 !in_view ? kNotifyListenerTimeMs : 130 event_type ==
159 mouse_watcher_->notify_on_exit_time_ms_); 131 MouseWatcherHost::MOUSE_MOVE ? kNotifyListenerTimeMs :
132 mouse_watcher_->notify_on_exit_time_ms_);
160 } 133 }
161 } else { 134 } else {
162 // Mouse moved quickly out of the view and then into it again, so cancel 135 // Mouse moved quickly out of the host and then into it again, so cancel
163 // the timer. 136 // the timer.
164 notify_listener_factory_.InvalidateWeakPtrs(); 137 notify_listener_factory_.InvalidateWeakPtrs();
165 } 138 }
166 } 139 }
167 140
168 void NotifyListener() { 141 void NotifyListener() {
169 mouse_watcher_->NotifyListener(); 142 mouse_watcher_->NotifyListener();
170 // WARNING: we've been deleted. 143 // WARNING: we've been deleted.
171 } 144 }
172 145
173 private: 146 private:
174 MouseWatcher* mouse_watcher_; 147 MouseWatcher* mouse_watcher_;
175 148
176 // A factory that is used to construct a delayed callback to the listener. 149 // A factory that is used to construct a delayed callback to the listener.
177 base::WeakPtrFactory<Observer> notify_listener_factory_; 150 base::WeakPtrFactory<Observer> notify_listener_factory_;
178 151
179 DISALLOW_COPY_AND_ASSIGN(Observer); 152 DISALLOW_COPY_AND_ASSIGN(Observer);
180 }; 153 };
181 154
182 MouseWatcherListener::~MouseWatcherListener() { 155 MouseWatcherListener::~MouseWatcherListener() {
183 } 156 }
184 157
185 MouseWatcher::MouseWatcher(View* host, 158 MouseWatcherHost::~MouseWatcherHost() {
186 MouseWatcherListener* listener, 159 }
187 const gfx::Insets& hot_zone_insets) 160
161 MouseWatcher::MouseWatcher(MouseWatcherHost* host,
162 MouseWatcherListener* listener)
188 : host_(host), 163 : host_(host),
189 listener_(listener), 164 listener_(listener),
190 hot_zone_insets_(hot_zone_insets),
191 notify_on_exit_time_ms_(kNotifyListenerTimeMs) { 165 notify_on_exit_time_ms_(kNotifyListenerTimeMs) {
192 } 166 }
193 167
194 MouseWatcher::~MouseWatcher() { 168 MouseWatcher::~MouseWatcher() {
195 } 169 }
196 170
197 void MouseWatcher::Start() { 171 void MouseWatcher::Start() {
198 if (!is_observing()) 172 if (!is_observing())
199 observer_.reset(new Observer(this)); 173 observer_.reset(new Observer(this));
200 } 174 }
201 175
202 void MouseWatcher::Stop() { 176 void MouseWatcher::Stop() {
203 observer_.reset(NULL); 177 observer_.reset(NULL);
204 } 178 }
205 179
206 void MouseWatcher::NotifyListener() { 180 void MouseWatcher::NotifyListener() {
207 observer_.reset(NULL); 181 observer_.reset(NULL);
208 listener_->MouseMovedOutOfView(); 182 listener_->MouseMovedOutOfHost();
209 } 183 }
210 184
211 } // namespace views 185 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/mouse_watcher.h ('k') | ui/views/mouse_watcher_view_host.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698