15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/corewm/tooltip_controller.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 91e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/strings/string_util.h" 10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h" 11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/aura/client/capture_client.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/aura/client/cursor_client.h" 131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "ui/aura/client/screen_position_client.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/env.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/window.h" 16d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/events/event.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/font.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/rect.h" 191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "ui/gfx/screen.h" 204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ui/views/corewm/tooltip.h" 214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ui/views/widget/tooltip_manager.h" 22effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "ui/wm/public/drag_drop_client.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)namespace views { 251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)namespace corewm { 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kTooltipTimeoutMs = 500; 2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const int kDefaultTooltipShownTimeoutMs = 10000; 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Returns true if |target| is a valid window to get the tooltip from. 321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// |event_target| is the original target from the event and |target| the window 331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// at the same location. 341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)bool IsValidTarget(aura::Window* event_target, aura::Window* target) { 351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!target || (event_target == target)) 361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return true; 371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) void* event_target_grouping_id = event_target->GetNativeWindowProperty( 391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) TooltipManager::kGroupingPropertyKey); 401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) void* target_grouping_id = target->GetNativeWindowProperty( 411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) TooltipManager::kGroupingPropertyKey); 421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return event_target_grouping_id && 431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) event_target_grouping_id == target_grouping_id; 441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Returns the target (the Window tooltip text comes from) based on the event. 471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// If a Window other than event.target() is returned, |location| is adjusted 481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// to be in the coordinates of the returned Window. 491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)aura::Window* GetTooltipTarget(const ui::MouseEvent& event, 501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) gfx::Point* location) { 511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) switch (event.type()) { 521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) case ui::ET_MOUSE_CAPTURE_CHANGED: 531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // On windows we can get a capture changed without an exit. We need to 541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // reset state when this happens else the tooltip may incorrectly show. 551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return NULL; 561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) case ui::ET_MOUSE_EXITED: 571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return NULL; 581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) case ui::ET_MOUSE_MOVED: 591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) case ui::ET_MOUSE_DRAGGED: { 601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) aura::Window* event_target = static_cast<aura::Window*>(event.target()); 61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!event_target) 62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return NULL; 63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // If a window other than |event_target| has capture, ignore the event. 65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // This can happen when RootWindow creates events when showing/hiding, or 66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // the system generates an extra event. We have to check 67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // GetGlobalCaptureWindow() as Windows does not use a singleton 68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // CaptureClient. 69f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!event_target->HasCapture()) { 70f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) aura::Window* root = event_target->GetRootWindow(); 71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (root) { 72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) aura::client::CaptureClient* capture_client = 73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) aura::client::GetCaptureClient(root); 74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (capture_client) { 75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) aura::Window* capture_window = 76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) capture_client->GetGlobalCaptureWindow(); 77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (capture_window && event_target != capture_window) 78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return NULL; 79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return event_target; 82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // If |target| has capture all events go to it, even if the mouse is 851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // really over another window. Find the real window the mouse is over. 861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) gfx::Point screen_loc(event.location()); 871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) aura::client::GetScreenPositionClient(event_target->GetRootWindow())-> 881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) ConvertPointToScreen(event_target, &screen_loc); 891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) gfx::Screen* screen = gfx::Screen::GetScreenFor(event_target); 901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) aura::Window* target = screen->GetWindowAtScreenPoint(screen_loc); 911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!target) 921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return NULL; 931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) gfx::Point target_loc(screen_loc); 941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) aura::client::GetScreenPositionClient(target->GetRootWindow())-> 951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) ConvertPointFromScreen(target, &target_loc); 961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) aura::Window* screen_target = target->GetEventHandlerForPoint(target_loc); 971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!IsValidTarget(event_target, screen_target)) 981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return NULL; 991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) aura::Window::ConvertPointToTarget(screen_target, target, &target_loc); 1011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) *location = target_loc; 1021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return screen_target; 1031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 1041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) default: 1051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) NOTREACHED(); 1061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) break; 1071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 1081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return NULL; 1091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 1101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} // namespace 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//////////////////////////////////////////////////////////////////////////////// 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TooltipController public: 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)TooltipController::TooltipController(scoped_ptr<Tooltip> tooltip) 1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) : tooltip_window_(NULL), 118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) tooltip_id_(NULL), 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tooltip_window_at_mouse_press_(NULL), 1204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) tooltip_(tooltip.Pass()), 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tooltips_enabled_(true) { 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tooltip_timer_.Start(FROM_HERE, 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::TimeDelta::FromMilliseconds(kTooltipTimeoutMs), 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this, &TooltipController::TooltipTimerFired); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TooltipController::~TooltipController() { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tooltip_window_) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tooltip_window_->RemoveObserver(this); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TooltipController::UpdateTooltip(aura::Window* target) { 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If tooltip is visible, we may want to hide it. If it is not, we are ok. 1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (tooltip_window_ == target && tooltip_->IsVisible()) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateIfRequired(); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Reset |tooltip_window_at_mouse_press_| if the moving within the same window 1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // but over a region that has different tooltip text. By resetting 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // |tooltip_window_at_mouse_press_| we ensure the next time the timer fires 1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // we'll requery for the tooltip text. 1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // This handles the case of clicking on a view, moving within the same window 1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // but over a different view, than back to the original. 1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (tooltip_window_at_mouse_press_ && 1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) target == tooltip_window_at_mouse_press_ && 1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) aura::client::GetTooltipText(target) != tooltip_text_at_mouse_press_) { 1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) tooltip_window_at_mouse_press_ = NULL; 1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we had stopped the tooltip timer for some reason, we must restart it if 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // there is a change in the tooltip. 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!tooltip_timer_.IsRunning()) { 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tooltip_window_ != target || (tooltip_window_ && 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tooltip_text_ != aura::client::GetTooltipText(tooltip_window_))) { 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tooltip_timer_.Start(FROM_HERE, 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::TimeDelta::FromMilliseconds(kTooltipTimeoutMs), 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this, &TooltipController::TooltipTimerFired); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void TooltipController::SetTooltipShownTimeout(aura::Window* target, 16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int timeout_in_ms) { 16390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) tooltip_shown_timeout_map_[target] = timeout_in_ms; 16490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TooltipController::SetTooltipsEnabled(bool enable) { 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tooltips_enabled_ == enable) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tooltips_enabled_ = enable; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateTooltip(tooltip_window_); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TooltipController::OnKeyEvent(ui::KeyEvent* event) { 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // On key press, we want to hide the tooltip and not show it until change. 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is the same behavior as hiding tooltips on timeout. Hence, we can 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // simply simulate a timeout. 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tooltip_shown_timer_.IsRunning()) { 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tooltip_shown_timer_.Stop(); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TooltipShownTimerFired(); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TooltipController::OnMouseEvent(ui::MouseEvent* event) { 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (event->type()) { 1851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) case ui::ET_MOUSE_CAPTURE_CHANGED: 186424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) case ui::ET_MOUSE_EXITED: 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::ET_MOUSE_MOVED: 1881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) case ui::ET_MOUSE_DRAGGED: { 1891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) curr_mouse_loc_ = event->location(); 190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) aura::Window* target = NULL; 191cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Avoid a call to gfx::Screen::GetWindowAtScreenPoint() since it can be 192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // very expensive on X11 in cases when the tooltip is hidden anyway. 193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (tooltips_enabled_ && 194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) !aura::Env::GetInstance()->IsMouseButtonDown() && 195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) !IsDragDropInProgress()) { 196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) target = GetTooltipTarget(*event, &curr_mouse_loc_); 197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetTooltipWindow(target); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tooltip_timer_.IsRunning()) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tooltip_timer_.Reset(); 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (tooltip_->IsVisible()) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateIfRequired(); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::ET_MOUSE_PRESSED: 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if ((event->flags() & ui::EF_IS_NON_CLIENT) == 0) { 2081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) aura::Window* target = static_cast<aura::Window*>(event->target()); 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We don't get a release for non-client areas. 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) tooltip_window_at_mouse_press_ = target; 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (target) 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) tooltip_text_at_mouse_press_ = aura::client::GetTooltipText(target); 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) tooltip_->Hide(); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::ET_MOUSEWHEEL: 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Hide the tooltip for click, release, drag, wheel events. 2184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (tooltip_->IsVisible()) 2194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) tooltip_->Hide(); 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TooltipController::OnTouchEvent(ui::TouchEvent* event) { 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(varunjain): need to properly implement tooltips for 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // touch events. 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Hide the tooltip for touch events. 2304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) tooltip_->Hide(); 2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetTooltipWindow(NULL); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TooltipController::OnCancelMode(ui::CancelModeEvent* event) { 2354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) tooltip_->Hide(); 2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetTooltipWindow(NULL); 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TooltipController::OnWindowDestroyed(aura::Window* window) { 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tooltip_window_ == window) { 2414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) tooltip_->Hide(); 24290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) tooltip_shown_timeout_map_.erase(tooltip_window_); 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tooltip_window_ = NULL; 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//////////////////////////////////////////////////////////////////////////////// 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TooltipController private: 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TooltipController::TooltipTimerFired() { 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateIfRequired(); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TooltipController::TooltipShownTimerFired() { 2554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) tooltip_->Hide(); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Since the user presumably no longer needs the tooltip, we also stop the 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // tooltip timer so that tooltip does not pop back up. We will restart this 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // timer if the tooltip changes (see UpdateTooltip()). 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tooltip_timer_.Stop(); 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TooltipController::UpdateIfRequired() { 2644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!tooltips_enabled_ || 2654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) aura::Env::GetInstance()->IsMouseButtonDown() || 2664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) IsDragDropInProgress() || !IsCursorVisible()) { 2674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) tooltip_->Hide(); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 tooltip_text; 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tooltip_window_) 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tooltip_text = aura::client::GetTooltipText(tooltip_window_); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the user pressed a mouse button. We will hide the tooltip and not show 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // it until there is a change in the tooltip. 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tooltip_window_at_mouse_press_) { 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tooltip_window_ == tooltip_window_at_mouse_press_ && 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tooltip_text == tooltip_text_at_mouse_press_) { 2804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) tooltip_->Hide(); 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tooltip_window_at_mouse_press_ = NULL; 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 286f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // If the uniqueness indicator is different from the previously encountered 287f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // one, we should force tooltip update 288f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const void* tooltip_id = aura::client::GetTooltipId(tooltip_window_); 289f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) bool ids_differ = false; 290f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ids_differ = tooltip_id_ != tooltip_id; 291f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) tooltip_id_ = tooltip_id; 292f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 2934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // We add the !tooltip_->IsVisible() below because when we come here from 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TooltipTimerFired(), the tooltip_text may not have changed but we still 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // want to update the tooltip because the timer has fired. 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we come here from UpdateTooltip(), we have already checked for tooltip 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // visibility and this check below will have no effect. 298f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (tooltip_text_ != tooltip_text || !tooltip_->IsVisible() || ids_differ) { 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tooltip_shown_timer_.Stop(); 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tooltip_text_ = tooltip_text; 3011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) base::string16 trimmed_text(tooltip_text_); 3021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) views::TooltipManager::TrimTooltipText(&trimmed_text); 3031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // If the string consists entirely of whitespace, then don't both showing it 3041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // (an empty tooltip is useless). 3051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) base::string16 whitespace_removed_text; 306a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::TrimWhitespace(trimmed_text, base::TRIM_ALL, 307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) &whitespace_removed_text); 3081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (whitespace_removed_text.empty()) { 3094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) tooltip_->Hide(); 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Point widget_loc = curr_mouse_loc_ + 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tooltip_window_->GetBoundsInScreen().OffsetFromOrigin(); 3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) tooltip_->SetText(tooltip_window_, whitespace_removed_text, widget_loc); 3144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) tooltip_->Show(); 3154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int timeout = GetTooltipShownTimeout(); 3164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (timeout > 0) { 3174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) tooltip_shown_timer_.Start(FROM_HERE, 3184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::TimeDelta::FromMilliseconds(timeout), 3194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) this, &TooltipController::TooltipShownTimerFired); 3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TooltipController::IsTooltipVisible() { 3264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return tooltip_->IsVisible(); 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TooltipController::IsDragDropInProgress() { 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!tooltip_window_) 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) aura::client::DragDropClient* client = 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) aura::client::GetDragDropClient(tooltip_window_->GetRootWindow()); 3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return client && client->IsDragDropInProgress(); 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TooltipController::IsCursorVisible() { 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!tooltip_window_) 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 3401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) aura::Window* root = tooltip_window_->GetRootWindow(); 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!root) 3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) aura::client::CursorClient* cursor_client = 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) aura::client::GetCursorClient(root); 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // |cursor_client| may be NULL in tests, treat NULL as always visible. 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return !cursor_client || cursor_client->IsCursorVisible(); 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 34990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)int TooltipController::GetTooltipShownTimeout() { 35090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::map<aura::Window*, int>::const_iterator it = 35190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) tooltip_shown_timeout_map_.find(tooltip_window_); 35290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (it == tooltip_shown_timeout_map_.end()) 35390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return kDefaultTooltipShownTimeoutMs; 35490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return it->second; 35590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 35690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void TooltipController::SetTooltipWindow(aura::Window* target) { 3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (tooltip_window_ == target) 3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (tooltip_window_) 3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) tooltip_window_->RemoveObserver(this); 3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) tooltip_window_ = target; 3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (tooltip_window_) 3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) tooltip_window_->AddObserver(this); 3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace corewm 3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace views 369