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

Side by Side Diff: ui/views/corewm/tooltip_controller.cc

Issue 2652833002: Remove infinite spin, make tooltip delay consistent (Closed)
Patch Set: Fix nits. Created 3 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
« no previous file with comments | « ui/views/corewm/tooltip_controller.h ('k') | ui/views/corewm/tooltip_controller_test_helper.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) 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 <stddef.h> 7 #include <stddef.h>
8 8
9 #include <utility> 9 #include <utility>
10 #include <vector> 10 #include <vector>
11 11
12 #include "base/strings/string_util.h" 12 #include "base/strings/string_util.h"
13 #include "base/time/time.h" 13 #include "base/time/time.h"
14 #include "build/build_config.h" 14 #include "build/build_config.h"
15 #include "ui/aura/client/capture_client.h" 15 #include "ui/aura/client/capture_client.h"
16 #include "ui/aura/client/cursor_client.h" 16 #include "ui/aura/client/cursor_client.h"
17 #include "ui/aura/client/drag_drop_client.h" 17 #include "ui/aura/client/drag_drop_client.h"
18 #include "ui/aura/client/screen_position_client.h" 18 #include "ui/aura/client/screen_position_client.h"
19 #include "ui/aura/env.h" 19 #include "ui/aura/env.h"
20 #include "ui/aura/window.h" 20 #include "ui/aura/window.h"
21 #include "ui/display/screen.h" 21 #include "ui/display/screen.h"
22 #include "ui/events/event.h" 22 #include "ui/events/event.h"
23 #include "ui/gfx/font.h" 23 #include "ui/gfx/font.h"
24 #include "ui/gfx/geometry/rect.h" 24 #include "ui/gfx/geometry/rect.h"
25 #include "ui/gfx/text_elider.h" 25 #include "ui/gfx/text_elider.h"
26 #include "ui/views/corewm/tooltip.h" 26 #include "ui/views/corewm/tooltip.h"
27 #include "ui/views/widget/tooltip_manager.h" 27 #include "ui/views/widget/tooltip_manager.h"
28 #include "ui/wm/public/tooltip_client.h"
28 29
29 namespace views { 30 namespace views {
30 namespace corewm { 31 namespace corewm {
31 namespace { 32 namespace {
32 33
33 const int kTooltipTimeoutMs = 500; 34 const int kDelayForTooltipUpdateInMs = 500;
34 const int kDefaultTooltipShownTimeoutMs = 10000; 35 const int kDefaultTooltipShownTimeoutMs = 10000;
35 #if defined(OS_WIN) 36 #if defined(OS_WIN)
36 // Drawing a long word in tooltip is very slow on Windows. crbug.com/513693 37 // Drawing a long word in tooltip is very slow on Windows. crbug.com/513693
37 const size_t kMaxTooltipLength = 1024; 38 const size_t kMaxTooltipLength = 1024;
38 #else 39 #else
39 const size_t kMaxTooltipLength = 2048; 40 const size_t kMaxTooltipLength = 2048;
40 #endif 41 #endif
41 42
42 // Returns true if |target| is a valid window to get the tooltip from. 43 // Returns true if |target| is a valid window to get the tooltip from.
43 // |event_target| is the original target from the event and |target| the window 44 // |event_target| is the original target from the event and |target| the window
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 } // namespace 123 } // namespace
123 124
124 //////////////////////////////////////////////////////////////////////////////// 125 ////////////////////////////////////////////////////////////////////////////////
125 // TooltipController public: 126 // TooltipController public:
126 127
127 TooltipController::TooltipController(std::unique_ptr<Tooltip> tooltip) 128 TooltipController::TooltipController(std::unique_ptr<Tooltip> tooltip)
128 : tooltip_window_(NULL), 129 : tooltip_window_(NULL),
129 tooltip_id_(NULL), 130 tooltip_id_(NULL),
130 tooltip_window_at_mouse_press_(NULL), 131 tooltip_window_at_mouse_press_(NULL),
131 tooltip_(std::move(tooltip)), 132 tooltip_(std::move(tooltip)),
132 tooltips_enabled_(true) { 133 tooltips_enabled_(true),
133 tooltip_timer_.Start(FROM_HERE, 134 tooltip_show_delayed_(true) {}
134 base::TimeDelta::FromMilliseconds(kTooltipTimeoutMs),
135 this, &TooltipController::TooltipTimerFired);
136 }
137 135
138 TooltipController::~TooltipController() { 136 TooltipController::~TooltipController() {
139 if (tooltip_window_) 137 if (tooltip_window_)
140 tooltip_window_->RemoveObserver(this); 138 tooltip_window_->RemoveObserver(this);
141 } 139 }
142 140
143 int TooltipController::GetMaxWidth(const gfx::Point& location) const { 141 int TooltipController::GetMaxWidth(const gfx::Point& location) const {
144 return tooltip_->GetMaxWidth(location); 142 return tooltip_->GetMaxWidth(location);
145 } 143 }
146 144
147 void TooltipController::UpdateTooltip(aura::Window* target) { 145 void TooltipController::UpdateTooltip(aura::Window* target) {
148 // If tooltip is visible, we may want to hide it. If it is not, we are ok. 146 // If tooltip is visible, we may want to hide it. If it is not, we are ok.
149 if (tooltip_window_ == target && tooltip_->IsVisible()) 147 if (tooltip_window_ == target && tooltip_->IsVisible())
150 UpdateIfRequired(); 148 UpdateIfRequired();
151 149
152 // Reset |tooltip_window_at_mouse_press_| if the moving within the same window 150 // Reset |tooltip_window_at_mouse_press_| if the moving within the same window
153 // but over a region that has different tooltip text. By resetting 151 // but over a region that has different tooltip text.
154 // |tooltip_window_at_mouse_press_| we ensure the next time the timer fires
155 // we'll requery for the tooltip text.
156 // This handles the case of clicking on a view, moving within the same window 152 // This handles the case of clicking on a view, moving within the same window
157 // but over a different view, than back to the original. 153 // but over a different view, than back to the original.
158 if (tooltip_window_at_mouse_press_ && 154 if (tooltip_window_at_mouse_press_ &&
159 target == tooltip_window_at_mouse_press_ && 155 target == tooltip_window_at_mouse_press_ &&
160 aura::client::GetTooltipText(target) != tooltip_text_at_mouse_press_) { 156 aura::client::GetTooltipText(target) != tooltip_text_at_mouse_press_) {
161 tooltip_window_at_mouse_press_ = NULL; 157 tooltip_window_at_mouse_press_ = NULL;
162 } 158 }
163
164 // If we had stopped the tooltip timer for some reason, we must restart it if
165 // there is a change in the tooltip.
166 if (!tooltip_timer_.IsRunning()) {
167 if (tooltip_window_ != target || (tooltip_window_ &&
168 tooltip_text_ != aura::client::GetTooltipText(tooltip_window_))) {
169 tooltip_timer_.Start(FROM_HERE,
170 base::TimeDelta::FromMilliseconds(kTooltipTimeoutMs),
171 this, &TooltipController::TooltipTimerFired);
172 }
173 }
174 } 159 }
175 160
176 void TooltipController::SetTooltipShownTimeout(aura::Window* target, 161 void TooltipController::SetTooltipShownTimeout(aura::Window* target,
177 int timeout_in_ms) { 162 int timeout_in_ms) {
178 tooltip_shown_timeout_map_[target] = timeout_in_ms; 163 tooltip_shown_timeout_map_[target] = timeout_in_ms;
179 } 164 }
180 165
181 void TooltipController::SetTooltipsEnabled(bool enable) { 166 void TooltipController::SetTooltipsEnabled(bool enable) {
182 if (tooltips_enabled_ == enable) 167 if (tooltips_enabled_ == enable)
183 return; 168 return;
(...skipping 20 matching lines...) Expand all
204 curr_mouse_loc_ = event->location(); 189 curr_mouse_loc_ = event->location();
205 aura::Window* target = NULL; 190 aura::Window* target = NULL;
206 // Avoid a call to display::Screen::GetWindowAtScreenPoint() since it can 191 // Avoid a call to display::Screen::GetWindowAtScreenPoint() since it can
207 // be very expensive on X11 in cases when the tooltip is hidden anyway. 192 // be very expensive on X11 in cases when the tooltip is hidden anyway.
208 if (tooltips_enabled_ && 193 if (tooltips_enabled_ &&
209 !aura::Env::GetInstance()->IsMouseButtonDown() && 194 !aura::Env::GetInstance()->IsMouseButtonDown() &&
210 !IsDragDropInProgress()) { 195 !IsDragDropInProgress()) {
211 target = GetTooltipTarget(*event, &curr_mouse_loc_); 196 target = GetTooltipTarget(*event, &curr_mouse_loc_);
212 } 197 }
213 SetTooltipWindow(target); 198 SetTooltipWindow(target);
214 if (tooltip_timer_.IsRunning())
215 tooltip_timer_.Reset();
216 199
217 if (tooltip_->IsVisible()) 200 if (tooltip_->IsVisible() ||
201 (tooltip_window_ &&
202 tooltip_text_ != aura::client::GetTooltipText(tooltip_window_)))
218 UpdateIfRequired(); 203 UpdateIfRequired();
219 break; 204 break;
220 } 205 }
221 case ui::ET_MOUSE_PRESSED: 206 case ui::ET_MOUSE_PRESSED:
222 if ((event->flags() & ui::EF_IS_NON_CLIENT) == 0) { 207 if ((event->flags() & ui::EF_IS_NON_CLIENT) == 0) {
223 aura::Window* target = static_cast<aura::Window*>(event->target()); 208 aura::Window* target = static_cast<aura::Window*>(event->target());
224 // We don't get a release for non-client areas. 209 // We don't get a release for non-client areas.
225 tooltip_window_at_mouse_press_ = target; 210 tooltip_window_at_mouse_press_ = target;
226 if (target) 211 if (target)
227 tooltip_text_at_mouse_press_ = aura::client::GetTooltipText(target); 212 tooltip_text_at_mouse_press_ = aura::client::GetTooltipText(target);
228 } 213 }
229 tooltip_->Hide(); 214 tooltip_->Hide();
230 break; 215 break;
231 case ui::ET_MOUSEWHEEL: 216 case ui::ET_MOUSEWHEEL:
232 // Hide the tooltip for click, release, drag, wheel events. 217 // Hide the tooltip for click, release, drag, wheel events.
233 if (tooltip_->IsVisible()) 218 if (tooltip_->IsVisible())
234 tooltip_->Hide(); 219 tooltip_->Hide();
235
236 // Don't reshow the tooltip during scroll.
237 if (tooltip_timer_.IsRunning())
238 tooltip_timer_.Reset();
239 break; 220 break;
240 default: 221 default:
241 break; 222 break;
242 } 223 }
243 } 224 }
244 225
245 void TooltipController::OnTouchEvent(ui::TouchEvent* event) { 226 void TooltipController::OnTouchEvent(ui::TouchEvent* event) {
246 // TODO(varunjain): need to properly implement tooltips for 227 // TODO(varunjain): need to properly implement tooltips for
247 // touch events. 228 // touch events.
248 // Hide the tooltip for touch events. 229 // Hide the tooltip for touch events.
249 tooltip_->Hide(); 230 tooltip_->Hide();
250 SetTooltipWindow(NULL); 231 SetTooltipWindow(NULL);
251 } 232 }
252 233
253 void TooltipController::OnCancelMode(ui::CancelModeEvent* event) { 234 void TooltipController::OnCancelMode(ui::CancelModeEvent* event) {
254 tooltip_->Hide(); 235 tooltip_->Hide();
255 SetTooltipWindow(NULL); 236 SetTooltipWindow(NULL);
256 } 237 }
257 238
239 void TooltipController::OnCursorVisibilityChanged(bool is_visible) {
240 UpdateIfRequired();
241 }
242
258 void TooltipController::OnWindowDestroyed(aura::Window* window) { 243 void TooltipController::OnWindowDestroyed(aura::Window* window) {
259 if (tooltip_window_ == window) { 244 if (tooltip_window_ == window) {
260 tooltip_->Hide(); 245 tooltip_->Hide();
261 tooltip_shown_timeout_map_.erase(tooltip_window_); 246 tooltip_shown_timeout_map_.erase(tooltip_window_);
262 tooltip_window_ = NULL; 247 tooltip_window_ = NULL;
263 } 248 }
264 } 249 }
265 250
251 void TooltipController::OnWindowPropertyChanged(aura::Window* window,
252 const void* key,
253 intptr_t old) {
254 if ((key == aura::client::kTooltipIdKey ||
255 key == aura::client::kTooltipTextKey) &&
256 aura::client::GetTooltipText(window) != base::string16() &&
257 (tooltip_text_ != aura::client::GetTooltipText(window) ||
258 tooltip_id_ != aura::client::GetTooltipId(window)))
259 UpdateIfRequired();
260 }
261
266 //////////////////////////////////////////////////////////////////////////////// 262 ////////////////////////////////////////////////////////////////////////////////
267 // TooltipController private: 263 // TooltipController private:
268 264
269 void TooltipController::TooltipTimerFired() {
270 UpdateIfRequired();
271 }
272
273 void TooltipController::TooltipShownTimerFired() { 265 void TooltipController::TooltipShownTimerFired() {
274 tooltip_->Hide(); 266 tooltip_->Hide();
275
276 // Since the user presumably no longer needs the tooltip, we also stop the
277 // tooltip timer so that tooltip does not pop back up. We will restart this
278 // timer if the tooltip changes (see UpdateTooltip()).
279 tooltip_timer_.Stop();
280 } 267 }
281 268
282 void TooltipController::UpdateIfRequired() { 269 void TooltipController::UpdateIfRequired() {
283 if (!tooltips_enabled_ || 270 if (!tooltips_enabled_ || aura::Env::GetInstance()->IsMouseButtonDown() ||
284 aura::Env::GetInstance()->IsMouseButtonDown() ||
285 IsDragDropInProgress() || !IsCursorVisible()) { 271 IsDragDropInProgress() || !IsCursorVisible()) {
286 tooltip_->Hide(); 272 tooltip_->Hide();
287 return; 273 return;
288 } 274 }
289 275
290 base::string16 tooltip_text; 276 base::string16 tooltip_text;
291 if (tooltip_window_) 277 if (tooltip_window_)
292 tooltip_text = aura::client::GetTooltipText(tooltip_window_); 278 tooltip_text = aura::client::GetTooltipText(tooltip_window_);
293 279
294 // If the user pressed a mouse button. We will hide the tooltip and not show 280 // If the user pressed a mouse button. We will hide the tooltip and not show
295 // it until there is a change in the tooltip. 281 // it until there is a change in the tooltip.
296 if (tooltip_window_at_mouse_press_) { 282 if (tooltip_window_at_mouse_press_) {
297 if (tooltip_window_ == tooltip_window_at_mouse_press_ && 283 if (tooltip_window_ == tooltip_window_at_mouse_press_ &&
298 tooltip_text == tooltip_text_at_mouse_press_) { 284 tooltip_text == tooltip_text_at_mouse_press_) {
299 tooltip_->Hide(); 285 tooltip_->Hide();
300 return; 286 return;
301 } 287 }
302 tooltip_window_at_mouse_press_ = NULL; 288 tooltip_window_at_mouse_press_ = NULL;
303 } 289 }
304 290
305 // If the uniqueness indicator is different from the previously encountered 291 // If the uniqueness indicator is different from the previously encountered
306 // one, we should force tooltip update 292 // one, we should force tooltip update
307 const void* tooltip_id = aura::client::GetTooltipId(tooltip_window_); 293 const void* tooltip_id = aura::client::GetTooltipId(tooltip_window_);
308 bool ids_differ = false; 294 bool ids_differ = false;
309 ids_differ = tooltip_id_ != tooltip_id; 295 ids_differ = tooltip_id_ != tooltip_id;
310 tooltip_id_ = tooltip_id; 296 tooltip_id_ = tooltip_id;
311 297
312 // We add the !tooltip_->IsVisible() below because when we come here from
313 // TooltipTimerFired(), the tooltip_text may not have changed but we still
314 // want to update the tooltip because the timer has fired.
315 // If we come here from UpdateTooltip(), we have already checked for tooltip 298 // If we come here from UpdateTooltip(), we have already checked for tooltip
316 // visibility and this check below will have no effect. 299 // visibility and this check below will have no effect.
317 if (tooltip_text_ != tooltip_text || !tooltip_->IsVisible() || ids_differ) { 300 if (tooltip_text_ != tooltip_text || !tooltip_->IsVisible() || ids_differ) {
318 tooltip_shown_timer_.Stop(); 301 tooltip_shown_timer_.Stop();
319 tooltip_text_ = tooltip_text; 302 tooltip_text_ = tooltip_text;
320 base::string16 trimmed_text = 303 base::string16 trimmed_text =
321 gfx::TruncateString(tooltip_text_, kMaxTooltipLength, gfx::WORD_BREAK); 304 gfx::TruncateString(tooltip_text_, kMaxTooltipLength, gfx::WORD_BREAK);
322 // If the string consists entirely of whitespace, then don't both showing it 305 // If the string consists entirely of whitespace, then don't both showing it
323 // (an empty tooltip is useless). 306 // (an empty tooltip is useless).
324 base::string16 whitespace_removed_text;
325 base::TrimWhitespace(trimmed_text, base::TRIM_ALL, 307 base::TrimWhitespace(trimmed_text, base::TRIM_ALL,
326 &whitespace_removed_text); 308 &tooltip_text_whitespace_trimmed_);
327 if (whitespace_removed_text.empty()) { 309 if (tooltip_text_whitespace_trimmed_.empty()) {
328 tooltip_->Hide(); 310 tooltip_->Hide();
311 } else if (tooltip_show_delayed_) {
312 // Initialize the one-shot timer to show the tooltip in a while.
313 // If there is already a request queued then cancel it and post the new
314 // request. This ensures that tooltip won't show up too early.
315 // The delayed appearance of a tooltip is by default.
316 if (tooltip_defer_timer_.IsRunning()) {
317 tooltip_defer_timer_.Reset();
318 } else {
319 tooltip_defer_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(
320 kDelayForTooltipUpdateInMs),
321 this, &TooltipController::ShowTooltip);
322 }
329 } else { 323 } else {
330 gfx::Point widget_loc = curr_mouse_loc_ + 324 ShowTooltip(); // Allow tooltip to show up without delay for unit tests.
331 tooltip_window_->GetBoundsInScreen().OffsetFromOrigin();
332 tooltip_->SetText(tooltip_window_, whitespace_removed_text, widget_loc);
333 tooltip_->Show();
334 int timeout = GetTooltipShownTimeout();
335 if (timeout > 0) {
336 tooltip_shown_timer_.Start(FROM_HERE,
337 base::TimeDelta::FromMilliseconds(timeout),
338 this, &TooltipController::TooltipShownTimerFired);
339 }
340 } 325 }
341 } 326 }
342 } 327 }
343 328
329 void TooltipController::ShowTooltip() {
330 if (!tooltip_window_)
331 return;
332 gfx::Point widget_loc =
333 curr_mouse_loc_ + tooltip_window_->GetBoundsInScreen().OffsetFromOrigin();
334 tooltip_->SetText(tooltip_window_, tooltip_text_whitespace_trimmed_,
335 widget_loc);
336 tooltip_->Show();
337 int timeout = GetTooltipShownTimeout();
338 if (timeout > 0) {
339 tooltip_shown_timer_.Start(FROM_HERE,
340 base::TimeDelta::FromMilliseconds(timeout), this,
341 &TooltipController::TooltipShownTimerFired);
342 }
343 }
344
344 bool TooltipController::IsTooltipVisible() { 345 bool TooltipController::IsTooltipVisible() {
345 return tooltip_->IsVisible(); 346 return tooltip_->IsVisible();
346 } 347 }
347 348
348 bool TooltipController::IsDragDropInProgress() { 349 bool TooltipController::IsDragDropInProgress() {
349 if (!tooltip_window_) 350 if (!tooltip_window_)
350 return false; 351 return false;
351 aura::client::DragDropClient* client = 352 aura::client::DragDropClient* client =
352 aura::client::GetDragDropClient(tooltip_window_->GetRootWindow()); 353 aura::client::GetDragDropClient(tooltip_window_->GetRootWindow());
353 return client && client->IsDragDropInProgress(); 354 return client && client->IsDragDropInProgress();
(...skipping 24 matching lines...) Expand all
378 return; 379 return;
379 if (tooltip_window_) 380 if (tooltip_window_)
380 tooltip_window_->RemoveObserver(this); 381 tooltip_window_->RemoveObserver(this);
381 tooltip_window_ = target; 382 tooltip_window_ = target;
382 if (tooltip_window_) 383 if (tooltip_window_)
383 tooltip_window_->AddObserver(this); 384 tooltip_window_->AddObserver(this);
384 } 385 }
385 386
386 } // namespace corewm 387 } // namespace corewm
387 } // namespace views 388 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/corewm/tooltip_controller.h ('k') | ui/views/corewm/tooltip_controller_test_helper.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698