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