Home | History | Annotate | Download | only in corewm
      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