Chromium Code Reviews| 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 |