14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 24e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 34e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// found in the LICENSE file. 44e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ui/views/corewm/tooltip_win.h" 64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include <winuser.h> 84e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/debug/stack_trace.h" 104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/i18n/rtl.h" 114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/logging.h" 124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ui/base/l10n/l10n_util_win.h" 134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ui/gfx/rect.h" 144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ui/gfx/screen.h" 15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/gfx/win/dpi.h" 16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/views/corewm/cursor_height_provider_win.h" 174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace views { 194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace corewm { 204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)TooltipWin::TooltipWin(HWND parent) 224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) : parent_hwnd_(parent), 234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) tooltip_hwnd_(NULL), 244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) showing_(false) { 254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) memset(&toolinfo_, 0, sizeof(toolinfo_)); 264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) toolinfo_.cbSize = sizeof(toolinfo_); 274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) toolinfo_.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE; 284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) toolinfo_.uId = reinterpret_cast<UINT_PTR>(parent_hwnd_); 294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) toolinfo_.hwnd = parent_hwnd_; 304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) toolinfo_.lpszText = NULL; 314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) toolinfo_.lpReserved = NULL; 324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) SetRectEmpty(&toolinfo_.rect); 334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)TooltipWin::~TooltipWin() { 364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (tooltip_hwnd_) 374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DestroyWindow(tooltip_hwnd_); 384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool TooltipWin::HandleNotify(int w_param, NMHDR* l_param, LRESULT* l_result) { 414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (tooltip_hwnd_ == NULL) 424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return false; 434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) switch (l_param->code) { 454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) case TTN_POP: 464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) showing_ = false; 474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; 484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) case TTN_SHOW: 494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) *l_result = TRUE; 504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) PositionTooltip(); 514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) showing_ = true; 524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; 534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) default: 544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) break; 554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return false; 574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool TooltipWin::EnsureTooltipWindow() { 604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (tooltip_hwnd_) 614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; 624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) tooltip_hwnd_ = CreateWindowEx( 648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(), 654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) TOOLTIPS_CLASS, NULL, TTS_NOPREFIX | WS_POPUP, 0, 0, 0, 0, 664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) parent_hwnd_, NULL, NULL, NULL); 674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!tooltip_hwnd_) { 68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) PLOG(WARNING) << "tooltip creation failed, disabling tooltips"; 694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return false; 704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) l10n_util::AdjustUIFontForWindow(tooltip_hwnd_); 734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) SendMessage(tooltip_hwnd_, TTM_ADDTOOL, 0, 754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) reinterpret_cast<LPARAM>(&toolinfo_)); 764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; 774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void TooltipWin::PositionTooltip() { 804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // This code only runs for non-metro, so GetNativeScreen() is fine. 81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) gfx::Point screen_point = gfx::win::DIPToScreenPoint(location_); 82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const int cursoroffset = GetCurrentCursorVisibleHeight(); 83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) screen_point.Offset(0, cursoroffset); 844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DWORD tooltip_size = SendMessage(tooltip_hwnd_, TTM_GETBUBBLESIZE, 0, 864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) reinterpret_cast<LPARAM>(&toolinfo_)); 87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const gfx::Size size(LOWORD(tooltip_size), HIWORD(tooltip_size)); 88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const gfx::Display display( 90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) gfx::Screen::GetNativeScreen()->GetDisplayNearestPoint(screen_point)); 91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) gfx::Rect tooltip_bounds(screen_point, size); 93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) tooltip_bounds.AdjustToFit(gfx::win::DIPToScreenRect(display.work_area())); 944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) SetWindowPos(tooltip_hwnd_, NULL, tooltip_bounds.x(), tooltip_bounds.y(), 0, 954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); 964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void TooltipWin::SetText(aura::Window* window, 994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const base::string16& tooltip_text, 1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const gfx::Point& location) { 1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!EnsureTooltipWindow()) 1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return; 1034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // See comment in header for details on why |location_| is needed. 1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) location_ = location; 1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Without this we get a flicker of the tooltip appearing at 0x0. Not sure 1088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // why. 1098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) SetWindowPos(tooltip_hwnd_, NULL, 0, 0, 0, 0, 1108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | 1118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER); 1128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::string16 adjusted_text(tooltip_text); 1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::i18n::AdjustStringForLocaleDirection(&adjusted_text); 1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) toolinfo_.lpszText = const_cast<WCHAR*>(adjusted_text.c_str()); 1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) SendMessage(tooltip_hwnd_, TTM_SETTOOLINFO, 0, 1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) reinterpret_cast<LPARAM>(&toolinfo_)); 1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // This code only runs for non-metro, so GetNativeScreen() is fine. 120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const gfx::Point screen_point = gfx::win::DIPToScreenPoint(location_); 1214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) gfx::Display display( 122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) gfx::Screen::GetNativeScreen()->GetDisplayNearestPoint(screen_point)); 1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const gfx::Rect monitor_bounds = display.bounds(); 1244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int max_width = (monitor_bounds.width() + 1) / 2; 1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) SendMessage(tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0, max_width); 1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void TooltipWin::Show() { 1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!EnsureTooltipWindow()) 1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return; 1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) SendMessage(tooltip_hwnd_, TTM_TRACKACTIVATE, 1334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) TRUE, reinterpret_cast<LPARAM>(&toolinfo_)); 1341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) SetWindowPos(tooltip_hwnd_, HWND_TOPMOST, 0, 0, 0, 0, 1351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE); 1364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void TooltipWin::Hide() { 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!tooltip_hwnd_) 1404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return; 1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) SendMessage(tooltip_hwnd_, TTM_TRACKACTIVATE, FALSE, 1434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) reinterpret_cast<LPARAM>(&toolinfo_)); 1444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool TooltipWin::IsVisible() { 1474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return showing_; 1484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} // namespace corewm 1514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} // namespace views 152