diff options
Diffstat (limited to 'ui/views/widget/tooltip_manager_win.cc')
-rw-r--r-- | ui/views/widget/tooltip_manager_win.cc | 391 |
1 files changed, 0 insertions, 391 deletions
diff --git a/ui/views/widget/tooltip_manager_win.cc b/ui/views/widget/tooltip_manager_win.cc deleted file mode 100644 index fedb700..0000000 --- a/ui/views/widget/tooltip_manager_win.cc +++ /dev/null @@ -1,391 +0,0 @@ -// Copyright (c) 2011 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 "ui/views/widget/tooltip_manager_win.h" - -#include <windowsx.h> - -#include <limits> - -#include "base/bind.h" -#include "base/i18n/rtl.h" -#include "base/logging.h" -#include "base/message_loop.h" -#include "base/string_util.h" -#include "ui/base/l10n/l10n_util_win.h" -#include "ui/base/win/hwnd_util.h" -#include "ui/gfx/font.h" -#include "ui/gfx/screen.h" -#include "ui/views/widget/monitor_win.h" -#include "ui/views/widget/widget.h" -#include "views/view.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; - -// static -int TooltipManager::GetTooltipHeight() { - DCHECK_GT(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); - if (!window) - return gfx::Font(); - HFONT hfont = reinterpret_cast<HFONT>(SendMessage(window, WM_GETFONT, 0, 0)); - gfx::Font font = hfont ? gfx::Font(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 -int TooltipManager::GetMaxWidth(int x, int y) { - gfx::Rect monitor_bounds = - gfx::Screen::GetMonitorAreaNearestPoint(gfx::Point(x, y)); - // Allow the tooltip to be almost as wide as the screen. - // Otherwise, we would truncate important text, since we're not word-wrapping - // the text onto multiple lines. - return monitor_bounds.width() == 0 ? 800 : monitor_bounds.width() - 30; -} - -TooltipManagerWin::TooltipManagerWin(Widget* widget) - : widget_(widget), - tooltip_hwnd_(NULL), - last_mouse_pos_(-1, -1), - tooltip_showing_(false), - last_tooltip_view_(NULL), - last_view_out_of_sync_(false), - tooltip_width_(0), - keyboard_tooltip_hwnd_(NULL), - ALLOW_THIS_IN_INITIALIZER_LIST(keyboard_tooltip_factory_(this)) { - DCHECK(widget); - DCHECK(widget->GetNativeView()); -} - -TooltipManagerWin::~TooltipManagerWin() { - if (tooltip_hwnd_) - DestroyWindow(tooltip_hwnd_); - if (keyboard_tooltip_hwnd_) - DestroyWindow(keyboard_tooltip_hwnd_); -} - -bool TooltipManagerWin::Init() { - DCHECK(!tooltip_hwnd_); - // 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); - if (!tooltip_hwnd_) - return false; - - 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<int16>::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; - toolinfo_.lpReserved = NULL; - SetRectEmpty(&toolinfo_.rect); - SendMessage(tooltip_hwnd_, TTM_ADDTOOL, 0, (LPARAM)&toolinfo_); - return true; -} - -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_pos_); -} - -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. - View* root_view = widget_->GetRootView(); - last_tooltip_view_ = - root_view->GetEventHandlerForPoint(last_mouse_pos_); - 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 its tooltip. - gfx::Point view_loc = last_mouse_pos_; - View::ConvertPointToView(widget_->GetRootView(), - last_tooltip_view_, &view_loc); - if (last_tooltip_view_->GetTooltipText(view_loc, &tooltip_text_) && - !tooltip_text_.empty()) { - // View has a valid tip, copy it into TOOLTIPINFO. - clipped_text_ = tooltip_text_; - gfx::Point screen_loc = last_mouse_pos_; - View::ConvertPointToScreen(widget_->GetRootView(), &screen_loc); - TrimTooltipToFit(&clipped_text_, &tooltip_width_, &line_count_, - screen_loc.x(), screen_loc.y()); - // Adjust the clipped tooltip text for locale direction. - base::i18n::AdjustStringForLocaleDirection(&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_pos_; - View::ConvertPointToView(widget_->GetRootView(), - last_tooltip_view_, &view_loc); - if (last_tooltip_view_->GetTooltipTextOrigin(view_loc, &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 = - views::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().GetHeight(); - } - // 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::UpdateTooltip(const gfx::Point& mouse_pos) { - View* root_view = widget_->GetRootView(); - View* view = root_view->GetEventHandlerForPoint(mouse_pos); - 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 = mouse_pos; - View::ConvertPointToView(root_view, last_tooltip_view_, &view_point); - string16 new_tooltip_text; - bool has_tooltip_text = - last_tooltip_view_->GetTooltipText(view_point, &new_tooltip_text); - if (!has_tooltip_text || (new_tooltip_text != tooltip_text_)) { - // The text has changed, hide the popup. - SendMessage(tooltip_hwnd_, TTM_POP, 0, 0); - if (has_tooltip_text && !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) { - gfx::Point mouse_pos(l_param); - - if (u_msg >= WM_NCMOUSEMOVE && u_msg <= WM_NCXBUTTONDBLCLK) { - // NC message coordinates are in screen coordinates. - POINT temp = mouse_pos.ToPOINT(); - ::MapWindowPoints(HWND_DESKTOP, GetParent(), &temp, 1); - mouse_pos.SetPoint(temp.x, temp.y); - } - - if (u_msg != WM_MOUSEMOVE || last_mouse_pos_ != mouse_pos) { - last_mouse_pos_ = mouse_pos; - HideKeyboardTooltip(); - UpdateTooltip(mouse_pos); - } - // 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(); - string16 tooltip_text; - if (!focused_view->GetTooltipText(gfx::Point(), &tooltip_text)) - return; - gfx::Rect focused_bounds = focused_view->bounds(); - gfx::Point screen_point; - focused_view->ConvertPointToScreen(focused_view, &screen_point); - keyboard_tooltip_hwnd_ = CreateWindowEx( - WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(), - TOOLTIPS_CLASS, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL); - if (!keyboard_tooltip_hwnd_) - return; - - SendMessage(keyboard_tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0, - std::numeric_limits<int16>::max()); - int tooltip_width; - int line_count; - TrimTooltipToFit(&tooltip_text, &tooltip_width, &line_count, - screen_point.x(), screen_point.y()); - ReplaceSubstringsAfterOffset(&tooltip_text, 0, L"\n", L"\r\n"); - 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 = - views::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, - base::Bind(&TooltipManagerWin::DestroyKeyboardTooltipWindow, - keyboard_tooltip_factory_.GetWeakPtr(), - 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 |