From 2d82a8160b726349984aa7756304a30b8b0f348d Mon Sep 17 00:00:00 2001
From: "sky@chromium.org"
 <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Thu, 28 May 2009 16:38:07 +0000
Subject: Splits TooltipManager so that it can be ported and stubs out the GTK
 side.

BUG=none
TEST=none

Review URL: http://codereview.chromium.org/114054

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@17076 0039d316-1c4b-4281-b951-d872f2087c98
---
 chrome/browser/views/tabs/tab.cc     |   2 -
 views/views.gyp                      |   5 +-
 views/widget/aero_tooltip_manager.cc |  14 +-
 views/widget/aero_tooltip_manager.h  |   6 +-
 views/widget/tooltip_manager.cc      | 448 ----------------------------------
 views/widget/tooltip_manager.h       | 143 +----------
 views/widget/tooltip_manager_gtk.cc  |  51 ++++
 views/widget/tooltip_manager_gtk.h   |  37 +++
 views/widget/tooltip_manager_win.cc  | 454 +++++++++++++++++++++++++++++++++++
 views/widget/tooltip_manager_win.h   | 160 ++++++++++++
 views/widget/widget_gtk.cc           |   6 +-
 views/widget/widget_gtk.h            |   3 +
 views/widget/widget_win.cc           |   4 +-
 views/widget/widget_win.h            |  14 +-
 14 files changed, 749 insertions(+), 598 deletions(-)
 delete mode 100644 views/widget/tooltip_manager.cc
 create mode 100644 views/widget/tooltip_manager_gtk.cc
 create mode 100644 views/widget/tooltip_manager_gtk.h
 create mode 100644 views/widget/tooltip_manager_win.cc
 create mode 100644 views/widget/tooltip_manager_win.h

