15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/omnibox/omnibox_popup_view_gtk.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <gtk/gtk.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/rtl.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h" 16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/autocomplete/autocomplete_match.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/autocomplete/autocomplete_result.h" 197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/defaults.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/search_engines/template_url.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/search_engines/template_url_service.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/gtk_theme_service.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/gtk_util.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/omnibox/omnibox_edit_model.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/omnibox/omnibox_popup_model.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/omnibox/omnibox_view.h" 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_source.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/theme_resources.h" 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/gtk/gtk_compat.h" 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/gtk/gtk_hig_constants.h" 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/gtk/gtk_screen_util.h" 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/gtk/gtk_signal_registrar.h" 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/gtk/gtk_windowing.h" 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/color_utils.h" 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/font.h" 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/gtk_util.h" 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/cairo_cached_surface.h" 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image.h" 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/rect.h" 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/skia_utils_gtk.h" 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const GdkColor kBorderColor = GDK_COLOR_RGB(0xc7, 0xca, 0xce); 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const GdkColor kBackgroundColor = GDK_COLOR_RGB(0xff, 0xff, 0xff); 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const GdkColor kSelectedBackgroundColor = GDK_COLOR_RGB(0xdf, 0xe6, 0xf6); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const GdkColor kHoveredBackgroundColor = GDK_COLOR_RGB(0xef, 0xf2, 0xfa); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const GdkColor kContentTextColor = GDK_COLOR_RGB(0x00, 0x00, 0x00); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const GdkColor kURLTextColor = GDK_COLOR_RGB(0x00, 0x88, 0x00); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We have a 1 pixel border around the entire results popup. 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kBorderThickness = 1; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The vertical height of each result. 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kHeightPerResult = 24; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Width of the icons. 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kIconWidth = 17; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We want to vertically center the image in the result space. 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kIconTopPadding = 2; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Space between the left edge (including the border) and the text. 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kIconLeftPadding = 3 + kBorderThickness; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Space between the image and the text. 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kIconRightPadding = 5; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Space between the left edge (including the border) and the text. 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kIconAreaWidth = 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kIconLeftPadding + kIconWidth + kIconRightPadding; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Space between the right edge (including the border) and the text. 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kRightPadding = 3; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// When we have both a content and description string, we don't want the 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// content to push the description off. Limit the content to a percentage of 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the total width. 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const float kContentWidthPercentage = 0.7; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// How much to offset the popup from the bottom of the location bar. 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kVerticalOffset = 3; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The size delta between the font used for the edit and the result rows. Passed 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to gfx::Font::DeriveFont. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kEditFontAdjust = -1; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// UTF-8 Left-to-right embedding. 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* kLRE = "\xe2\x80\xaa"; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return a Rect covering the whole area of |window|. 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Rect GetWindowRect(GdkWindow* window) { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gint width = gdk_window_get_width(window); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gint height = gdk_window_get_height(window); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return gfx::Rect(width, height); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return a Rect for the space for a result line. This excludes the border, 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// but includes the padding. This is the area that is colored for a selection. 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Rect GetRectForLine(size_t line, int width) { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return gfx::Rect(kBorderThickness, 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (line * kHeightPerResult) + kBorderThickness, 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) width - (kBorderThickness * 2), 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kHeightPerResult); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(deanm): Find some better home for this, and make it more efficient. 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t GetUTF8Offset(const string16& text, size_t text_offset) { 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return UTF16ToUTF8(text.substr(0, text_offset)).length(); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Generates the normal URL color, a green color used in unhighlighted URL 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// text. It is a mix of |kURLTextColor| and the current text color. Unlike the 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// selected text color, it is more important to match the qualities of the 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// foreground typeface color instead of taking the background into account. 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GdkColor NormalURLColor(GdkColor foreground) { 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) color_utils::HSL fg_hsl; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) color_utils::SkColorToHSL(gfx::GdkColorToSkColor(foreground), &fg_hsl); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) color_utils::HSL hue_hsl; 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) color_utils::SkColorToHSL(gfx::GdkColorToSkColor(kURLTextColor), &hue_hsl); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only allow colors that have a fair amount of saturation in them (color vs 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // white). This means that our output color will always be fairly green. 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double s = std::max(0.5, fg_hsl.s); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make sure the luminance is at least as bright as the |kURLTextColor| green 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // would be if we were to use that. 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double l; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fg_hsl.l < hue_hsl.l) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l = hue_hsl.l; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l = (fg_hsl.l + hue_hsl.l) / 2; 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) color_utils::HSL output = { hue_hsl.h, s, l }; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return gfx::SkColorToGdkColor(color_utils::HSLToSkColor(output, 255)); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Generates the selected URL color, a green color used on URL text in the 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// currently highlighted entry in the autocomplete popup. It's a mix of 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |kURLTextColor|, the current text color, and the background color (the 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// select highlight). It is more important to contrast with the background 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// saturation than to look exactly like the foreground color. 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GdkColor SelectedURLColor(GdkColor foreground, GdkColor background) { 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) color_utils::HSL fg_hsl; 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) color_utils::SkColorToHSL(gfx::GdkColorToSkColor(foreground), &fg_hsl); 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) color_utils::HSL bg_hsl; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) color_utils::SkColorToHSL(gfx::GdkColorToSkColor(background), &bg_hsl); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) color_utils::HSL hue_hsl; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) color_utils::SkColorToHSL(gfx::GdkColorToSkColor(kURLTextColor), &hue_hsl); 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The saturation of the text should be opposite of the background, clamped 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to 0.2-0.8. We make sure it's greater than 0.2 so there's some color, but 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // less than 0.8 so it's not the oversaturated neon-color. 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double opposite_s = 1 - bg_hsl.s; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double s = std::max(0.2, std::min(0.8, opposite_s)); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The luminance should match the luminance of the foreground text. Again, 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we clamp so as to have at some amount of color (green) in the text. 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double opposite_l = fg_hsl.l; 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double l = std::max(0.1, std::min(0.9, opposite_l)); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) color_utils::HSL output = { hue_hsl.h, s, l }; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return gfx::SkColorToGdkColor(color_utils::HSLToSkColor(output, 255)); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupViewGtk::SetupLayoutForMatch( 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PangoLayout* layout, 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& text, 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AutocompleteMatch::ACMatchClassifications& classifications, 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GdkColor* base_color, 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GdkColor* dim_color, 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GdkColor* url_color, 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& prefix_text) { 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In RTL, mark text with left-to-right embedding mark if there is no strong 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // RTL characters inside it, so the ending punctuation displays correctly 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and the eliding ellipsis displays correctly. We only mark the text with 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // LRE. Wrapping it with LRE and PDF by calling AdjustStringForLocaleDirection 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // or WrapStringWithLTRFormatting will render the elllipsis at the left of the 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // elided pure LTR text. 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool marked_with_lre = false; 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 localized_text = text; 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Pango is really easy to overflow and send into a computational death 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // spiral that can corrupt the screen. Assume that we'll never have more than 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2000 characters, which should be a safe assumption until we all get robot 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // eyes. http://crbug.com/66576 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (localized_text.length() > 2000) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) localized_text = localized_text.substr(0, 2000); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_rtl = base::i18n::IsRTL(); 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_rtl && !base::i18n::StringContainsStrongRTLChars(localized_text)) { 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) localized_text.insert(0, 1, base::i18n::kLeftToRightEmbeddingMark); 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) marked_with_lre = true; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We can have a prefix, or insert additional characters while processing the 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // classifications. We need to take this in to account when we translate the 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // UTF-16 offsets in the classification into text_utf8 byte offsets. 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t additional_offset = prefix_text.length(); // Length in utf-8 bytes. 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string text_utf8 = prefix_text + UTF16ToUTF8(localized_text); 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PangoAttrList* attrs = pango_attr_list_new(); 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(deanm): This is a hack, just to handle coloring prefix_text. 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Hopefully I can clean up the match situation a bit and this will 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // come out cleaner. For now, apply the base color to the whole text 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // so that our prefix will have the base color applied. 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PangoAttribute* base_fg_attr = pango_attr_foreground_new( 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base_color->red, base_color->green, base_color->blue); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_attr_list_insert(attrs, base_fg_attr); // Ownership taken. 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Walk through the classifications, they are linear, in order, and should 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // cover the entire text. We create a bunch of overlapping attributes, 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // extending from the offset to the end of the string. The ones created 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // later will override the previous ones, meaning we will still setup each 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // portion correctly, we just don't need to compute the end offset. 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (ACMatchClassifications::const_iterator i = classifications.begin(); 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i != classifications.end(); ++i) { 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t offset = GetUTF8Offset(localized_text, i->offset) + 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) additional_offset; 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(deanm): All the colors should probably blend based on whether this 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // result is selected or not. This would include the green URLs. Right 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // now the caller is left to blend only the base color. Do we need to 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // handle things like DIM urls? Turns out DIM means something different 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // than you'd think, all of the description text is not DIM, it is a 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // special case that is not very common, but we should figure out and 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // support it. 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GdkColor* color = base_color; 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i->style & ACMatchClassification::URL) { 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) color = url_color; 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Insert a left to right embedding to make sure that URLs are shown LTR. 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_rtl && !marked_with_lre) { 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string lre(kLRE); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) text_utf8.insert(offset, lre); 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) additional_offset += lre.length(); 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i->style & ACMatchClassification::DIM) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) color = dim_color; 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PangoAttribute* fg_attr = pango_attr_foreground_new( 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) color->red, color->green, color->blue); 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fg_attr->start_index = offset; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_attr_list_insert(attrs, fg_attr); // Ownership taken. 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Matched portions are bold, otherwise use the normal weight. 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PangoWeight weight = (i->style & ACMatchClassification::MATCH) ? 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL; 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PangoAttribute* weight_attr = pango_attr_weight_new(weight); 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weight_attr->start_index = offset; 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_attr_list_insert(attrs, weight_attr); // Ownership taken. 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_layout_set_text(layout, text_utf8.data(), text_utf8.length()); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_layout_set_attributes(layout, attrs); // Ref taken. 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_attr_list_unref(attrs); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OmniboxPopupViewGtk::OmniboxPopupViewGtk(const gfx::Font& font, 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OmniboxView* omnibox_view, 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OmniboxEditModel* edit_model, 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* location_bar) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : signal_registrar_(new ui::GtkSignalRegistrar), 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) model_(new OmniboxPopupModel(this, edit_model)), 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) omnibox_view_(omnibox_view), 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) location_bar_(location_bar), 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_(gtk_window_new(GTK_WINDOW_POPUP)), 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) layout_(NULL), 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) theme_service_(GtkThemeService::GetFrom(edit_model->profile())), 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) font_(font.DeriveFont(kEditFontAdjust)), 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ignore_mouse_drag_(false), 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) opened_(false) { 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_set_can_focus(window_, FALSE); 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Don't allow the window to be resized. This also forces the window to 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // shrink down to the size of its child contents. 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_window_set_resizable(GTK_WINDOW(window_), FALSE); 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_set_app_paintable(window_, TRUE); 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Have GTK double buffer around the expose signal. 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_set_double_buffered(window_, TRUE); 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cache the layout so we don't have to create it for every expose. If we 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // were a real widget we should handle changing directions, but we're not 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // doing RTL or anything yet, so it shouldn't be important now. 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) layout_ = gtk_widget_create_pango_layout(window_, NULL); 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We don't want the layout of search results depending on their language. 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_layout_set_auto_dir(layout_, FALSE); 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We always ellipsize when drawing our text runs. 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_layout_set_ellipsize(layout_, PANGO_ELLIPSIZE_END); 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_add_events(window_, GDK_BUTTON_MOTION_MASK | 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GDK_POINTER_MOTION_MASK | 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GDK_BUTTON_PRESS_MASK | 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GDK_BUTTON_RELEASE_MASK); 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) signal_registrar_->Connect(window_, "motion-notify-event", 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(HandleMotionThunk), this); 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) signal_registrar_->Connect(window_, "button-press-event", 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(HandleButtonPressThunk), this); 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) signal_registrar_->Connect(window_, "button-release-event", 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(HandleButtonReleaseThunk), this); 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) signal_registrar_->Connect(window_, "expose-event", 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(HandleExposeThunk), this); 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) registrar_.Add(this, 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::NOTIFICATION_BROWSER_THEME_CHANGED, 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Source<ThemeService>(theme_service_)); 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) theme_service_->InitThemesFor(this); 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(erg): There appears to be a bug somewhere in something which shows 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // itself when we're in NX. Previously, we called 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // gtk_util::ActAsRoundedWindow() to make this popup have rounded 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // corners. This worked on the standard xorg server (both locally and 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // remotely), but broke over NX. My current hypothesis is that it can't 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // handle shaping top-level windows during an expose event, but I'm not sure 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // how else to get accurate shaping information. 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // r25080 (the original patch that added rounded corners here) should 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // eventually be cherry picked once I know what's going 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // on. http://crbug.com/22015. 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OmniboxPopupViewGtk::~OmniboxPopupViewGtk() { 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Stop listening to our signals before we destroy the model. I suspect that 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we can race window destruction, otherwise. 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) signal_registrar_.reset(); 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Explicitly destroy our model here, before we destroy our GTK widgets. 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is because the model destructor can call back into us, and we need 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to make sure everything is still valid when it does. 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) model_.reset(); 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_object_unref(layout_); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_destroy(window_); 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool OmniboxPopupViewGtk::IsOpen() const { 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return opened_; 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupViewGtk::InvalidateLine(size_t line) { 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(deanm): Is it possible to use some constant for the width, instead 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of having to query the width of the window? 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window_)); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GdkRectangle line_rect = GetRectForLine( 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line, GetWindowRect(gdk_window).width()).ToGdkRectangle(); 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gdk_window_invalidate_rect(gdk_window, &line_rect, FALSE); 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupViewGtk::UpdatePopupAppearance() { 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AutocompleteResult& result = model_->result(); 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result.empty()) { 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Hide(); 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Show(result.size()); 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_queue_draw(window_); 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Rect OmniboxPopupViewGtk::GetTargetBounds() { 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!gtk_widget_get_realized(window_)) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return gfx::Rect(); 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect retval = ui::GetWidgetScreenBounds(window_); 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The widget bounds don't update synchronously so may be out of sync with 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // our last size request. 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkRequisition req; 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_size_request(window_, &req); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) retval.set_width(req.width); 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) retval.set_height(req.height); 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return retval; 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupViewGtk::PaintUpdatesNow() { 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Paint our queued invalidations now, synchronously. 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GdkWindow* gdk_window = gtk_widget_get_window(window_); 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gdk_window_process_updates(gdk_window, FALSE); 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupViewGtk::OnDragCanceled() { 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ignore_mouse_drag_ = true; 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupViewGtk::Observe(int type, 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::NotificationSource& source, 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::NotificationDetails& details) { 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(type == chrome::NOTIFICATION_BROWSER_THEME_CHANGED); 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (theme_service_->UsingNativeTheme()) { 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_util::UndoForceFontSize(window_); 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) border_color_ = theme_service_->GetBorderColor(); 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_util::GetTextColors( 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &background_color_, &selected_background_color_, 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &content_text_color_, &selected_content_text_color_); 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hovered_background_color_ = gtk_util::AverageColors( 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) background_color_, selected_background_color_); 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_text_color_ = NormalURLColor(content_text_color_); 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_selected_text_color_ = SelectedURLColor(selected_content_text_color_, 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) selected_background_color_); 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_util::ForceFontSizePixels(window_, font_.GetFontSize()); 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) border_color_ = kBorderColor; 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) background_color_ = kBackgroundColor; 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) selected_background_color_ = kSelectedBackgroundColor; 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hovered_background_color_ = kHoveredBackgroundColor; 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_text_color_ = kContentTextColor; 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) selected_content_text_color_ = kContentTextColor; 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_text_color_ = kURLTextColor; 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_selected_text_color_ = kURLTextColor; 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Calculate dimmed colors. 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_dim_text_color_ = 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_util::AverageColors(content_text_color_, 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) background_color_); 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) selected_content_dim_text_color_ = 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_util::AverageColors(selected_content_text_color_, 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) selected_background_color_); 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set the background color, so we don't need to paint it manually. 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_modify_bg(window_, GTK_STATE_NORMAL, &background_color_); 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupViewGtk::Show(size_t num_results) { 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gint origin_x, origin_y; 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GdkWindow* gdk_window = gtk_widget_get_window(location_bar_); 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gdk_window_get_origin(gdk_window, &origin_x, &origin_y); 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkAllocation allocation; 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_get_allocation(location_bar_, &allocation); 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int horizontal_offset = 1; 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_window_move(GTK_WINDOW(window_), 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) origin_x + allocation.x - kBorderThickness + horizontal_offset, 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) origin_y + allocation.y + allocation.height - kBorderThickness - 1 + 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kVerticalOffset); 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_set_size_request(window_, 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allocation.width + (kBorderThickness * 2) - (horizontal_offset * 2), 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (num_results * kHeightPerResult) + (kBorderThickness * 2)); 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_show(window_); 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StackWindow(); 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) opened_ = true; 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupViewGtk::Hide() { 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_hide(window_); 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) opened_ = false; 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupViewGtk::StackWindow() { 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::NativeView omnibox_view = omnibox_view_->GetNativeView(); 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(GTK_IS_WIDGET(omnibox_view)); 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* toplevel = gtk_widget_get_toplevel(omnibox_view); 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(gtk_widget_is_toplevel(toplevel)); 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::StackPopupWindow(window_, toplevel); 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t OmniboxPopupViewGtk::LineFromY(int y) { 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t line = std::max(y - kBorderThickness, 0) / kHeightPerResult; 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::min(line, model_->result().size() - 1); 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupViewGtk::AcceptLine(size_t line, 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WindowOpenDisposition disposition) { 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // OpenMatch() may close the popup, which will clear the result set and, by 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // extension, |match| and its contents. So copy the relevant match out to 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // make sure it stays alive until the call completes. 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutocompleteMatch match = model_->result().match_at(line); 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) omnibox_view_->OpenMatch(match, disposition, GURL(), line); 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Image OmniboxPopupViewGtk::IconForMatch( 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AutocompleteMatch& match, 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool selected, 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_selected_keyword) { 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Image image = model_->GetIconIfExtensionMatch(match); 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!image.IsEmpty()) 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return image; 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int icon; 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_selected_keyword) 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon = IDR_OMNIBOX_TTS; 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (match.starred) 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon = IDR_OMNIBOX_STAR; 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon = AutocompleteMatch::TypeToIcon(match.type); 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (selected) { 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (icon) { 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case IDR_OMNIBOX_EXTENSION_APP: 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon = IDR_OMNIBOX_EXTENSION_APP_DARK; 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case IDR_OMNIBOX_HTTP: 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon = IDR_OMNIBOX_HTTP_DARK; 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case IDR_OMNIBOX_SEARCH: 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon = IDR_OMNIBOX_SEARCH_DARK; 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case IDR_OMNIBOX_STAR: 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon = IDR_OMNIBOX_STAR_DARK; 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case IDR_OMNIBOX_TTS: 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon = IDR_OMNIBOX_TTS_DARK; 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return theme_service_->GetImageNamed(icon); 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupViewGtk::GetVisibleMatchForInput( 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t index, 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AutocompleteMatch** match, 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* is_selected_keyword) { 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AutocompleteResult& result = model_->result(); 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result.match_at(index).associated_keyword.get() && 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) model_->selected_line() == index && 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) model_->selected_line_state() == OmniboxPopupModel::KEYWORD) { 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *match = result.match_at(index).associated_keyword.get(); 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *is_selected_keyword = true; 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *match = &result.match_at(index); 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *is_selected_keyword = false; 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean OmniboxPopupViewGtk::HandleMotion(GtkWidget* widget, 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GdkEventMotion* event) { 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(deanm): Windows has a bunch of complicated logic here. 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t line = LineFromY(static_cast<int>(event->y)); 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There is both a hovered and selected line, hovered just means your mouse 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is over it, but selected is what's showing in the location edit. 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) model_->SetHoveredLine(line); 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Select the line if the user has the left mouse button down. 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ignore_mouse_drag_ && (event->state & GDK_BUTTON1_MASK)) 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) model_->SetSelectedLine(line, false, false); 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TRUE; 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean OmniboxPopupViewGtk::HandleButtonPress(GtkWidget* widget, 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GdkEventButton* event) { 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ignore_mouse_drag_ = false; 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Very similar to HandleMotion. 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t line = LineFromY(static_cast<int>(event->y)); 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) model_->SetHoveredLine(line); 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event->button == 1) 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) model_->SetSelectedLine(line, false, false); 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TRUE; 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean OmniboxPopupViewGtk::HandleButtonRelease(GtkWidget* widget, 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GdkEventButton* event) { 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ignore_mouse_drag_) { 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // See header comment about this flag. 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ignore_mouse_drag_ = false; 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TRUE; 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t line = LineFromY(static_cast<int>(event->y)); 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (event->button) { 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 1: // Left click. 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AcceptLine(line, CURRENT_TAB); 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 2: // Middle click. 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AcceptLine(line, NEW_BACKGROUND_TAB); 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Don't open the result. 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TRUE; 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean OmniboxPopupViewGtk::HandleExpose(GtkWidget* widget, 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GdkEventExpose* event) { 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ltr = !base::i18n::IsRTL(); 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AutocompleteResult& result = model_->result(); 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect window_rect = GetWindowRect(event->window); 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect damage_rect = gfx::Rect(event->area); 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Handle when our window is super narrow. A bunch of the calculations 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // below would go negative, and really we're not going to fit anything 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // useful in such a small window anyway. Just don't paint anything. 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This means we won't draw the border, but, yeah, whatever. 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(deanm): Make the code more robust and remove this check. 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (window_rect.width() < (kIconAreaWidth * 3)) 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TRUE; 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cairo_t* cr = gdk_cairo_create(gtk_widget_get_window(widget)); 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gdk_cairo_rectangle(cr, &event->area); 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cairo_clip(cr); 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This assert is kinda ugly, but it would be more currently unneeded work 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to support painting a border that isn't 1 pixel thick. There is no point 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in writing that code now, and explode if that day ever comes. 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) COMPILE_ASSERT(kBorderThickness == 1, border_1px_implied); 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Draw the 1px border around the entire window. 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gdk_cairo_set_source_color(cr, &border_color_); 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cairo_rectangle(cr, 0, 0, window_rect.width(), window_rect.height()); 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cairo_stroke(cr); 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_layout_set_height(layout_, kHeightPerResult * PANGO_SCALE); 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < result.size(); ++i) { 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect line_rect = GetRectForLine(i, window_rect.width()); 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only repaint and layout damaged lines. 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!line_rect.Intersects(damage_rect)) 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AutocompleteMatch* match = NULL; 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_selected_keyword = false; 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetVisibleMatchForInput(i, &match, &is_selected_keyword); 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_selected = (model_->selected_line() == i); 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_hovered = (model_->hovered_line() == i); 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_selected || is_hovered) { 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gdk_cairo_set_source_color(cr, is_selected ? &selected_background_color_ : 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &hovered_background_color_); 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This entry is selected or hovered, fill a rect with the color. 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cairo_rectangle(cr, line_rect.x(), line_rect.y(), 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line_rect.width(), line_rect.height()); 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cairo_fill(cr); 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int icon_start_x = ltr ? kIconLeftPadding : 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (line_rect.width() - kIconLeftPadding - kIconWidth); 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Draw the icon for this result. 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_util::DrawFullImage(cr, widget, 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IconForMatch(*match, is_selected, 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_selected_keyword), 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon_start_x, line_rect.y() + kIconTopPadding); 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Draw the results text vertically centered in the results space. 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // First draw the contents / url, but don't let it take up the whole width 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // if there is also a description to be shown. 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool has_description = !match->description.empty(); 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int text_width = window_rect.width() - (kIconAreaWidth + kRightPadding); 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int allocated_content_width = has_description ? 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<int>(text_width * kContentWidthPercentage) : text_width; 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_layout_set_width(layout_, allocated_content_width * PANGO_SCALE); 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: We force to URL to LTR for all text directions. 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetupLayoutForMatch(layout_, match->contents, match->contents_class, 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_selected ? &selected_content_text_color_ : 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &content_text_color_, 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_selected ? &selected_content_dim_text_color_ : 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &content_dim_text_color_, 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_selected ? &url_selected_text_color_ : 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &url_text_color_, 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string()); 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int actual_content_width, actual_content_height; 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_layout_get_size(layout_, 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &actual_content_width, &actual_content_height); 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) actual_content_width /= PANGO_SCALE; 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) actual_content_height /= PANGO_SCALE; 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // DCHECK_LT(actual_content_height, kHeightPerResult); // Font is too tall. 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Center the text within the line. 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int content_y = std::max(line_rect.y(), 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line_rect.y() + ((kHeightPerResult - actual_content_height) / 2)); 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cairo_save(cr); 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cairo_move_to(cr, 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ltr ? kIconAreaWidth : 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (text_width - actual_content_width), 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_y); 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_cairo_show_layout(cr, layout_); 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cairo_restore(cr); 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (has_description) { 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_layout_set_width(layout_, 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (text_width - actual_content_width) * PANGO_SCALE); 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In Windows, a boolean "force_dim" is passed as true for the 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // description. Here, we pass the dim text color for both normal and dim, 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to accomplish the same thing. 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetupLayoutForMatch(layout_, match->description, match->description_class, 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_selected ? &selected_content_dim_text_color_ : 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &content_dim_text_color_, 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_selected ? &selected_content_dim_text_color_ : 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &content_dim_text_color_, 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_selected ? &url_selected_text_color_ : 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &url_text_color_, 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string(" - ")); 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gint actual_description_width; 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_layout_get_size(layout_, &actual_description_width, NULL); 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cairo_save(cr); 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cairo_move_to(cr, ltr ? 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (kIconAreaWidth + actual_content_width) : 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (text_width - actual_content_width - 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (actual_description_width / PANGO_SCALE)), 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_y); 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_cairo_show_layout(cr, layout_); 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cairo_restore(cr); 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (match->associated_keyword.get()) { 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If this entry has an associated keyword, draw the arrow at the extreme 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // other side of the omnibox. 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon_start_x = ltr ? (line_rect.width() - kIconLeftPadding - kIconWidth) : 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kIconLeftPadding; 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Draw the icon for this result. 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_util::DrawFullImage(cr, widget, 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) theme_service_->GetImageNamed( 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_selected ? IDR_OMNIBOX_TTS_DARK : 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_OMNIBOX_TTS), 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon_start_x, line_rect.y() + kIconTopPadding); 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cairo_destroy(cr); 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TRUE; 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 731