| OLD | NEW |
| (Empty) |
| 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 | |
| OLD | NEW |