1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ui/views/corewm/tooltip_win.h" 6 7 #include <winuser.h> 8 9 #include "base/debug/stack_trace.h" 10 #include "base/i18n/rtl.h" 11 #include "base/logging.h" 12 #include "ui/base/l10n/l10n_util_win.h" 13 #include "ui/gfx/rect.h" 14 #include "ui/gfx/screen.h" 15 #include "ui/gfx/win/dpi.h" 16 #include "ui/views/corewm/cursor_height_provider_win.h" 17 18 namespace views { 19 namespace corewm { 20 21 TooltipWin::TooltipWin(HWND parent) 22 : parent_hwnd_(parent), 23 tooltip_hwnd_(NULL), 24 showing_(false) { 25 memset(&toolinfo_, 0, sizeof(toolinfo_)); 26 toolinfo_.cbSize = sizeof(toolinfo_); 27 toolinfo_.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE; 28 toolinfo_.uId = reinterpret_cast<UINT_PTR>(parent_hwnd_); 29 toolinfo_.hwnd = parent_hwnd_; 30 toolinfo_.lpszText = NULL; 31 toolinfo_.lpReserved = NULL; 32 SetRectEmpty(&toolinfo_.rect); 33 } 34 35 TooltipWin::~TooltipWin() { 36 if (tooltip_hwnd_) 37 DestroyWindow(tooltip_hwnd_); 38 } 39 40 bool TooltipWin::HandleNotify(int w_param, NMHDR* l_param, LRESULT* l_result) { 41 if (tooltip_hwnd_ == NULL) 42 return false; 43 44 switch (l_param->code) { 45 case TTN_POP: 46 showing_ = false; 47 return true; 48 case TTN_SHOW: 49 *l_result = TRUE; 50 PositionTooltip(); 51 showing_ = true; 52 return true; 53 default: 54 break; 55 } 56 return false; 57 } 58 59 bool TooltipWin::EnsureTooltipWindow() { 60 if (tooltip_hwnd_) 61 return true; 62 63 tooltip_hwnd_ = CreateWindowEx( 64 WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(), 65 TOOLTIPS_CLASS, NULL, TTS_NOPREFIX | WS_POPUP, 0, 0, 0, 0, 66 parent_hwnd_, NULL, NULL, NULL); 67 if (!tooltip_hwnd_) { 68 PLOG(WARNING) << "tooltip creation failed, disabling tooltips"; 69 return false; 70 } 71 72 l10n_util::AdjustUIFontForWindow(tooltip_hwnd_); 73 74 SendMessage(tooltip_hwnd_, TTM_ADDTOOL, 0, 75 reinterpret_cast<LPARAM>(&toolinfo_)); 76 return true; 77 } 78 79 void TooltipWin::PositionTooltip() { 80 // This code only runs for non-metro, so GetNativeScreen() is fine. 81 gfx::Point screen_point = gfx::win::DIPToScreenPoint(location_); 82 const int cursoroffset = GetCurrentCursorVisibleHeight(); 83 screen_point.Offset(0, cursoroffset); 84 85 DWORD tooltip_size = SendMessage(tooltip_hwnd_, TTM_GETBUBBLESIZE, 0, 86 reinterpret_cast<LPARAM>(&toolinfo_)); 87 const gfx::Size size(LOWORD(tooltip_size), HIWORD(tooltip_size)); 88 89 const gfx::Display display( 90 gfx::Screen::GetNativeScreen()->GetDisplayNearestPoint(screen_point)); 91 92 gfx::Rect tooltip_bounds(screen_point, size); 93 tooltip_bounds.AdjustToFit(gfx::win::DIPToScreenRect(display.work_area())); 94 SetWindowPos(tooltip_hwnd_, NULL, tooltip_bounds.x(), tooltip_bounds.y(), 0, 95 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); 96 } 97 98 void TooltipWin::SetText(aura::Window* window, 99 const base::string16& tooltip_text, 100 const gfx::Point& location) { 101 if (!EnsureTooltipWindow()) 102 return; 103 104 // See comment in header for details on why |location_| is needed. 105 location_ = location; 106 107 // Without this we get a flicker of the tooltip appearing at 0x0. Not sure 108 // why. 109 SetWindowPos(tooltip_hwnd_, NULL, 0, 0, 0, 0, 110 SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | 111 SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER); 112 113 base::string16 adjusted_text(tooltip_text); 114 base::i18n::AdjustStringForLocaleDirection(&adjusted_text); 115 toolinfo_.lpszText = const_cast<WCHAR*>(adjusted_text.c_str()); 116 SendMessage(tooltip_hwnd_, TTM_SETTOOLINFO, 0, 117 reinterpret_cast<LPARAM>(&toolinfo_)); 118 119 // This code only runs for non-metro, so GetNativeScreen() is fine. 120 const gfx::Point screen_point = gfx::win::DIPToScreenPoint(location_); 121 gfx::Display display( 122 gfx::Screen::GetNativeScreen()->GetDisplayNearestPoint(screen_point)); 123 const gfx::Rect monitor_bounds = display.bounds(); 124 int max_width = (monitor_bounds.width() + 1) / 2; 125 SendMessage(tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0, max_width); 126 } 127 128 void TooltipWin::Show() { 129 if (!EnsureTooltipWindow()) 130 return; 131 132 SendMessage(tooltip_hwnd_, TTM_TRACKACTIVATE, 133 TRUE, reinterpret_cast<LPARAM>(&toolinfo_)); 134 SetWindowPos(tooltip_hwnd_, HWND_TOPMOST, 0, 0, 0, 0, 135 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE); 136 } 137 138 void TooltipWin::Hide() { 139 if (!tooltip_hwnd_) 140 return; 141 142 SendMessage(tooltip_hwnd_, TTM_TRACKACTIVATE, FALSE, 143 reinterpret_cast<LPARAM>(&toolinfo_)); 144 } 145 146 bool TooltipWin::IsVisible() { 147 return showing_; 148 } 149 150 } // namespace corewm 151 } // namespace views 152