OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/corewm/tooltip_controller.h" | 5 #include "ui/views/corewm/tooltip_controller.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/strings/string_util.h" | 9 #include "base/strings/string_util.h" |
10 #include "base/time/time.h" | 10 #include "base/time/time.h" |
(...skipping 10 matching lines...) Expand all Loading... | |
21 #include "ui/views/widget/tooltip_manager.h" | 21 #include "ui/views/widget/tooltip_manager.h" |
22 #include "ui/wm/public/drag_drop_client.h" | 22 #include "ui/wm/public/drag_drop_client.h" |
23 | 23 |
24 namespace views { | 24 namespace views { |
25 namespace corewm { | 25 namespace corewm { |
26 namespace { | 26 namespace { |
27 | 27 |
28 const int kTooltipTimeoutMs = 500; | 28 const int kTooltipTimeoutMs = 500; |
29 const int kDefaultTooltipShownTimeoutMs = 10000; | 29 const int kDefaultTooltipShownTimeoutMs = 10000; |
30 | 30 |
31 // Delay mouse events so that they are dispatched if there are no mouse location | |
32 // events pending. Even a short delay delays them until the mouse is steady. | |
33 const int kMouseMoveDelay = 10; | |
34 | |
31 // Returns true if |target| is a valid window to get the tooltip from. | 35 // Returns true if |target| is a valid window to get the tooltip from. |
32 // |event_target| is the original target from the event and |target| the window | 36 // |event_target| is the original target from the event and |target| the window |
33 // at the same location. | 37 // at the same location. |
34 bool IsValidTarget(aura::Window* event_target, aura::Window* target) { | 38 bool IsValidTarget(aura::Window* event_target, aura::Window* target) { |
35 if (!target || (event_target == target)) | 39 if (!target || (event_target == target)) |
36 return true; | 40 return true; |
37 | 41 |
38 void* event_target_grouping_id = event_target->GetNativeWindowProperty( | 42 void* event_target_grouping_id = event_target->GetNativeWindowProperty( |
39 TooltipManager::kGroupingPropertyKey); | 43 TooltipManager::kGroupingPropertyKey); |
40 void* target_grouping_id = target->GetNativeWindowProperty( | 44 void* target_grouping_id = target->GetNativeWindowProperty( |
41 TooltipManager::kGroupingPropertyKey); | 45 TooltipManager::kGroupingPropertyKey); |
42 return event_target_grouping_id && | 46 return event_target_grouping_id && |
43 event_target_grouping_id == target_grouping_id; | 47 event_target_grouping_id == target_grouping_id; |
44 } | 48 } |
45 | 49 |
46 // Returns the target (the Window tooltip text comes from) based on the event. | 50 // Returns the target (the Window tooltip text comes from) based on the event. |
47 // If a Window other than event.target() is returned, |location| is adjusted | 51 // If a Window other than event.target() is returned, |location| is adjusted |
48 // to be in the coordinates of the returned Window. | 52 // to be in the coordinates of the returned Window. |
49 aura::Window* GetTooltipTarget(const ui::MouseEvent& event, | 53 aura::Window* GetTooltipTarget(ui::EventType event_type, |
54 aura::Window* target, | |
50 gfx::Point* location) { | 55 gfx::Point* location) { |
51 switch (event.type()) { | 56 switch (event_type) { |
52 case ui::ET_MOUSE_CAPTURE_CHANGED: | 57 case ui::ET_MOUSE_CAPTURE_CHANGED: |
53 // On windows we can get a capture changed without an exit. We need to | 58 // On windows we can get a capture changed without an exit. We need to |
54 // reset state when this happens else the tooltip may incorrectly show. | 59 // reset state when this happens else the tooltip may incorrectly show. |
55 return NULL; | 60 return NULL; |
56 case ui::ET_MOUSE_EXITED: | 61 case ui::ET_MOUSE_EXITED: |
57 return NULL; | 62 return NULL; |
58 case ui::ET_MOUSE_MOVED: | 63 case ui::ET_MOUSE_MOVED: |
59 case ui::ET_MOUSE_DRAGGED: { | 64 case ui::ET_MOUSE_DRAGGED: { |
60 aura::Window* event_target = static_cast<aura::Window*>(event.target()); | 65 aura::Window* event_target = target; |
61 if (!event_target) | 66 if (!event_target) |
62 return NULL; | 67 return NULL; |
63 | 68 |
64 // If a window other than |event_target| has capture, ignore the event. | 69 // If a window other than |event_target| has capture, ignore the event. |
65 // This can happen when RootWindow creates events when showing/hiding, or | 70 // This can happen when RootWindow creates events when showing/hiding, or |
66 // the system generates an extra event. We have to check | 71 // the system generates an extra event. We have to check |
67 // GetGlobalCaptureWindow() as Windows does not use a singleton | 72 // GetGlobalCaptureWindow() as Windows does not use a singleton |
68 // CaptureClient. | 73 // CaptureClient. |
69 if (!event_target->HasCapture()) { | 74 if (!event_target->HasCapture()) { |
70 aura::Window* root = event_target->GetRootWindow(); | 75 aura::Window* root = event_target->GetRootWindow(); |
71 if (root) { | 76 if (root) { |
72 aura::client::CaptureClient* capture_client = | 77 aura::client::CaptureClient* capture_client = |
73 aura::client::GetCaptureClient(root); | 78 aura::client::GetCaptureClient(root); |
74 if (capture_client) { | 79 if (capture_client) { |
75 aura::Window* capture_window = | 80 aura::Window* capture_window = |
76 capture_client->GetGlobalCaptureWindow(); | 81 capture_client->GetGlobalCaptureWindow(); |
77 if (capture_window && event_target != capture_window) | 82 if (capture_window && event_target != capture_window) |
78 return NULL; | 83 return NULL; |
79 } | 84 } |
80 } | 85 } |
81 return event_target; | 86 return event_target; |
82 } | 87 } |
83 | 88 |
84 // If |target| has capture all events go to it, even if the mouse is | 89 // If |target| has capture all events go to it, even if the mouse is |
85 // really over another window. Find the real window the mouse is over. | 90 // really over another window. Find the real window the mouse is over. |
86 gfx::Point screen_loc(event.location()); | 91 gfx::Point screen_loc(*location); |
87 aura::client::GetScreenPositionClient(event_target->GetRootWindow())-> | 92 aura::client::GetScreenPositionClient(event_target->GetRootWindow())-> |
88 ConvertPointToScreen(event_target, &screen_loc); | 93 ConvertPointToScreen(event_target, &screen_loc); |
89 gfx::Screen* screen = gfx::Screen::GetScreenFor(event_target); | 94 gfx::Screen* screen = gfx::Screen::GetScreenFor(event_target); |
90 aura::Window* target = screen->GetWindowAtScreenPoint(screen_loc); | 95 aura::Window* target = screen->GetWindowAtScreenPoint(screen_loc); |
91 if (!target) | 96 if (!target) |
92 return NULL; | 97 return NULL; |
93 gfx::Point target_loc(screen_loc); | 98 gfx::Point target_loc(screen_loc); |
94 aura::client::GetScreenPositionClient(target->GetRootWindow())-> | 99 aura::client::GetScreenPositionClient(target->GetRootWindow())-> |
95 ConvertPointFromScreen(target, &target_loc); | 100 ConvertPointFromScreen(target, &target_loc); |
96 aura::Window* screen_target = target->GetEventHandlerForPoint(target_loc); | 101 aura::Window* screen_target = target->GetEventHandlerForPoint(target_loc); |
97 if (!IsValidTarget(event_target, screen_target)) | 102 if (!IsValidTarget(event_target, screen_target)) |
pkotwicz
2014/05/07 22:45:08
Idea: It might be useful to check whether there ar
varkha
2014/05/07 23:08:18
This may speed this method but with the throttling
| |
98 return NULL; | 103 return NULL; |
99 | 104 |
100 aura::Window::ConvertPointToTarget(screen_target, target, &target_loc); | 105 aura::Window::ConvertPointToTarget(screen_target, target, &target_loc); |
101 *location = target_loc; | 106 *location = target_loc; |
102 return screen_target; | 107 return screen_target; |
103 } | 108 } |
104 default: | 109 default: |
105 NOTREACHED(); | 110 NOTREACHED(); |
106 break; | 111 break; |
107 } | 112 } |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
178 TooltipShownTimerFired(); | 183 TooltipShownTimerFired(); |
179 } | 184 } |
180 } | 185 } |
181 | 186 |
182 void TooltipController::OnMouseEvent(ui::MouseEvent* event) { | 187 void TooltipController::OnMouseEvent(ui::MouseEvent* event) { |
183 switch (event->type()) { | 188 switch (event->type()) { |
184 case ui::ET_MOUSE_CAPTURE_CHANGED: | 189 case ui::ET_MOUSE_CAPTURE_CHANGED: |
185 case ui::ET_MOUSE_EXITED: | 190 case ui::ET_MOUSE_EXITED: |
186 case ui::ET_MOUSE_MOVED: | 191 case ui::ET_MOUSE_MOVED: |
187 case ui::ET_MOUSE_DRAGGED: { | 192 case ui::ET_MOUSE_DRAGGED: { |
188 curr_mouse_loc_ = event->location(); | 193 last_mouse_location_ = event->location(); |
189 aura::Window* target = GetTooltipTarget(*event, &curr_mouse_loc_); | 194 mouse_event_timer_.Start( |
190 SetTooltipWindow(target); | 195 FROM_HERE, |
191 if (tooltip_timer_.IsRunning()) | 196 base::TimeDelta::FromMilliseconds(kMouseMoveDelay), |
192 tooltip_timer_.Reset(); | 197 base::Bind(&TooltipController::DispatchMouseEvent, |
sky
2014/05/08 19:05:55
What happens if we enter some sort of nested messa
varkha
2014/05/13 19:30:55
We would need to synchronously process any pending
| |
193 | 198 base::Unretained(this), |
194 if (tooltip_->IsVisible()) | 199 event->type(), |
195 UpdateIfRequired(); | 200 static_cast<aura::Window*>(event->target()))); |
sky
2014/05/08 19:05:55
What if window is destroyed between now and when t
varkha
2014/05/13 19:30:55
We could maintain a set of windows for which we ha
| |
196 break; | 201 break; |
197 } | 202 } |
198 case ui::ET_MOUSE_PRESSED: | 203 case ui::ET_MOUSE_PRESSED: |
199 if ((event->flags() & ui::EF_IS_NON_CLIENT) == 0) { | 204 if ((event->flags() & ui::EF_IS_NON_CLIENT) == 0) { |
sky
2014/05/08 19:05:55
If you process the above async and this (and whell
varkha
2014/05/13 19:30:55
It could. It should be easy to just call a sync di
| |
200 aura::Window* target = static_cast<aura::Window*>(event->target()); | 205 aura::Window* target = static_cast<aura::Window*>(event->target()); |
201 // We don't get a release for non-client areas. | 206 // We don't get a release for non-client areas. |
202 tooltip_window_at_mouse_press_ = target; | 207 tooltip_window_at_mouse_press_ = target; |
203 if (target) | 208 if (target) |
204 tooltip_text_at_mouse_press_ = aura::client::GetTooltipText(target); | 209 tooltip_text_at_mouse_press_ = aura::client::GetTooltipText(target); |
205 } | 210 } |
206 tooltip_->Hide(); | 211 tooltip_->Hide(); |
207 break; | 212 break; |
208 case ui::ET_MOUSEWHEEL: | 213 case ui::ET_MOUSEWHEEL: |
209 // Hide the tooltip for click, release, drag, wheel events. | 214 // Hide the tooltip for click, release, drag, wheel events. |
(...skipping 22 matching lines...) Expand all Loading... | |
232 if (tooltip_window_ == window) { | 237 if (tooltip_window_ == window) { |
233 tooltip_->Hide(); | 238 tooltip_->Hide(); |
234 tooltip_shown_timeout_map_.erase(tooltip_window_); | 239 tooltip_shown_timeout_map_.erase(tooltip_window_); |
235 tooltip_window_ = NULL; | 240 tooltip_window_ = NULL; |
236 } | 241 } |
237 } | 242 } |
238 | 243 |
239 //////////////////////////////////////////////////////////////////////////////// | 244 //////////////////////////////////////////////////////////////////////////////// |
240 // TooltipController private: | 245 // TooltipController private: |
241 | 246 |
247 void TooltipController::DispatchMouseEvent(ui::EventType event_type, | |
248 aura::Window* target) { | |
249 curr_mouse_loc_ = last_mouse_location_; | |
250 target = GetTooltipTarget(event_type, target, &curr_mouse_loc_); | |
251 SetTooltipWindow(target); | |
252 if (tooltip_timer_.IsRunning()) | |
253 tooltip_timer_.Reset(); | |
254 | |
255 if (tooltip_->IsVisible()) | |
256 UpdateIfRequired(); | |
257 } | |
258 | |
242 void TooltipController::TooltipTimerFired() { | 259 void TooltipController::TooltipTimerFired() { |
243 UpdateIfRequired(); | 260 UpdateIfRequired(); |
244 } | 261 } |
245 | 262 |
246 void TooltipController::TooltipShownTimerFired() { | 263 void TooltipController::TooltipShownTimerFired() { |
247 tooltip_->Hide(); | 264 tooltip_->Hide(); |
248 | 265 |
249 // Since the user presumably no longer needs the tooltip, we also stop the | 266 // Since the user presumably no longer needs the tooltip, we also stop the |
250 // tooltip timer so that tooltip does not pop back up. We will restart this | 267 // tooltip timer so that tooltip does not pop back up. We will restart this |
251 // timer if the tooltip changes (see UpdateTooltip()). | 268 // timer if the tooltip changes (see UpdateTooltip()). |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
344 return; | 361 return; |
345 if (tooltip_window_) | 362 if (tooltip_window_) |
346 tooltip_window_->RemoveObserver(this); | 363 tooltip_window_->RemoveObserver(this); |
347 tooltip_window_ = target; | 364 tooltip_window_ = target; |
348 if (tooltip_window_) | 365 if (tooltip_window_) |
349 tooltip_window_->AddObserver(this); | 366 tooltip_window_->AddObserver(this); |
350 } | 367 } |
351 | 368 |
352 } // namespace corewm | 369 } // namespace corewm |
353 } // namespace views | 370 } // namespace views |
OLD | NEW |