diff --git a/chrome/browser/views/tabs/tab.cc b/chrome/browser/views/tabs/tab.cc
index 6118699..7891063 100644
--- a/chrome/browser/views/tabs/tab.cc
+++ b/chrome/browser/views/tabs/tab.cc
@@ -214,9 +214,7 @@ bool Tab::GetTooltipText(int x, int y, std::wstring* tooltip) {
 bool Tab::GetTooltipTextOrigin(int x, int y, gfx::Point* origin) {
   gfx::Font font;
   origin->set_x(title_bounds().x() + 10);
-#if defined(OS_WIN)
   origin->set_y(-views::TooltipManager::GetTooltipHeight() - 4);
-#endif
   return true;
 }
 
diff --git a/views/views.gyp b/views/views.gyp
index 5a3a2d8..85bb1d8 100644
--- a/views/views.gyp
+++ b/views/views.gyp
@@ -189,7 +189,10 @@
         'widget/root_view_drop_target.h',
         'widget/root_view_gtk.cc',
         'widget/root_view_win.cc',
-        'widget/tooltip_manager.cc',
+        'widget/tooltip_manager_gtk.cc',
+        'widget/tooltip_manager_gtk.h',
+        'widget/tooltip_manager_win.cc',
+        'widget/tooltip_manager_win.h',
         'widget/tooltip_manager.h',
         'widget/widget.h',
         'widget/widget_gtk.cc',
diff --git a/views/widget/aero_tooltip_manager.cc b/views/widget/aero_tooltip_manager.cc
index ca58c24..aef9e65 100644
--- a/views/widget/aero_tooltip_manager.cc
+++ b/views/widget/aero_tooltip_manager.cc
@@ -18,8 +18,8 @@ namespace views {
 ///////////////////////////////////////////////////////////////////////////////
 // AeroTooltipManager, public:
 
-AeroTooltipManager::AeroTooltipManager(Widget* widget, HWND parent)
-    : TooltipManager(widget, parent),
+AeroTooltipManager::AeroTooltipManager(Widget* widget)
+    : TooltipManagerWin(widget),
       initial_delay_(0) {
 }
 
@@ -71,7 +71,7 @@ void AeroTooltipManager::Init() {
   tooltip_hwnd_ = CreateWindowEx(
       WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
       TOOLTIPS_CLASS, NULL, TTS_NOPREFIX, 0, 0, 0, 0,
-      parent_, NULL, NULL, NULL);
+      GetParent(), NULL, NULL, NULL);
 
   l10n_util::AdjustUIFontForWindow(tooltip_hwnd_);
 
@@ -81,10 +81,10 @@ void AeroTooltipManager::Init() {
   // We use tracking tooltips on Vista to allow us to manually control the
   // visibility of the tooltip.
   toolinfo_.uFlags = TTF_TRANSPARENT | TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
-  toolinfo_.hwnd = parent_;
-  toolinfo_.uId = (UINT_PTR)parent_;
+  toolinfo_.hwnd = GetParent();
+  toolinfo_.uId = (UINT_PTR)GetParent();
 
-  // Setting this tells windows to call parent_ back (using a WM_NOTIFY
+  // Setting this tells windows to call GetParent() back (using a WM_NOTIFY
   // message) for the actual tooltip contents.
   toolinfo_.lpszText = LPSTR_TEXTCALLBACK;
   SetRectEmpty(&toolinfo_.rect);
@@ -97,7 +97,7 @@ void AeroTooltipManager::OnTimer() {
   POINT pt;
   pt.x = last_mouse_x_;
   pt.y = last_mouse_y_;
-  ::ClientToScreen(parent_, &pt);
+  ::ClientToScreen(GetParent(), &pt);
 
   // Set the position and visibility.
   if (!tooltip_showing_) {
diff --git a/views/widget/aero_tooltip_manager.h b/views/widget/aero_tooltip_manager.h
index fe5856d..c81991c 100644
--- a/views/widget/aero_tooltip_manager.h
+++ b/views/widget/aero_tooltip_manager.h
@@ -7,7 +7,7 @@
 
 #include "base/ref_counted.h"
 #include "base/task.h"
-#include "views/widget/tooltip_manager.h"
+#include "views/widget/tooltip_manager_win.h"
 
 namespace views {
 
@@ -26,9 +26,9 @@ namespace views {
 //  TTF_TRACKed tooltips.
 //
 // TODO(glen): Resolve this with Microsoft.
-class AeroTooltipManager : public TooltipManager {
+class AeroTooltipManager : public TooltipManagerWin {
  public:
-  AeroTooltipManager(Widget* widget, HWND parent);
+  explicit AeroTooltipManager(Widget* widget);
   virtual ~AeroTooltipManager();
 
   virtual void OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param);
diff --git a/views/widget/tooltip_manager.cc b/views/widget/tooltip_manager.cc
deleted file mode 100644
index 9ef9ff9..0000000
--- a/views/widget/tooltip_manager.cc
+++ /dev/null
@@ -1,448 +0,0 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "views/widget/tooltip_manager.h"
-
-#include <windowsx.h>
-#include <limits>
-
-#include "app/gfx/text_elider.h"
-#include "app/l10n_util.h"
-#include "app/l10n_util_win.h"
-#include "app/win_util.h"
-#include "base/logging.h"
-#include "base/message_loop.h"
-#include "views/view.h"
-#include "views/widget/root_view.h"
-#include "views/widget/widget.h"
-
-namespace views {
-
-//static
-int TooltipManager::tooltip_height_ = 0;
-
-// Default timeout for the tooltip displayed using keyboard.
-// Timeout is mentioned in milliseconds.
-static const int kDefaultTimeout = 4000;
-
-// Maximum number of lines we allow in the tooltip.
-static const int kMaxLines = 6;
-
-// Maximum number of characters we allow in a tooltip.
-static const int kMaxTooltipLength = 1024;
-
-// Breaks |text| along line boundaries, placing each line of text into lines.
-static void SplitTooltipString(const std::wstring& text,
-                               std::vector<std::wstring>* lines) {
-  size_t index = 0;
-  size_t next_index;
-  while ((next_index = text.find(TooltipManager::GetLineSeparator(), index))
-         != std::wstring::npos && lines->size() < kMaxLines) {
-    lines->push_back(text.substr(index, next_index - index));
-    index = next_index + TooltipManager::GetLineSeparator().size();
-  }
-  if (next_index != text.size() && lines->size() < kMaxLines)
-    lines->push_back(text.substr(index, text.size() - index));
-}
-
-// static
-int TooltipManager::GetTooltipHeight() {
-  DCHECK(tooltip_height_ > 0);
-  return tooltip_height_;
-}
-
-static gfx::Font DetermineDefaultFont() {
-  HWND window = CreateWindowEx(
-      WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
-      TOOLTIPS_CLASS, NULL, 0 , 0, 0, 0, 0, NULL, NULL, NULL, NULL);
-  HFONT hfont = reinterpret_cast<HFONT>(SendMessage(window, WM_GETFONT, 0, 0));
-  gfx::Font font = hfont ? gfx::Font::CreateFont(hfont) : gfx::Font();
-  DestroyWindow(window);
-  return font;
-}
-
-// static
-gfx::Font TooltipManager::GetDefaultFont() {
-  static gfx::Font* font = NULL;
-  if (!font)
-    font = new gfx::Font(DetermineDefaultFont());
-  return *font;
-}
-
-// static
-const std::wstring& TooltipManager::GetLineSeparator() {
-  static const std::wstring* separator = NULL;
-  if (!separator)
-    separator = new std::wstring(L"\r\n");
-  return *separator;
-}
-
-TooltipManager::TooltipManager(Widget* widget, HWND parent)
-    : widget_(widget),
-      parent_(parent),
-      last_mouse_x_(-1),
-      last_mouse_y_(-1),
-      tooltip_showing_(false),
-      last_tooltip_view_(NULL),
-      last_view_out_of_sync_(false),
-      tooltip_width_(0),
-      keyboard_tooltip_hwnd_(NULL),
-#pragma warning(suppress: 4355)
-      keyboard_tooltip_factory_(this) {
-  DCHECK(widget && parent);
-  Init();
-}
-
-TooltipManager::~TooltipManager() {
-  if (tooltip_hwnd_)
-    DestroyWindow(tooltip_hwnd_);
-  if (keyboard_tooltip_hwnd_)
-    DestroyWindow(keyboard_tooltip_hwnd_);
-}
-
-void TooltipManager::Init() {
-  // Create the tooltip control.
-  tooltip_hwnd_ = CreateWindowEx(
-      WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
-      TOOLTIPS_CLASS, NULL, TTS_NOPREFIX, 0, 0, 0, 0,
-      parent_, NULL, NULL, NULL);
-
-  l10n_util::AdjustUIFontForWindow(tooltip_hwnd_);
-
-  // This effectively turns off clipping of tooltips. We need this otherwise
-  // multi-line text (\r\n) won't work right. The size doesn't really matter
-  // (just as long as its bigger than the monitor's width) as we clip to the
-  // screen size before rendering.
-  SendMessage(tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0,
-              std::numeric_limits<short>::max());
-
-  // Add one tool that is used for all tooltips.
-  toolinfo_.cbSize = sizeof(toolinfo_);
-  toolinfo_.uFlags = TTF_TRANSPARENT | TTF_IDISHWND;
-  toolinfo_.hwnd = parent_;
-  toolinfo_.uId = reinterpret_cast<UINT_PTR>(parent_);
-  // Setting this tells windows to call parent_ back (using a WM_NOTIFY
-  // message) for the actual tooltip contents.
-  toolinfo_.lpszText = LPSTR_TEXTCALLBACK;
-  SetRectEmpty(&toolinfo_.rect);
-  SendMessage(tooltip_hwnd_, TTM_ADDTOOL, 0, (LPARAM)&toolinfo_);
-}
-
-void TooltipManager::UpdateTooltip() {
-  // Set last_view_out_of_sync_ to indicate the view is currently out of sync.
-  // This doesn't update the view under the mouse immediately as it may cause
-  // timing problems.
-  last_view_out_of_sync_ = true;
-  last_tooltip_view_ = NULL;
-  // Hide the tooltip.
-  SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
-}
-
-void TooltipManager::TooltipTextChanged(View* view) {
-  if (view == last_tooltip_view_)
-    UpdateTooltip(last_mouse_x_, last_mouse_y_);
-}
-
-LRESULT TooltipManager::OnNotify(int w_param, NMHDR* l_param, bool* handled) {
-  *handled = false;
-  if (l_param->hwndFrom == tooltip_hwnd_ && keyboard_tooltip_hwnd_ == NULL) {
-    switch (l_param->code) {
-      case TTN_GETDISPINFO: {
-        if (last_view_out_of_sync_) {
-          // View under the mouse is out of sync, determine it now.
-          RootView* root_view = widget_->GetRootView();
-          last_tooltip_view_ = root_view->GetViewForPoint(
-              gfx::Point(last_mouse_x_, last_mouse_y_));
-          last_view_out_of_sync_ = false;
-        }
-        // Tooltip control is asking for the tooltip to display.
-        NMTTDISPINFOW* tooltip_info =
-            reinterpret_cast<NMTTDISPINFOW*>(l_param);
-        // Initialize the string, if we have a valid tooltip the string will
-        // get reset below.
-        tooltip_info->szText[0] = TEXT('\0');
-        tooltip_text_.clear();
-        tooltip_info->lpszText = NULL;
-        clipped_text_.clear();
-        if (last_tooltip_view_ != NULL) {
-          tooltip_text_.clear();
-          // Mouse is over a View, ask the View for it's tooltip.
-          gfx::Point view_loc(last_mouse_x_, last_mouse_y_);
-          View::ConvertPointToView(widget_->GetRootView(),
-                                   last_tooltip_view_, &view_loc);
-          if (last_tooltip_view_->GetTooltipText(view_loc.x(), view_loc.y(),
-                                                 &tooltip_text_) &&
-              !tooltip_text_.empty()) {
-            // View has a valid tip, copy it into TOOLTIPINFO.
-            clipped_text_ = tooltip_text_;
-            TrimTooltipToFit(&clipped_text_, &tooltip_width_, &line_count_,
-                             last_mouse_x_, last_mouse_y_, tooltip_hwnd_);
-            // Adjust the clipped tooltip text for locale direction.
-            l10n_util::AdjustStringForLocaleDirection(clipped_text_,
-                                                      &clipped_text_);
-            tooltip_info->lpszText = const_cast<WCHAR*>(clipped_text_.c_str());
-          } else {
-            tooltip_text_.clear();
-          }
-        }
-        *handled = true;
-        return 0;
-      }
-      case TTN_POP:
-        tooltip_showing_ = false;
-        *handled = true;
-        return 0;
-      case TTN_SHOW: {
-        *handled = true;
-        tooltip_showing_ = true;
-        // The tooltip is about to show, allow the view to position it
-        gfx::Point text_origin;
-        if (tooltip_height_ == 0)
-          tooltip_height_ = CalcTooltipHeight();
-        gfx::Point view_loc(last_mouse_x_, last_mouse_y_);
-        View::ConvertPointToView(widget_->GetRootView(),
-                                 last_tooltip_view_, &view_loc);
-        if (last_tooltip_view_->GetTooltipTextOrigin(
-              view_loc.x(), view_loc.y(), &text_origin) &&
-            SetTooltipPosition(text_origin.x(), text_origin.y())) {
-          // Return true, otherwise the rectangle we specified is ignored.
-          return TRUE;
-        }
-        return 0;
-      }
-      default:
-        // Fall through.
-        break;
-    }
-  }
-  return 0;
-}
-
-bool TooltipManager::SetTooltipPosition(int text_x, int text_y) {
-  // NOTE: this really only tests that the y location fits on screen, but that
-  // is good enough for our usage.
-
-  // Calculate the bounds the tooltip will get.
-  gfx::Point view_loc;
-  View::ConvertPointToScreen(last_tooltip_view_, &view_loc);
-  RECT bounds = { view_loc.x() + text_x,
-                  view_loc.y() + text_y,
-                  view_loc.x() + text_x + tooltip_width_,
-                  view_loc.y() + line_count_ * GetTooltipHeight() };
-  SendMessage(tooltip_hwnd_, TTM_ADJUSTRECT, TRUE, (LPARAM)&bounds);
-
-  // Make sure the rectangle completely fits on the current monitor. If it
-  // doesn't, return false so that windows positions the tooltip at the
-  // default location.
-  gfx::Rect monitor_bounds =
-      win_util::GetMonitorBoundsForRect(gfx::Rect(bounds.left,bounds.right,
-                                                  0, 0));
-  if (!monitor_bounds.Contains(gfx::Rect(bounds))) {
-    return false;
-  }
-
-  ::SetWindowPos(tooltip_hwnd_, NULL, bounds.left, bounds.top, 0, 0,
-                 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
-  return true;
-}
-
-int TooltipManager::CalcTooltipHeight() {
-  // Ask the tooltip for it's font.
-  int height;
-  HFONT hfont = reinterpret_cast<HFONT>(
-      SendMessage(tooltip_hwnd_, WM_GETFONT, 0, 0));
-  if (hfont != NULL) {
-    HDC dc = GetDC(tooltip_hwnd_);
-    HFONT previous_font = static_cast<HFONT>(SelectObject(dc, hfont));
-    int last_map_mode = SetMapMode(dc, MM_TEXT);
-    TEXTMETRIC font_metrics;
-    GetTextMetrics(dc, &font_metrics);
-    height = font_metrics.tmHeight;
-    // To avoid the DC referencing font_handle_, select the previous font.
-    SelectObject(dc, previous_font);
-    SetMapMode(dc, last_map_mode);
-    ReleaseDC(NULL, dc);
-  } else {
-    // Tooltip is using the system font. Use gfx::Font, which should pick
-    // up the system font.
-    height = gfx::Font().height();
-  }
-  // Get the margins from the tooltip
-  RECT tooltip_margin;
-  SendMessage(tooltip_hwnd_, TTM_GETMARGIN, 0, (LPARAM)&tooltip_margin);
-  return height + tooltip_margin.top + tooltip_margin.bottom;
-}
-
-void TooltipManager::TrimTooltipToFit(std::wstring* text,
-                                      int* max_width,
-                                      int* line_count,
-                                      int position_x,
-                                      int position_y,
-                                      HWND window) {
-  *max_width = 0;
-  *line_count = 0;
-
-  // Clamp the tooltip length to kMaxTooltipLength so that we don't
-  // accidentally DOS the user with a mega tooltip (since Windows doesn't seem
-  // to do this itself).
-  if (text->length() > kMaxTooltipLength)
-    *text = text->substr(0, kMaxTooltipLength);
-
-  // Determine the available width for the tooltip.
-  gfx::Point screen_loc(position_x, position_y);
-  View::ConvertPointToScreen(widget_->GetRootView(), &screen_loc);
-  gfx::Rect monitor_bounds =
-      win_util::GetMonitorBoundsForRect(gfx::Rect(screen_loc.x(),
-                                                  screen_loc.y(),
-                                                  0, 0));
-  RECT tooltip_margin;
-  SendMessage(window, TTM_GETMARGIN, 0, (LPARAM)&tooltip_margin);
-  const int available_width = monitor_bounds.width() - tooltip_margin.left -
-      tooltip_margin.right;
-  if (available_width <= 0)
-    return;
-
-  // Split the string.
-  std::vector<std::wstring> lines;
-  SplitTooltipString(*text, &lines);
-  *line_count = static_cast<int>(lines.size());
-
-  // Format each line to fit.
-  gfx::Font font = GetDefaultFont();
-  std::wstring result;
-  for (std::vector<std::wstring>::iterator i = lines.begin(); i != lines.end();
-       ++i) {
-    std::wstring elided_text = gfx::ElideText(*i, font, available_width);
-    *max_width = std::max(*max_width, font.GetStringWidth(elided_text));
-    if (i == lines.begin() && i + 1 == lines.end()) {
-      *text = elided_text;
-      return;
-    }
-    if (!result.empty())
-      result.append(GetLineSeparator());
-    result.append(elided_text);
-  }
-  *text = result;
-}
-
-void TooltipManager::UpdateTooltip(int x, int y) {
-  RootView* root_view = widget_->GetRootView();
-  View* view = root_view->GetViewForPoint(gfx::Point(x, y));
-  if (view != last_tooltip_view_) {
-    // NOTE: This *must* be sent regardless of the visibility of the tooltip.
-    // It triggers Windows to ask for the tooltip again.
-    SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
-    last_tooltip_view_ = view;
-  } else if (last_tooltip_view_ != NULL) {
-    // Tooltip is showing, and mouse is over the same view. See if the tooltip
-    // text has changed.
-    gfx::Point view_point(x, y);
-    View::ConvertPointToView(root_view, last_tooltip_view_, &view_point);
-    std::wstring new_tooltip_text;
-    if (last_tooltip_view_->GetTooltipText(view_point.x(), view_point.y(),
-                                           &new_tooltip_text) &&
-        new_tooltip_text != tooltip_text_) {
-      // The text has changed, hide the popup.
-      SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
-      if (!new_tooltip_text.empty() && tooltip_showing_) {
-        // New text is valid, show the popup.
-        SendMessage(tooltip_hwnd_, TTM_POPUP, 0, 0);
-      }
-    }
-  }
-}
-
-void TooltipManager::OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param) {
-  int x = GET_X_LPARAM(l_param);
-  int y = GET_Y_LPARAM(l_param);
-
-  if (u_msg >= WM_NCMOUSEMOVE && u_msg <= WM_NCXBUTTONDBLCLK) {
-    // NC message coordinates are in screen coordinates.
-    gfx::Rect frame_bounds;
-    widget_->GetBounds(&frame_bounds, true);
-    x -= frame_bounds.x();
-    y -= frame_bounds.y();
-  }
-
-  if (u_msg != WM_MOUSEMOVE || last_mouse_x_ != x || last_mouse_y_ != y) {
-    last_mouse_x_ = x;
-    last_mouse_y_ = y;
-    HideKeyboardTooltip();
-    UpdateTooltip(x, y);
-  }
-  // Forward the message onto the tooltip.
-  MSG msg;
-  msg.hwnd = parent_;
-  msg.message = u_msg;
-  msg.wParam = w_param;
-  msg.lParam = l_param;
-  SendMessage(tooltip_hwnd_, TTM_RELAYEVENT, 0, (LPARAM)&msg);
-}
-
-void TooltipManager::ShowKeyboardTooltip(View* focused_view) {
-  if (tooltip_showing_) {
-    SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
-    tooltip_text_.clear();
-  }
-  HideKeyboardTooltip();
-  std::wstring tooltip_text;
-  if (!focused_view->GetTooltipText(0, 0, &tooltip_text))
-    return;
-  gfx::Rect focused_bounds = focused_view->bounds();
-  gfx::Point screen_point;
-  focused_view->ConvertPointToScreen(focused_view, &screen_point);
-  gfx::Point relative_point_coordinates;
-  focused_view->ConvertPointToWidget(focused_view, &relative_point_coordinates);
-  keyboard_tooltip_hwnd_ = CreateWindowEx(
-      WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
-      TOOLTIPS_CLASS, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
-  SendMessage(keyboard_tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0,
-              std::numeric_limits<short>::max());
-  int tooltip_width;
-  int line_count;
-  TrimTooltipToFit(&tooltip_text, &tooltip_width, &line_count,
-                   relative_point_coordinates.x(),
-                   relative_point_coordinates.y(), keyboard_tooltip_hwnd_);
-  TOOLINFO keyboard_toolinfo;
-  memset(&keyboard_toolinfo, 0, sizeof(keyboard_toolinfo));
-  keyboard_toolinfo.cbSize = sizeof(keyboard_toolinfo);
-  keyboard_toolinfo.hwnd = parent_;
-  keyboard_toolinfo.uFlags = TTF_TRACK | TTF_TRANSPARENT | TTF_IDISHWND ;
-  keyboard_toolinfo.lpszText = const_cast<WCHAR*>(tooltip_text.c_str());
-  SendMessage(keyboard_tooltip_hwnd_, TTM_ADDTOOL, 0,
-              reinterpret_cast<LPARAM>(&keyboard_toolinfo));
-  SendMessage(keyboard_tooltip_hwnd_, TTM_TRACKACTIVATE,  TRUE,
-              reinterpret_cast<LPARAM>(&keyboard_toolinfo));
-  if (!tooltip_height_)
-    tooltip_height_ = CalcTooltipHeight();
-  RECT rect_bounds = {screen_point.x(),
-                      screen_point.y() + focused_bounds.height(),
-                      screen_point.x() + tooltip_width,
-                      screen_point.y() + focused_bounds.height() +
-                      line_count * tooltip_height_ };
-  gfx::Rect monitor_bounds =
-      win_util::GetMonitorBoundsForRect(gfx::Rect(rect_bounds));
-  rect_bounds = gfx::Rect(rect_bounds).AdjustToFit(monitor_bounds).ToRECT();
-  ::SetWindowPos(keyboard_tooltip_hwnd_, NULL, rect_bounds.left,
-                 rect_bounds.top, 0, 0,
-                 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
-  MessageLoop::current()->PostDelayedTask(FROM_HERE,
-      keyboard_tooltip_factory_.NewRunnableMethod(
-      &TooltipManager::DestroyKeyboardTooltipWindow, keyboard_tooltip_hwnd_),
-      kDefaultTimeout);
-}
-
-void TooltipManager::HideKeyboardTooltip() {
-  if (keyboard_tooltip_hwnd_ != NULL) {
-    SendMessage(keyboard_tooltip_hwnd_, WM_CLOSE, 0, 0);
-    keyboard_tooltip_hwnd_ = NULL;
-  }
-}
-
-void TooltipManager::DestroyKeyboardTooltipWindow(HWND window_to_destroy) {
-  if (keyboard_tooltip_hwnd_ == window_to_destroy)
-    HideKeyboardTooltip();
-}
-
-}  // namespace views
diff --git a/views/widget/tooltip_manager.h b/views/widget/tooltip_manager.h
index 5cfe2bf..cb48973 100644
--- a/views/widget/tooltip_manager.h
+++ b/views/widget/tooltip_manager.h
@@ -5,51 +5,21 @@
 #ifndef VIEWS_WIDGET_TOOLTIP_MANAGER_H_
 #define VIEWS_WIDGET_TOOLTIP_MANAGER_H_
 
-#include <windows.h>
-#include <commctrl.h>
-
 #include <string>
+
 #include "base/basictypes.h"
-#include "base/task.h"
 
 namespace gfx {
 class Font;
-}
+}  // namespace gfx
 
 namespace views {
 
 class View;
-class Widget;
-
-// TooltipManager takes care of the wiring to support tooltips for Views.
-// This class is intended to be used by Widgets. To use this, you must
-// do the following:
-// Add the following to your MSG_MAP:
-//
-//   MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange)
-//   MESSAGE_RANGE_HANDLER(WM_NCMOUSEMOVE, WM_NCMOUSEMOVE, OnMouseRange)
-//   MSG_WM_NOTIFY(OnNotify)
-//
-// With the following implementations:
-//   LRESULT XXX::OnMouseRange(UINT u_msg, WPARAM w_param, LPARAM l_param,
-//                             BOOL& handled) {
-//     tooltip_manager_->OnMouse(u_msg, w_param, l_param);
-//     handled = FALSE;
-//     return 0;
-//   }
-//
-//   LRESULT XXX::OnNotify(int w_param, NMHDR* l_param) {
-//     bool handled;
-//     LRESULT result = tooltip_manager_->OnNotify(w_param, l_param, &handled);
-//     SetMsgHandled(handled);
-//     return result;
-//   }
-//
-// And of course you'll need to create the TooltipManager!
-//
-// Lastly, you'll need to override GetTooltipManager.
-//
-// See XPFrame for an example of this in action.
+
+// TooltipManager takes care of the wiring to support tooltips for Views. You
+// almost never need to interact directly with TooltipManager, rather look to
+// the various tooltip methods on View.
 class TooltipManager {
  public:
   // Returns the height of tooltips. This should only be invoked from within
@@ -62,109 +32,22 @@ class TooltipManager {
   // Returns the separator for lines of text in a tooltip.
   static const std::wstring& GetLineSeparator();
 
-  // Creates a TooltipManager for the specified Widget and parent window.
-  TooltipManager(Widget* widget, HWND parent);
-  virtual ~TooltipManager();
+  TooltipManager() {}
+  virtual ~TooltipManager() {}
 
   // Notification that the view hierarchy has changed in some way.
-  void UpdateTooltip();
+  virtual void UpdateTooltip() = 0;
 
   // Invoked when the tooltip text changes for the specified views.
-  void TooltipTextChanged(View* view);
+  virtual void TooltipTextChanged(View* view) = 0;
 
   // Invoked when toolbar icon gets focus.
-  void ShowKeyboardTooltip(View* view);
+  virtual void ShowKeyboardTooltip(View* view) = 0;
 
   // Invoked when toolbar loses focus.
-  void HideKeyboardTooltip();
-
-  // Message handlers. These forward to the tooltip control.
-  virtual void OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param);
-  LRESULT OnNotify(int w_param, NMHDR* l_param, bool* handled);
-  // Not used directly by TooltipManager, but provided for AeroTooltipManager.
-  virtual void OnMouseLeave() {}
-
- protected:
-  virtual void Init();
-
-  // Updates the tooltip for the specified location.
-  void UpdateTooltip(int x, int y);
-
-  // Parent window the tooltip is added to.
-  HWND parent_;
-
-  // Tooltip control window.
-  HWND tooltip_hwnd_;
-
-  // Tooltip information.
-  TOOLINFO toolinfo_;
-
-  // Last location of the mouse. This is in the coordinates of the rootview.
-  int last_mouse_x_;
-  int last_mouse_y_;
-
-  // Whether or not the tooltip is showing.
-  bool tooltip_showing_;
-
- private:
-  // Sets the tooltip position based on the x/y position of the text. If the
-  // tooltip fits, true is returned.
-  bool SetTooltipPosition(int text_x, int text_y);
-
-  // Calculates the preferred height for tooltips. This always returns a
-  // positive value.
-  int CalcTooltipHeight();
-
-  // Trims the tooltip to fit, setting text to the clipped result, width to the
-  // width (in pixels) of the clipped text and line_count to the number of lines
-  // of text in the tooltip.
-  void TrimTooltipToFit(std::wstring* text,
-                        int* width,
-                        int* line_count,
-                        int position_x,
-                        int position_y,
-                        HWND window);
-
-  // Invoked when the timer elapses and tooltip has to be destroyed.
-  void DestroyKeyboardTooltipWindow(HWND window_to_destroy);
-
-  // Hosting Widget.
-  Widget* widget_;
-
-  // The View the mouse is under. This is null if the mouse isn't under a
-  // View.
-  View* last_tooltip_view_;
-
-  // Whether or not the view under the mouse needs to be refreshed. If this
-  // is true, when the tooltip is asked for the view under the mouse is
-  // refreshed.
-  bool last_view_out_of_sync_;
-
-  // Text for tooltip from the view.
-  std::wstring tooltip_text_;
-
-  // The clipped tooltip.
-  std::wstring clipped_text_;
-
-  // Number of lines in the tooltip.
-  int line_count_;
-
-  // Width of the last tooltip.
-  int tooltip_width_;
-
-  // Height for a tooltip; lazily calculated.
-  static int tooltip_height_;
-
-  // control window for tooltip displayed using keyboard.
-  HWND keyboard_tooltip_hwnd_;
-
-  // Used to register DestroyTooltipWindow function with PostDelayedTask
-  // function.
-  ScopedRunnableMethodFactory<TooltipManager> keyboard_tooltip_factory_;
-
-  DISALLOW_EVIL_CONSTRUCTORS(TooltipManager);
+  virtual void HideKeyboardTooltip() = 0;
 };
 
 }  // namespace views
 
-#endif // VIEWS_WIDGET_TOOLTIP_MANAGER_H_
+#endif  // VIEWS_WIDGET_TOOLTIP_MANAGER_H_
diff --git a/views/widget/tooltip_manager_gtk.cc b/views/widget/tooltip_manager_gtk.cc
new file mode 100644
index 0000000..702514a
--- /dev/null
+++ b/views/widget/tooltip_manager_gtk.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "views/widget/tooltip_manager_gtk.h"
+
+#include "app/gfx/font.h"
+#include "base/logging.h"
+
+namespace views {
+
+// static
+int TooltipManager::GetTooltipHeight() {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+// static
+gfx::Font TooltipManager::GetDefaultFont() {
+  NOTIMPLEMENTED();
+  return gfx::Font();
+}
+
+// static
+const std::wstring& TooltipManager::GetLineSeparator() {
+  static std::wstring* line_separator = NULL;
+  if (!line_separator)
+    line_separator = new std::wstring(L"\n");
+  return *line_separator;
+}
+
+TooltipManagerGtk::TooltipManagerGtk(Widget* widget) : widget_(widget) {
+}
+
+void TooltipManagerGtk::UpdateTooltip() {
+  NOTIMPLEMENTED();
+}
+
+void TooltipManagerGtk::TooltipTextChanged(View* view) {
+  NOTIMPLEMENTED();
+}
+
+void TooltipManagerGtk::ShowKeyboardTooltip(View* view) {
+  NOTIMPLEMENTED();
+}
+
+void TooltipManagerGtk::HideKeyboardTooltip() {
+  NOTIMPLEMENTED();
+}
+
+}  // namespace views
diff --git a/views/widget/tooltip_manager_gtk.h b/views/widget/tooltip_manager_gtk.h
new file mode 100644
index 0000000..447f6ce
--- /dev/null
+++ b/views/widget/tooltip_manager_gtk.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef VIEWS_WIDGET_TOOLTIP_MANAGER_GTK_H_
+#define VIEWS_WIDGET_TOOLTIP_MANAGER_GTK_H_
+
+#include "views/widget/tooltip_manager.h"
+
+namespace views {
+
+class Widget;
+
+// TooltipManager takes care of the wiring to support tooltips for Views. You
+// almost never need to interact directly with TooltipManager, rather look to
+// the various tooltip methods on View.
+class TooltipManagerGtk : public TooltipManager {
+ public:
+  explicit TooltipManagerGtk(Widget* widget);
+  virtual ~TooltipManagerGtk() {}
+
+  // TooltipManager.
+  virtual void UpdateTooltip();
+  virtual void TooltipTextChanged(View* view);
+  virtual void ShowKeyboardTooltip(View* view);
+  virtual void HideKeyboardTooltip();
+
+ private:
+  // Our owner.
+  Widget* widget_;
+
+  DISALLOW_COPY_AND_ASSIGN(TooltipManagerGtk);
+};
+
+}  // namespace views
+
+#endif // VIEWS_WIDGET_TOOLTIP_MANAGER_GTK_H_
diff --git a/views/widget/tooltip_manager_win.cc b/views/widget/tooltip_manager_win.cc
new file mode 100644
index 0000000..70aff1e
--- /dev/null
+++ b/views/widget/tooltip_manager_win.cc
@@ -0,0 +1,454 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "views/widget/tooltip_manager_win.h"
+
+#include <windowsx.h>
+#include <limits>
+
+#include "app/gfx/text_elider.h"
+#include "app/l10n_util.h"
+#include "app/l10n_util_win.h"
+#include "app/win_util.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "views/view.h"
+#include "views/widget/root_view.h"
+#include "views/widget/widget.h"
+
+namespace views {
+
+static int tooltip_height_ = 0;
+
+// Default timeout for the tooltip displayed using keyboard.
+// Timeout is mentioned in milliseconds.
+static const int kDefaultTimeout = 4000;
+
+// Maximum number of lines we allow in the tooltip.
+static const int kMaxLines = 6;
+
+// Maximum number of characters we allow in a tooltip.
+static const int kMaxTooltipLength = 1024;
+
+// Breaks |text| along line boundaries, placing each line of text into lines.
+static void SplitTooltipString(const std::wstring& text,
+                               std::vector<std::wstring>* lines) {
+  size_t index = 0;
+  size_t next_index;
+  while ((next_index = text.find(TooltipManagerWin::GetLineSeparator(), index))
+         != std::wstring::npos && lines->size() < kMaxLines) {
+    lines->push_back(text.substr(index, next_index - index));
+    index = next_index + TooltipManagerWin::GetLineSeparator().size();
+  }
+  if (next_index != text.size() && lines->size() < kMaxLines)
+    lines->push_back(text.substr(index, text.size() - index));
+}
+
+// static
+int TooltipManager::GetTooltipHeight() {
+  DCHECK(tooltip_height_ > 0);
+  return tooltip_height_;
+}
+
+static gfx::Font DetermineDefaultFont() {
+  HWND window = CreateWindowEx(
+      WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
+      TOOLTIPS_CLASS, NULL, 0 , 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+  HFONT hfont = reinterpret_cast<HFONT>(SendMessage(window, WM_GETFONT, 0, 0));
+  gfx::Font font = hfont ? gfx::Font::CreateFont(hfont) : gfx::Font();
+  DestroyWindow(window);
+  return font;
+}
+
+// static
+gfx::Font TooltipManager::GetDefaultFont() {
+  static gfx::Font* font = NULL;
+  if (!font)
+    font = new gfx::Font(DetermineDefaultFont());
+  return *font;
+}
+
+// static
+const std::wstring& TooltipManager::GetLineSeparator() {
+  static const std::wstring* separator = NULL;
+  if (!separator)
+    separator = new std::wstring(L"\r\n");
+  return *separator;
+}
+
+TooltipManagerWin::TooltipManagerWin(Widget* widget)
+    : widget_(widget),
+      last_mouse_x_(-1),
+      last_mouse_y_(-1),
+      tooltip_showing_(false),
+      last_tooltip_view_(NULL),
+      last_view_out_of_sync_(false),
+      tooltip_width_(0),
+      keyboard_tooltip_hwnd_(NULL),
+#pragma warning(suppress: 4355)
+      keyboard_tooltip_factory_(this) {
+  DCHECK(widget);
+  DCHECK(widget->GetNativeView());
+  Init();
+}
+
+TooltipManagerWin::~TooltipManagerWin() {
+  if (tooltip_hwnd_)
+    DestroyWindow(tooltip_hwnd_);
+  if (keyboard_tooltip_hwnd_)
+    DestroyWindow(keyboard_tooltip_hwnd_);
+}
+
+void TooltipManagerWin::Init() {
+  // Create the tooltip control.
+  tooltip_hwnd_ = CreateWindowEx(
+      WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
+      TOOLTIPS_CLASS, NULL, TTS_NOPREFIX, 0, 0, 0, 0,
+      GetParent(), NULL, NULL, NULL);
+
+  l10n_util::AdjustUIFontForWindow(tooltip_hwnd_);
+
+  // This effectively turns off clipping of tooltips. We need this otherwise
+  // multi-line text (\r\n) won't work right. The size doesn't really matter
+  // (just as long as its bigger than the monitor's width) as we clip to the
+  // screen size before rendering.
+  SendMessage(tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0,
+              std::numeric_limits<short>::max());
+
+  // Add one tool that is used for all tooltips.
+  toolinfo_.cbSize = sizeof(toolinfo_);
+  toolinfo_.uFlags = TTF_TRANSPARENT | TTF_IDISHWND;
+  toolinfo_.hwnd = GetParent();
+  toolinfo_.uId = reinterpret_cast<UINT_PTR>(GetParent());
+  // Setting this tells windows to call GetParent() back (using a WM_NOTIFY
+  // message) for the actual tooltip contents.
+  toolinfo_.lpszText = LPSTR_TEXTCALLBACK;
+  SetRectEmpty(&toolinfo_.rect);
+  SendMessage(tooltip_hwnd_, TTM_ADDTOOL, 0, (LPARAM)&toolinfo_);
+}
+
+gfx::NativeView TooltipManagerWin::GetParent() {
+  return widget_->GetNativeView();
+}
+
+void TooltipManagerWin::UpdateTooltip() {
+  // Set last_view_out_of_sync_ to indicate the view is currently out of sync.
+  // This doesn't update the view under the mouse immediately as it may cause
+  // timing problems.
+  last_view_out_of_sync_ = true;
+  last_tooltip_view_ = NULL;
+  // Hide the tooltip.
+  SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+}
+
+void TooltipManagerWin::TooltipTextChanged(View* view) {
+  if (view == last_tooltip_view_)
+    UpdateTooltip(last_mouse_x_, last_mouse_y_);
+}
+
+LRESULT TooltipManagerWin::OnNotify(int w_param,
+                                    NMHDR* l_param,
+                                    bool* handled) {
+  *handled = false;
+  if (l_param->hwndFrom == tooltip_hwnd_ && keyboard_tooltip_hwnd_ == NULL) {
+    switch (l_param->code) {
+      case TTN_GETDISPINFO: {
+        if (last_view_out_of_sync_) {
+          // View under the mouse is out of sync, determine it now.
+          RootView* root_view = widget_->GetRootView();
+          last_tooltip_view_ = root_view->GetViewForPoint(
+              gfx::Point(last_mouse_x_, last_mouse_y_));
+          last_view_out_of_sync_ = false;
+        }
+        // Tooltip control is asking for the tooltip to display.
+        NMTTDISPINFOW* tooltip_info =
+            reinterpret_cast<NMTTDISPINFOW*>(l_param);
+        // Initialize the string, if we have a valid tooltip the string will
+        // get reset below.
+        tooltip_info->szText[0] = TEXT('\0');
+        tooltip_text_.clear();
+        tooltip_info->lpszText = NULL;
+        clipped_text_.clear();
+        if (last_tooltip_view_ != NULL) {
+          tooltip_text_.clear();
+          // Mouse is over a View, ask the View for it's tooltip.
+          gfx::Point view_loc(last_mouse_x_, last_mouse_y_);
+          View::ConvertPointToView(widget_->GetRootView(),
+                                   last_tooltip_view_, &view_loc);
+          if (last_tooltip_view_->GetTooltipText(view_loc.x(), view_loc.y(),
+                                                 &tooltip_text_) &&
+              !tooltip_text_.empty()) {
+            // View has a valid tip, copy it into TOOLTIPINFO.
+            clipped_text_ = tooltip_text_;
+            TrimTooltipToFit(&clipped_text_, &tooltip_width_, &line_count_,
+                             last_mouse_x_, last_mouse_y_, tooltip_hwnd_);
+            // Adjust the clipped tooltip text for locale direction.
+            l10n_util::AdjustStringForLocaleDirection(clipped_text_,
+                                                      &clipped_text_);
+            tooltip_info->lpszText = const_cast<WCHAR*>(clipped_text_.c_str());
+          } else {
+            tooltip_text_.clear();
+          }
+        }
+        *handled = true;
+        return 0;
+      }
+      case TTN_POP:
+        tooltip_showing_ = false;
+        *handled = true;
+        return 0;
+      case TTN_SHOW: {
+        *handled = true;
+        tooltip_showing_ = true;
+        // The tooltip is about to show, allow the view to position it
+        gfx::Point text_origin;
+        if (tooltip_height_ == 0)
+          tooltip_height_ = CalcTooltipHeight();
+        gfx::Point view_loc(last_mouse_x_, last_mouse_y_);
+        View::ConvertPointToView(widget_->GetRootView(),
+                                 last_tooltip_view_, &view_loc);
+        if (last_tooltip_view_->GetTooltipTextOrigin(
+              view_loc.x(), view_loc.y(), &text_origin) &&
+            SetTooltipPosition(text_origin.x(), text_origin.y())) {
+          // Return true, otherwise the rectangle we specified is ignored.
+          return TRUE;
+        }
+        return 0;
+      }
+      default:
+        // Fall through.
+        break;
+    }
+  }
+  return 0;
+}
+
+bool TooltipManagerWin::SetTooltipPosition(int text_x, int text_y) {
+  // NOTE: this really only tests that the y location fits on screen, but that
+  // is good enough for our usage.
+
+  // Calculate the bounds the tooltip will get.
+  gfx::Point view_loc;
+  View::ConvertPointToScreen(last_tooltip_view_, &view_loc);
+  RECT bounds = { view_loc.x() + text_x,
+                  view_loc.y() + text_y,
+                  view_loc.x() + text_x + tooltip_width_,
+                  view_loc.y() + line_count_ * GetTooltipHeight() };
+  SendMessage(tooltip_hwnd_, TTM_ADJUSTRECT, TRUE, (LPARAM)&bounds);
+
+  // Make sure the rectangle completely fits on the current monitor. If it
+  // doesn't, return false so that windows positions the tooltip at the
+  // default location.
+  gfx::Rect monitor_bounds =
+      win_util::GetMonitorBoundsForRect(gfx::Rect(bounds.left,bounds.right,
+                                                  0, 0));
+  if (!monitor_bounds.Contains(gfx::Rect(bounds))) {
+    return false;
+  }
+
+  ::SetWindowPos(tooltip_hwnd_, NULL, bounds.left, bounds.top, 0, 0,
+                 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
+  return true;
+}
+
+int TooltipManagerWin::CalcTooltipHeight() {
+  // Ask the tooltip for it's font.
+  int height;
+  HFONT hfont = reinterpret_cast<HFONT>(
+      SendMessage(tooltip_hwnd_, WM_GETFONT, 0, 0));
+  if (hfont != NULL) {
+    HDC dc = GetDC(tooltip_hwnd_);
+    HFONT previous_font = static_cast<HFONT>(SelectObject(dc, hfont));
+    int last_map_mode = SetMapMode(dc, MM_TEXT);
+    TEXTMETRIC font_metrics;
+    GetTextMetrics(dc, &font_metrics);
+    height = font_metrics.tmHeight;
+    // To avoid the DC referencing font_handle_, select the previous font.
+    SelectObject(dc, previous_font);
+    SetMapMode(dc, last_map_mode);
+    ReleaseDC(NULL, dc);
+  } else {
+    // Tooltip is using the system font. Use gfx::Font, which should pick
+    // up the system font.
+    height = gfx::Font().height();
+  }
+  // Get the margins from the tooltip
+  RECT tooltip_margin;
+  SendMessage(tooltip_hwnd_, TTM_GETMARGIN, 0, (LPARAM)&tooltip_margin);
+  return height + tooltip_margin.top + tooltip_margin.bottom;
+}
+
+void TooltipManagerWin::TrimTooltipToFit(std::wstring* text,
+                                         int* max_width,
+                                         int* line_count,
+                                         int position_x,
+                                         int position_y,
+                                         HWND window) {
+  *max_width = 0;
+  *line_count = 0;
+
+  // Clamp the tooltip length to kMaxTooltipLength so that we don't
+  // accidentally DOS the user with a mega tooltip (since Windows doesn't seem
+  // to do this itself).
+  if (text->length() > kMaxTooltipLength)
+    *text = text->substr(0, kMaxTooltipLength);
+
+  // Determine the available width for the tooltip.
+  gfx::Point screen_loc(position_x, position_y);
+  View::ConvertPointToScreen(widget_->GetRootView(), &screen_loc);
+  gfx::Rect monitor_bounds =
+      win_util::GetMonitorBoundsForRect(gfx::Rect(screen_loc.x(),
+                                                  screen_loc.y(),
+                                                  0, 0));
+  RECT tooltip_margin;
+  SendMessage(window, TTM_GETMARGIN, 0, (LPARAM)&tooltip_margin);
+  const int available_width = monitor_bounds.width() - tooltip_margin.left -
+      tooltip_margin.right;
+  if (available_width <= 0)
+    return;
+
+  // Split the string.
+  std::vector<std::wstring> lines;
+  SplitTooltipString(*text, &lines);
+  *line_count = static_cast<int>(lines.size());
+
+  // Format each line to fit.
+  gfx::Font font = GetDefaultFont();
+  std::wstring result;
+  for (std::vector<std::wstring>::iterator i = lines.begin(); i != lines.end();
+       ++i) {
+    std::wstring elided_text = gfx::ElideText(*i, font, available_width);
+    *max_width = std::max(*max_width, font.GetStringWidth(elided_text));
+    if (i == lines.begin() && i + 1 == lines.end()) {
+      *text = elided_text;
+      return;
+    }
+    if (!result.empty())
+      result.append(GetLineSeparator());
+    result.append(elided_text);
+  }
+  *text = result;
+}
+
+void TooltipManagerWin::UpdateTooltip(int x, int y) {
+  RootView* root_view = widget_->GetRootView();
+  View* view = root_view->GetViewForPoint(gfx::Point(x, y));
+  if (view != last_tooltip_view_) {
+    // NOTE: This *must* be sent regardless of the visibility of the tooltip.
+    // It triggers Windows to ask for the tooltip again.
+    SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+    last_tooltip_view_ = view;
+  } else if (last_tooltip_view_ != NULL) {
+    // Tooltip is showing, and mouse is over the same view. See if the tooltip
+    // text has changed.
+    gfx::Point view_point(x, y);
+    View::ConvertPointToView(root_view, last_tooltip_view_, &view_point);
+    std::wstring new_tooltip_text;
+    if (last_tooltip_view_->GetTooltipText(view_point.x(), view_point.y(),
+                                           &new_tooltip_text) &&
+        new_tooltip_text != tooltip_text_) {
+      // The text has changed, hide the popup.
+      SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+      if (!new_tooltip_text.empty() && tooltip_showing_) {
+        // New text is valid, show the popup.
+        SendMessage(tooltip_hwnd_, TTM_POPUP, 0, 0);
+      }
+    }
+  }
+}
+
+void TooltipManagerWin::OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param) {
+  int x = GET_X_LPARAM(l_param);
+  int y = GET_Y_LPARAM(l_param);
+
+  if (u_msg >= WM_NCMOUSEMOVE && u_msg <= WM_NCXBUTTONDBLCLK) {
+    // NC message coordinates are in screen coordinates.
+    gfx::Rect frame_bounds;
+    widget_->GetBounds(&frame_bounds, true);
+    x -= frame_bounds.x();
+    y -= frame_bounds.y();
+  }
+
+  if (u_msg != WM_MOUSEMOVE || last_mouse_x_ != x || last_mouse_y_ != y) {
+    last_mouse_x_ = x;
+    last_mouse_y_ = y;
+    HideKeyboardTooltip();
+    UpdateTooltip(x, y);
+  }
+  // Forward the message onto the tooltip.
+  MSG msg;
+  msg.hwnd = GetParent();
+  msg.message = u_msg;
+  msg.wParam = w_param;
+  msg.lParam = l_param;
+  SendMessage(tooltip_hwnd_, TTM_RELAYEVENT, 0, (LPARAM)&msg);
+}
+
+void TooltipManagerWin::ShowKeyboardTooltip(View* focused_view) {
+  if (tooltip_showing_) {
+    SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+    tooltip_text_.clear();
+  }
+  HideKeyboardTooltip();
+  std::wstring tooltip_text;
+  if (!focused_view->GetTooltipText(0, 0, &tooltip_text))
+    return;
+  gfx::Rect focused_bounds = focused_view->bounds();
+  gfx::Point screen_point;
+  focused_view->ConvertPointToScreen(focused_view, &screen_point);
+  gfx::Point relative_point_coordinates;
+  focused_view->ConvertPointToWidget(focused_view, &relative_point_coordinates);
+  keyboard_tooltip_hwnd_ = CreateWindowEx(
+      WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
+      TOOLTIPS_CLASS, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+  SendMessage(keyboard_tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0,
+              std::numeric_limits<short>::max());
+  int tooltip_width;
+  int line_count;
+  TrimTooltipToFit(&tooltip_text, &tooltip_width, &line_count,
+                   relative_point_coordinates.x(),
+                   relative_point_coordinates.y(), keyboard_tooltip_hwnd_);
+  TOOLINFO keyboard_toolinfo;
+  memset(&keyboard_toolinfo, 0, sizeof(keyboard_toolinfo));
+  keyboard_toolinfo.cbSize = sizeof(keyboard_toolinfo);
+  keyboard_toolinfo.hwnd = GetParent();
+  keyboard_toolinfo.uFlags = TTF_TRACK | TTF_TRANSPARENT | TTF_IDISHWND ;
+  keyboard_toolinfo.lpszText = const_cast<WCHAR*>(tooltip_text.c_str());
+  SendMessage(keyboard_tooltip_hwnd_, TTM_ADDTOOL, 0,
+              reinterpret_cast<LPARAM>(&keyboard_toolinfo));
+  SendMessage(keyboard_tooltip_hwnd_, TTM_TRACKACTIVATE,  TRUE,
+              reinterpret_cast<LPARAM>(&keyboard_toolinfo));
+  if (!tooltip_height_)
+    tooltip_height_ = CalcTooltipHeight();
+  RECT rect_bounds = {screen_point.x(),
+                      screen_point.y() + focused_bounds.height(),
+                      screen_point.x() + tooltip_width,
+                      screen_point.y() + focused_bounds.height() +
+                      line_count * tooltip_height_ };
+  gfx::Rect monitor_bounds =
+      win_util::GetMonitorBoundsForRect(gfx::Rect(rect_bounds));
+  rect_bounds = gfx::Rect(rect_bounds).AdjustToFit(monitor_bounds).ToRECT();
+  ::SetWindowPos(keyboard_tooltip_hwnd_, NULL, rect_bounds.left,
+                 rect_bounds.top, 0, 0,
+                 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
+  MessageLoop::current()->PostDelayedTask(FROM_HERE,
+      keyboard_tooltip_factory_.NewRunnableMethod(
+      &TooltipManagerWin::DestroyKeyboardTooltipWindow,
+      keyboard_tooltip_hwnd_),
+      kDefaultTimeout);
+}
+
+void TooltipManagerWin::HideKeyboardTooltip() {
+  if (keyboard_tooltip_hwnd_ != NULL) {
+    SendMessage(keyboard_tooltip_hwnd_, WM_CLOSE, 0, 0);
+    keyboard_tooltip_hwnd_ = NULL;
+  }
+}
+
+void TooltipManagerWin::DestroyKeyboardTooltipWindow(HWND window_to_destroy) {
+  if (keyboard_tooltip_hwnd_ == window_to_destroy)
+    HideKeyboardTooltip();
+}
+
+}  // namespace views
diff --git a/views/widget/tooltip_manager_win.h b/views/widget/tooltip_manager_win.h
new file mode 100644
index 0000000..b2213c3
--- /dev/null
+++ b/views/widget/tooltip_manager_win.h
@@ -0,0 +1,160 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef VIEWS_WIDGET_TOOLTIP_MANAGER_WIN_H_
+#define VIEWS_WIDGET_TOOLTIP_MANAGER_WIN_H_
+
+#include <windows.h>
+#include <commctrl.h>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/gfx/native_widget_types.h"
+#include "base/task.h"
+#include "views/widget/tooltip_manager.h"
+
+namespace gfx {
+class Font;
+}
+
+namespace views {
+
+class View;
+class Widget;
+
+// TooltipManager implementation for Windows.
+//
+// This class is intended to be used by WidgetWin. To use this, you must
+// do the following:
+// Add the following to your MSG_MAP:
+//
+//   MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange)
+//   MESSAGE_RANGE_HANDLER(WM_NCMOUSEMOVE, WM_NCMOUSEMOVE, OnMouseRange)
+//   MSG_WM_NOTIFY(OnNotify)
+//
+// With the following implementations:
+//   LRESULT XXX::OnMouseRange(UINT u_msg, WPARAM w_param, LPARAM l_param,
+//                             BOOL& handled) {
+//     tooltip_manager_->OnMouse(u_msg, w_param, l_param);
+//     handled = FALSE;
+//     return 0;
+//   }
+//
+//   LRESULT XXX::OnNotify(int w_param, NMHDR* l_param) {
+//     bool handled;
+//     LRESULT result = tooltip_manager_->OnNotify(w_param, l_param, &handled);
+//     SetMsgHandled(handled);
+//     return result;
+//   }
+//
+// And of course you'll need to create the TooltipManager!
+//
+// Lastly, you'll need to override GetTooltipManager.
+//
+// See WidgetWin for an example of this in action.
+class TooltipManagerWin : public TooltipManager {
+ public:
+  // Creates a TooltipManager for the specified Widget and parent window.
+  explicit TooltipManagerWin(Widget* widget);
+  virtual ~TooltipManagerWin();
+
+  // Notification that the view hierarchy has changed in some way.
+  virtual void UpdateTooltip();
+
+  // Invoked when the tooltip text changes for the specified views.
+  virtual void TooltipTextChanged(View* view);
+
+  // Invoked when toolbar icon gets focus.
+  virtual void ShowKeyboardTooltip(View* view);
+
+  // Invoked when toolbar loses focus.
+  virtual void HideKeyboardTooltip();
+
+  // Message handlers. These forward to the tooltip control.
+  virtual void OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param);
+  LRESULT OnNotify(int w_param, NMHDR* l_param, bool* handled);
+  // Not used directly by TooltipManager, but provided for AeroTooltipManager.
+  virtual void OnMouseLeave() {}
+
+ protected:
+  virtual void Init();
+
+  // Returns the Widget we're showing tooltips for.
+  gfx::NativeView GetParent();
+
+  // Updates the tooltip for the specified location.
+  void UpdateTooltip(int x, int y);
+
+  // Tooltip control window.
+  HWND tooltip_hwnd_;
+
+  // Tooltip information.
+  TOOLINFO toolinfo_;
+
+  // Last location of the mouse. This is in the coordinates of the rootview.
+  int last_mouse_x_;
+  int last_mouse_y_;
+
+  // Whether or not the tooltip is showing.
+  bool tooltip_showing_;
+
+ private:
+  // Sets the tooltip position based on the x/y position of the text. If the
+  // tooltip fits, true is returned.
+  bool SetTooltipPosition(int text_x, int text_y);
+
+  // Calculates the preferred height for tooltips. This always returns a
+  // positive value.
+  int CalcTooltipHeight();
+
+  // Trims the tooltip to fit, setting text to the clipped result, width to the
+  // width (in pixels) of the clipped text and line_count to the number of lines
+  // of text in the tooltip.
+  void TrimTooltipToFit(std::wstring* text,
+                        int* width,
+                        int* line_count,
+                        int position_x,
+                        int position_y,
+                        HWND window);
+
+  // Invoked when the timer elapses and tooltip has to be destroyed.
+  void DestroyKeyboardTooltipWindow(HWND window_to_destroy);
+
+  // Hosting Widget.
+  Widget* widget_;
+
+  // The View the mouse is under. This is null if the mouse isn't under a
+  // View.
+  View* last_tooltip_view_;
+
+  // Whether or not the view under the mouse needs to be refreshed. If this
+  // is true, when the tooltip is asked for the view under the mouse is
+  // refreshed.
+  bool last_view_out_of_sync_;
+
+  // Text for tooltip from the view.
+  std::wstring tooltip_text_;
+
+  // The clipped tooltip.
+  std::wstring clipped_text_;
+
+  // Number of lines in the tooltip.
+  int line_count_;
+
+  // Width of the last tooltip.
+  int tooltip_width_;
+
+  // control window for tooltip displayed using keyboard.
+  HWND keyboard_tooltip_hwnd_;
+
+  // Used to register DestroyTooltipWindow function with PostDelayedTask
+  // function.
+  ScopedRunnableMethodFactory<TooltipManagerWin> keyboard_tooltip_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(TooltipManagerWin);
+};
+
+}  // namespace views
+
+#endif // VIEWS_WIDGET_TOOLTIP_MANAGER_WIN_H_
diff --git a/views/widget/widget_gtk.cc b/views/widget/widget_gtk.cc
index 96a2ad3..a1d30f6 100644
--- a/views/widget/widget_gtk.cc
+++ b/views/widget/widget_gtk.cc
@@ -7,6 +7,7 @@
 #include "base/compiler_specific.h"
 #include "views/fill_layout.h"
 #include "views/widget/root_view.h"
+#include "views/widget/tooltip_manager_gtk.h"
 #include "views/window/window_gtk.h"
 
 namespace views {
@@ -152,6 +153,8 @@ void WidgetGtk::Init(GtkWidget* parent,
   // g_signal_connect(G_OBJECT(widget_), "drag_data_received",
   //                  G_CALLBACK(drag_data_received_event_cb), NULL);
 
+  tooltip_manager_.reset(new TooltipManagerGtk(this));
+
   if (type_ == TYPE_CHILD) {
     WidgetGtk* parent_widget = GetViewForNative(parent);
     parent_widget->AddChild(widget_);
@@ -301,8 +304,7 @@ bool WidgetGtk::IsActive() const {
 }
 
 TooltipManager* WidgetGtk::GetTooltipManager() {
-  NOTIMPLEMENTED();
-  return NULL;
+  return tooltip_manager_.get();
 }
 
 bool WidgetGtk::GetAccelerator(int cmd_id, Accelerator* accelerator) {
diff --git a/views/widget/widget_gtk.h b/views/widget/widget_gtk.h
index 7cbc87e..3d57e4f 100644
--- a/views/widget/widget_gtk.h
+++ b/views/widget/widget_gtk.h
@@ -16,6 +16,7 @@ class Rect;
 
 namespace views {
 
+class TooltipManagerGtk;
 class View;
 class WindowGtk;
 
@@ -172,6 +173,8 @@ class WidgetGtk : public Widget, public MessageLoopForUI::Observer {
   // The root of the View hierarchy attached to this window.
   scoped_ptr<RootView> root_view_;
 
+  scoped_ptr<TooltipManagerGtk> tooltip_manager_;
+
   // If true, the mouse is currently down.
   bool is_mouse_down_;
 
diff --git a/views/widget/widget_win.cc b/views/widget/widget_win.cc
index 039ab36..516b771 100644
--- a/views/widget/widget_win.cc
+++ b/views/widget/widget_win.cc
@@ -203,9 +203,9 @@ void WidgetWin::Init(HWND parent, const gfx::Rect& bounds,
   // that window controls in Chrome windows don't flicker when you move your
   // mouse over them. See comment in aero_tooltip_manager.h.
   if (win_util::ShouldUseVistaFrame()) {
-    tooltip_manager_.reset(new AeroTooltipManager(this, GetNativeView()));
+    tooltip_manager_.reset(new AeroTooltipManager(this));
   } else {
-    tooltip_manager_.reset(new TooltipManager(this, GetNativeView()));
+    tooltip_manager_.reset(new TooltipManagerWin(this));
   }
 
   // This message initializes the window so that focus border are shown for
diff --git a/views/widget/widget_win.h b/views/widget/widget_win.h
index ebf6bfa..fa6bab6 100644
--- a/views/widget/widget_win.h
+++ b/views/widget/widget_win.h
@@ -24,7 +24,7 @@ class Rect;
 namespace views {
 
 class RootView;
-class TooltipManager;
+class TooltipManagerWin;
 class DefaultThemeProvider;
 class Window;
 
@@ -506,7 +506,17 @@ class WidgetWin : public Widget,
   // Returns true if this WidgetWin is opaque.
   bool opaque() const { return opaque_; }
 
+  // The TooltipManager.
+  // WARNING: RootView's destructor calls into the TooltipManager. As such, this
+  // must be destroyed AFTER root_view_. This really only matters during
+  // WM_SESSIONEND, as normally the hwnd is destroyed which tiggers unsetting
+  // the widget in the RootView so that RootView's destructor doesn't call into
+  // the TooltipManager.
+  scoped_ptr<TooltipManagerWin> tooltip_manager_;
+
   // The root of the View hierarchy attached to this window.
+  // WARNING: see warning in tooltip_manager_ for ordering dependencies with
+  // this and tooltip_manager_.
   scoped_ptr<RootView> root_view_;
 
   // Whether or not we have capture the mouse.
@@ -515,8 +525,6 @@ class WidgetWin : public Widget,
   // If true, the mouse is currently down.
   bool is_mouse_down_;
 
-  scoped_ptr<TooltipManager> tooltip_manager_;
-
   // Are a subclass of WindowWin?
   bool is_window_;
 
-- 
cgit v1.1