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

Side by Side Diff: views/mouse_watcher.cc

Issue 8735009: views: Move some random files from views/ to ui/views/. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years 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 | « views/mouse_watcher.h ('k') | views/view.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "views/mouse_watcher.h"
6
7 #include "base/bind.h"
8 #include "base/compiler_specific.h"
9 #include "base/event_types.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/message_loop.h"
12 #include "ui/base/events.h"
13 #include "ui/gfx/screen.h"
14 #include "ui/views/widget/widget.h"
15 #include "views/view.h"
16
17 namespace views {
18
19 // Amount of time between when the mouse moves outside the view's zone and when
20 // the listener is notified.
21 const int kNotifyListenerTimeMs = 300;
22
23 class MouseWatcher::Observer : public MessageLoopForUI::Observer {
24 public:
25 explicit Observer(MouseWatcher* mouse_watcher)
26 : mouse_watcher_(mouse_watcher),
27 ALLOW_THIS_IN_INITIALIZER_LIST(notify_listener_factory_(this)) {
28 MessageLoopForUI::current()->AddObserver(this);
29 }
30
31 ~Observer() {
32 MessageLoopForUI::current()->RemoveObserver(this);
33 }
34
35 // MessageLoop::Observer implementation:
36 #if defined(OS_WIN)
37 virtual base::EventStatus WillProcessEvent(
38 const base::NativeEvent& event) OVERRIDE {
39 return base::EVENT_CONTINUE;
40 }
41
42 virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE {
43 // 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:
45 //
46 // WM_MOUSEMOVE:
47 // 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.
49 // WM_MOUSELEAVE:
50 // For when the mouse moves out of the bounds of the view's HWND.
51 // WM_NCMOUSELEAVE:
52 // For notification when the mouse leaves the _non-client_ area.
53 //
54 switch (event.message) {
55 case WM_MOUSEMOVE:
56 HandleGlobalMouseMoveEvent(false);
57 break;
58 case WM_MOUSELEAVE:
59 case WM_NCMOUSELEAVE:
60 HandleGlobalMouseMoveEvent(true);
61 break;
62 }
63 }
64 #elif defined(USE_WAYLAND)
65 virtual MessageLoopForUI::Observer::EventStatus WillProcessEvent(
66 base::wayland::WaylandEvent* event) OVERRIDE {
67 switch (event->type) {
68 case base::wayland::WAYLAND_MOTION:
69 HandleGlobalMouseMoveEvent(false);
70 break;
71 case base::wayland::WAYLAND_POINTER_FOCUS:
72 if (!event->pointer_focus.state)
73 HandleGlobalMouseMoveEvent(true);
74 break;
75 default:
76 break;
77 }
78 return EVENT_CONTINUE;
79 }
80 #elif defined(USE_AURA)
81 virtual base::EventStatus WillProcessEvent(
82 const base::NativeEvent& event) OVERRIDE {
83 return base::EVENT_CONTINUE;
84 }
85 virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE {
86 switch (ui::EventTypeFromNative(event)) {
87 case ui::ET_MOUSE_MOVED:
88 case ui::ET_MOUSE_DRAGGED:
89 // DRAGGED is a special case of MOVED. See events_win.cc/events_x.cc.
90 HandleGlobalMouseMoveEvent(false);
91 break;
92 case ui::ET_MOUSE_EXITED:
93 HandleGlobalMouseMoveEvent(true);
94 break;
95 default:
96 break;
97 }
98 }
99 #elif defined(TOOLKIT_USES_GTK)
100 virtual void WillProcessEvent(GdkEvent* event) OVERRIDE {
101 }
102
103 virtual void DidProcessEvent(GdkEvent* event) OVERRIDE {
104 switch (event->type) {
105 case GDK_MOTION_NOTIFY:
106 HandleGlobalMouseMoveEvent(false);
107 break;
108 case GDK_LEAVE_NOTIFY:
109 HandleGlobalMouseMoveEvent(true);
110 break;
111 default:
112 break;
113 }
114 }
115 #endif
116
117 private:
118 View* view() const { return mouse_watcher_->host_; }
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
147 // Called from the message loop observer when a mouse movement has occurred.
148 void HandleGlobalMouseMoveEvent(bool check_window) {
149 bool in_view = IsCursorInViewZone();
150 if (!in_view || (check_window && !IsMouseOverWindow())) {
151 // Mouse moved outside the view's zone, start a timer to notify the
152 // listener.
153 if (!notify_listener_factory_.HasWeakPtrs()) {
154 MessageLoop::current()->PostDelayedTask(
155 FROM_HERE,
156 base::Bind(&Observer::NotifyListener,
157 notify_listener_factory_.GetWeakPtr()),
158 !in_view ? kNotifyListenerTimeMs :
159 mouse_watcher_->notify_on_exit_time_ms_);
160 }
161 } else {
162 // Mouse moved quickly out of the view and then into it again, so cancel
163 // the timer.
164 notify_listener_factory_.InvalidateWeakPtrs();
165 }
166 }
167
168 void NotifyListener() {
169 mouse_watcher_->NotifyListener();
170 // WARNING: we've been deleted.
171 }
172
173 private:
174 MouseWatcher* mouse_watcher_;
175
176 // A factory that is used to construct a delayed callback to the listener.
177 base::WeakPtrFactory<Observer> notify_listener_factory_;
178
179 DISALLOW_COPY_AND_ASSIGN(Observer);
180 };
181
182 MouseWatcherListener::~MouseWatcherListener() {
183 }
184
185 MouseWatcher::MouseWatcher(View* host,
186 MouseWatcherListener* listener,
187 const gfx::Insets& hot_zone_insets)
188 : host_(host),
189 listener_(listener),
190 hot_zone_insets_(hot_zone_insets),
191 notify_on_exit_time_ms_(kNotifyListenerTimeMs) {
192 }
193
194 MouseWatcher::~MouseWatcher() {
195 }
196
197 void MouseWatcher::Start() {
198 if (!is_observing())
199 observer_.reset(new Observer(this));
200 }
201
202 void MouseWatcher::Stop() {
203 observer_.reset(NULL);
204 }
205
206 void MouseWatcher::NotifyListener() {
207 observer_.reset(NULL);
208 listener_->MouseMovedOutOfView();
209 }
210
211 } // namespace views
OLDNEW
« no previous file with comments | « views/mouse_watcher.h ('k') | views/view.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698