• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
TooltipWin(HWND parent)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 
~TooltipWin()35 TooltipWin::~TooltipWin() {
36   if (tooltip_hwnd_)
37     DestroyWindow(tooltip_hwnd_);
38 }
39 
HandleNotify(int w_param,NMHDR * l_param,LRESULT * l_result)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 
EnsureTooltipWindow()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 
PositionTooltip()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 
SetText(aura::Window * window,const base::string16 & tooltip_text,const gfx::Point & location)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 
Show()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 
Hide()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 
IsVisible()146 bool TooltipWin::IsVisible() {
147   return showing_;
148 }
149 
150 }  // namespace corewm
151 }  // namespace views
152