Home | History | Annotate | Download | only in gtk
      1 // Copyright 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/gtk/location_bar_view_gtk.h"
      6 
      7 #include <algorithm>
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/basictypes.h"
     12 #include "base/bind.h"
     13 #include "base/command_line.h"
     14 #include "base/debug/trace_event.h"
     15 #include "base/i18n/rtl.h"
     16 #include "base/logging.h"
     17 #include "base/message_loop/message_loop.h"
     18 #include "base/prefs/pref_service.h"
     19 #include "base/strings/string_number_conversions.h"
     20 #include "base/strings/string_util.h"
     21 #include "base/strings/utf_string_conversions.h"
     22 #include "chrome/app/chrome_command_ids.h"
     23 #include "chrome/browser/accessibility/accessibility_events.h"
     24 #include "chrome/browser/chrome_notification_types.h"
     25 #include "chrome/browser/command_updater.h"
     26 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
     27 #include "chrome/browser/defaults.h"
     28 #include "chrome/browser/extensions/api/commands/command_service.h"
     29 #include "chrome/browser/extensions/api/omnibox/omnibox_api.h"
     30 #include "chrome/browser/extensions/extension_action.h"
     31 #include "chrome/browser/extensions/extension_service.h"
     32 #include "chrome/browser/extensions/extension_tab_util.h"
     33 #include "chrome/browser/extensions/location_bar_controller.h"
     34 #include "chrome/browser/extensions/script_bubble_controller.h"
     35 #include "chrome/browser/extensions/tab_helper.h"
     36 #include "chrome/browser/favicon/favicon_tab_helper.h"
     37 #include "chrome/browser/profiles/profile.h"
     38 #include "chrome/browser/search_engines/template_url.h"
     39 #include "chrome/browser/search_engines/template_url_service.h"
     40 #include "chrome/browser/search_engines/template_url_service_factory.h"
     41 #include "chrome/browser/themes/theme_properties.h"
     42 #include "chrome/browser/ui/browser.h"
     43 #include "chrome/browser/ui/browser_command_controller.h"
     44 #include "chrome/browser/ui/browser_commands.h"
     45 #include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h"
     46 #include "chrome/browser/ui/browser_instant_controller.h"
     47 #include "chrome/browser/ui/browser_list.h"
     48 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
     49 #include "chrome/browser/ui/content_settings/content_setting_image_model.h"
     50 #include "chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.h"
     51 #include "chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.h"
     52 #include "chrome/browser/ui/gtk/browser_window_gtk.h"
     53 #include "chrome/browser/ui/gtk/content_setting_bubble_gtk.h"
     54 #include "chrome/browser/ui/gtk/extensions/extension_popup_gtk.h"
     55 #include "chrome/browser/ui/gtk/first_run_bubble.h"
     56 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
     57 #include "chrome/browser/ui/gtk/gtk_util.h"
     58 #include "chrome/browser/ui/gtk/nine_box.h"
     59 #include "chrome/browser/ui/gtk/omnibox/omnibox_view_gtk.h"
     60 #include "chrome/browser/ui/gtk/rounded_window.h"
     61 #include "chrome/browser/ui/gtk/script_bubble_gtk.h"
     62 #include "chrome/browser/ui/gtk/view_id_util.h"
     63 #include "chrome/browser/ui/gtk/zoom_bubble_gtk.h"
     64 #include "chrome/browser/ui/omnibox/alternate_nav_url_fetcher.h"
     65 #include "chrome/browser/ui/omnibox/location_bar_util.h"
     66 #include "chrome/browser/ui/omnibox/omnibox_edit_model.h"
     67 #include "chrome/browser/ui/omnibox/omnibox_popup_model.h"
     68 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     69 #include "chrome/browser/ui/webui/extensions/extension_info_ui.h"
     70 #include "chrome/browser/ui/zoom/zoom_controller.h"
     71 #include "chrome/common/badge_util.h"
     72 #include "chrome/common/chrome_switches.h"
     73 #include "chrome/common/extensions/extension.h"
     74 #include "chrome/common/extensions/extension_manifest_constants.h"
     75 #include "chrome/common/extensions/feature_switch.h"
     76 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
     77 #include "chrome/common/pref_names.h"
     78 #include "content/public/browser/navigation_entry.h"
     79 #include "content/public/browser/notification_service.h"
     80 #include "content/public/browser/web_contents.h"
     81 #include "grit/generated_resources.h"
     82 #include "grit/theme_resources.h"
     83 #include "net/base/net_util.h"
     84 #include "ui/base/accelerators/platform_accelerator_gtk.h"
     85 #include "ui/base/dragdrop/gtk_dnd_util.h"
     86 #include "ui/base/gtk/gtk_hig_constants.h"
     87 #include "ui/base/gtk/gtk_signal_registrar.h"
     88 #include "ui/base/l10n/l10n_util.h"
     89 #include "ui/base/resource/resource_bundle.h"
     90 #include "ui/base/window_open_disposition.h"
     91 #include "ui/gfx/canvas_skia_paint.h"
     92 #include "ui/gfx/font.h"
     93 #include "ui/gfx/gtk_util.h"
     94 #include "ui/gfx/image/image.h"
     95 
     96 using content::NavigationEntry;
     97 using content::OpenURLParams;
     98 using content::WebContents;
     99 using extensions::LocationBarController;
    100 using extensions::Extension;
    101 
    102 namespace {
    103 
    104 // We are positioned with a little bit of extra space that we don't use now.
    105 const int kTopMargin = 1;
    106 const int kBottomMargin = 1;
    107 // We draw a border on the top and bottom (but not on left or right).
    108 const int kBorderThickness = 1;
    109 
    110 const int kPopupEdgeThickness = 1;
    111 const int kNormalEdgeThickness = 2;
    112 
    113 // Spacing needed to align the bubble with the left side of the omnibox.
    114 const int kFirstRunBubbleLeftSpacing = 4;
    115 
    116 // The padding around the top, bottom, and sides of the location bar hbox.
    117 // We don't want to edit control's text to be right against the edge,
    118 // as well the tab to search box and other widgets need to have the padding on
    119 // top and bottom to avoid drawing larger than the location bar space.
    120 const int kHboxBorder = 2;
    121 
    122 // Padding between the elements in the bar.
    123 const int kInnerPadding = 2;
    124 const int kScriptBadgeInnerPadding = 9;
    125 
    126 // Colors used to draw the EV certificate rounded bubble.
    127 const GdkColor kEvSecureTextColor = GDK_COLOR_RGB(0x07, 0x95, 0x00);
    128 const GdkColor kEvSecureBackgroundColor = GDK_COLOR_RGB(0xef, 0xfc, 0xef);
    129 const GdkColor kEvSecureBorderColor = GDK_COLOR_RGB(0x90, 0xc3, 0x90);
    130 
    131 // Colors used to draw the Tab to Search rounded bubble.
    132 const GdkColor kKeywordBackgroundColor = GDK_COLOR_RGB(0xf0, 0xf4, 0xfa);
    133 const GdkColor kKeywordBorderColor = GDK_COLOR_RGB(0xcb, 0xde, 0xf7);
    134 
    135 // Use weak gray for showing search and keyword hint text.
    136 const GdkColor kHintTextColor = GDK_COLOR_RGB(0x75, 0x75, 0x75);
    137 
    138 // Size of the rounding of the "Search site for:" box.
    139 const int kCornerSize = 3;
    140 
    141 // Default page tool animation time (open and close). In ms.
    142 const int kPageToolAnimationTime = 150;
    143 
    144 // The time, in ms, that the content setting label is fully displayed, for the
    145 // cases where we animate it into and out of view.
    146 const int kContentSettingImageDisplayTime = 3200;
    147 // The time, in ms, of the animation (open and close).
    148 const int kContentSettingImageAnimationTime = 150;
    149 
    150 // Color of border of content setting area (icon/label).
    151 const GdkColor kContentSettingBorderColor = GDK_COLOR_RGB(0xe9, 0xb9, 0x66);
    152 // Colors for the background gradient.
    153 const GdkColor kContentSettingTopColor = GDK_COLOR_RGB(0xff, 0xf8, 0xd4);
    154 const GdkColor kContentSettingBottomColor = GDK_COLOR_RGB(0xff, 0xe6, 0xaf);
    155 
    156 // Styling for gray button.
    157 const GdkColor kGrayBorderColor = GDK_COLOR_RGB(0xa0, 0xa0, 0xa0);
    158 const GdkColor kTopColorGray = GDK_COLOR_RGB(0xe5, 0xe5, 0xe5);
    159 const GdkColor kBottomColorGray = GDK_COLOR_RGB(0xd0, 0xd0, 0xd0);
    160 
    161 inline int InnerPadding() {
    162   return extensions::FeatureSwitch::script_badges()->IsEnabled() ?
    163       kScriptBadgeInnerPadding : kInnerPadding;
    164 }
    165 
    166 // If widget is visible, increment the int pointed to by count.
    167 // Suitible for use with gtk_container_foreach.
    168 void CountVisibleWidgets(GtkWidget* widget, gpointer count) {
    169   if (gtk_widget_get_visible(widget))
    170     *static_cast<int*>(count) += 1;
    171 }
    172 
    173 class ContentSettingImageViewGtk : public LocationBarViewGtk::PageToolViewGtk,
    174                                    public BubbleDelegateGtk {
    175  public:
    176   ContentSettingImageViewGtk(ContentSettingsType content_type,
    177                              const LocationBarViewGtk* parent);
    178   virtual ~ContentSettingImageViewGtk();
    179 
    180   // PageToolViewGtk
    181   virtual void Update(WebContents* web_contents) OVERRIDE;
    182 
    183   // ui::AnimationDelegate
    184   virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE;
    185 
    186  private:
    187   // PageToolViewGtk
    188   virtual GdkColor button_border_color() const OVERRIDE;
    189   virtual GdkColor gradient_top_color() const OVERRIDE;
    190   virtual GdkColor gradient_bottom_color() const OVERRIDE;
    191   virtual void OnClick(GtkWidget* sender) OVERRIDE;
    192 
    193   // BubbleDelegateGtk
    194   virtual void BubbleClosing(BubbleGtk* bubble,
    195                              bool closed_by_escape) OVERRIDE;
    196 
    197   scoped_ptr<ContentSettingImageModel> content_setting_image_model_;
    198 
    199   // The currently shown bubble if any.
    200   ContentSettingBubbleGtk* content_setting_bubble_;
    201 
    202   DISALLOW_COPY_AND_ASSIGN(ContentSettingImageViewGtk);
    203 };
    204 
    205 ContentSettingImageViewGtk::ContentSettingImageViewGtk(
    206     ContentSettingsType content_type,
    207     const LocationBarViewGtk* parent)
    208     : PageToolViewGtk(parent),
    209       content_setting_image_model_(
    210           ContentSettingImageModel::CreateContentSettingImageModel(
    211               content_type)),
    212       content_setting_bubble_(NULL) {
    213   animation_.SetSlideDuration(kContentSettingImageAnimationTime);
    214 }
    215 
    216 ContentSettingImageViewGtk::~ContentSettingImageViewGtk() {
    217   if (content_setting_bubble_)
    218     content_setting_bubble_->Close();
    219 }
    220 
    221 void ContentSettingImageViewGtk::Update(WebContents* web_contents) {
    222   if (web_contents)
    223     content_setting_image_model_->UpdateFromWebContents(web_contents);
    224 
    225   if (!content_setting_image_model_->is_visible()) {
    226     gtk_widget_hide(widget());
    227     return;
    228   }
    229 
    230   gtk_image_set_from_pixbuf(GTK_IMAGE(image_.get()),
    231       GtkThemeService::GetFrom(parent_->browser()->profile())->GetImageNamed(
    232           content_setting_image_model_->get_icon()).ToGdkPixbuf());
    233 
    234   gtk_widget_set_tooltip_text(widget(),
    235       content_setting_image_model_->get_tooltip().c_str());
    236   gtk_widget_show_all(widget());
    237 
    238   if (!web_contents)
    239     return;
    240 
    241   TabSpecificContentSettings* content_settings =
    242       TabSpecificContentSettings::FromWebContents(web_contents);
    243   if (!content_settings || content_settings->IsBlockageIndicated(
    244       content_setting_image_model_->get_content_settings_type()))
    245     return;
    246 
    247   // The content blockage was not yet indicated to the user. Start indication
    248   // animation and clear "not yet shown" flag.
    249   content_settings->SetBlockageHasBeenIndicated(
    250       content_setting_image_model_->get_content_settings_type());
    251 
    252   int label_string_id =
    253       content_setting_image_model_->explanatory_string_id();
    254   // If there's no string for the content type, we don't animate.
    255   if (!label_string_id)
    256     return;
    257 
    258   gtk_label_set_text(GTK_LABEL(label_.get()),
    259       l10n_util::GetStringUTF8(label_string_id).c_str());
    260   StartAnimating();
    261 }
    262 
    263 void ContentSettingImageViewGtk::AnimationEnded(
    264     const ui::Animation* animation) {
    265   if (animation_.IsShowing()) {
    266     base::MessageLoop::current()->PostDelayedTask(
    267         FROM_HERE,
    268         base::Bind(&ContentSettingImageViewGtk::CloseAnimation,
    269                    weak_factory_.GetWeakPtr()),
    270         base::TimeDelta::FromMilliseconds(kContentSettingImageDisplayTime));
    271   } else {
    272     gtk_widget_hide(label_.get());
    273     gtk_util::StopActingAsRoundedWindow(event_box_.get());
    274     gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box_.get()), FALSE);
    275   }
    276 }
    277 
    278 GdkColor ContentSettingImageViewGtk::
    279     button_border_color() const {
    280   return kContentSettingBorderColor;
    281 }
    282 
    283 GdkColor ContentSettingImageViewGtk::
    284     gradient_top_color() const {
    285   return kContentSettingTopColor;
    286 }
    287 
    288 GdkColor ContentSettingImageViewGtk::
    289     gradient_bottom_color() const {
    290   return kContentSettingBottomColor;
    291 }
    292 
    293 void ContentSettingImageViewGtk::OnClick(
    294     GtkWidget* sender) {
    295   WebContents* web_contents = parent_->GetWebContents();
    296   if (!web_contents)
    297     return;
    298   Profile* profile = parent_->browser()->profile();
    299   content_setting_bubble_ = new ContentSettingBubbleGtk(
    300       sender, this,
    301       ContentSettingBubbleModel::CreateContentSettingBubbleModel(
    302           parent_->browser()->content_setting_bubble_model_delegate(),
    303           web_contents,
    304           profile,
    305           content_setting_image_model_->get_content_settings_type()),
    306       profile, web_contents);
    307   return;
    308 }
    309 
    310 void ContentSettingImageViewGtk::BubbleClosing(
    311     BubbleGtk* bubble,
    312     bool closed_by_escape) {
    313   content_setting_bubble_ = NULL;
    314 }
    315 
    316 gfx::Rect AllocationToRect(const GtkAllocation& allocation) {
    317   return gfx::Rect(allocation.x, allocation.y,
    318                    allocation.width, allocation.height);
    319 }
    320 
    321 }  // namespace
    322 
    323 ////////////////////////////////////////////////////////////////////////////////
    324 // LocationBarViewGtk
    325 
    326 // static
    327 const GdkColor LocationBarViewGtk::kBackgroundColor =
    328     GDK_COLOR_RGB(255, 255, 255);
    329 
    330 LocationBarViewGtk::LocationBarViewGtk(Browser* browser)
    331     : zoom_image_(NULL),
    332       script_bubble_button_image_(NULL),
    333       num_running_scripts_(0u),
    334       star_image_(NULL),
    335       starred_(false),
    336       star_sized_(false),
    337       site_type_alignment_(NULL),
    338       site_type_event_box_(NULL),
    339       location_icon_image_(NULL),
    340       drag_icon_(NULL),
    341       enable_location_drag_(false),
    342       security_info_label_(NULL),
    343       tab_to_search_alignment_(NULL),
    344       tab_to_search_box_(NULL),
    345       tab_to_search_full_label_(NULL),
    346       tab_to_search_partial_label_(NULL),
    347       tab_to_search_hint_(NULL),
    348       tab_to_search_hint_leading_label_(NULL),
    349       tab_to_search_hint_icon_(NULL),
    350       tab_to_search_hint_trailing_label_(NULL),
    351       command_updater_(browser->command_controller()->command_updater()),
    352       toolbar_model_(browser->toolbar_model()),
    353       browser_(browser),
    354       disposition_(CURRENT_TAB),
    355       transition_(content::PageTransitionFromInt(
    356           content::PAGE_TRANSITION_TYPED |
    357           content::PAGE_TRANSITION_FROM_ADDRESS_BAR)),
    358       weak_ptr_factory_(this),
    359       popup_window_mode_(false),
    360       theme_service_(NULL),
    361       hbox_width_(0),
    362       entry_box_width_(0),
    363       show_selected_keyword_(false),
    364       show_keyword_hint_(false) {
    365 }
    366 
    367 LocationBarViewGtk::~LocationBarViewGtk() {
    368   // All of our widgets should be children of / owned by the alignment.
    369   zoom_.Destroy();
    370   script_bubble_button_.Destroy();
    371   star_.Destroy();
    372   hbox_.Destroy();
    373   content_setting_hbox_.Destroy();
    374   page_action_hbox_.Destroy();
    375 }
    376 
    377 void LocationBarViewGtk::Init(bool popup_window_mode) {
    378   popup_window_mode_ = popup_window_mode;
    379 
    380   Profile* profile = browser_->profile();
    381   theme_service_ = GtkThemeService::GetFrom(profile);
    382 
    383   // Create the widget first, so we can pass it to the OmniboxViewGtk.
    384   hbox_.Own(gtk_hbox_new(FALSE, InnerPadding()));
    385   gtk_container_set_border_width(GTK_CONTAINER(hbox_.get()), kHboxBorder);
    386   // We will paint for the alignment, to paint the background and border.
    387   gtk_widget_set_app_paintable(hbox_.get(), TRUE);
    388   // Redraw the whole location bar when it changes size (e.g., when toggling
    389   // the home button on/off.
    390   gtk_widget_set_redraw_on_allocate(hbox_.get(), TRUE);
    391 
    392   // Now initialize the OmniboxViewGtk.
    393   location_entry_.reset(new OmniboxViewGtk(this, toolbar_model_, browser_,
    394       browser_->profile(), command_updater_, popup_window_mode_, hbox_.get()));
    395   location_entry_->Init();
    396 
    397   g_signal_connect(hbox_.get(), "expose-event",
    398                    G_CALLBACK(&HandleExposeThunk), this);
    399 
    400   BuildSiteTypeArea();
    401 
    402   // Put |tab_to_search_box_|, |location_entry_|, and |tab_to_search_hint_| into
    403   // a sub hbox, so that we can make this part horizontally shrinkable without
    404   // affecting other elements in the location bar.
    405   entry_box_ = gtk_hbox_new(FALSE, InnerPadding());
    406   gtk_widget_show(entry_box_);
    407   gtk_widget_set_size_request(entry_box_, 0, -1);
    408   gtk_box_pack_start(GTK_BOX(hbox_.get()), entry_box_, TRUE, TRUE, 0);
    409 
    410   // We need to adjust the visibility of the search hint widgets according to
    411   // the horizontal space in the |entry_box_|.
    412   g_signal_connect(entry_box_, "size-allocate",
    413                    G_CALLBACK(&OnEntryBoxSizeAllocateThunk), this);
    414 
    415   // Tab to search (the keyword box on the left hand side).
    416   tab_to_search_full_label_ =
    417       theme_service_->BuildLabel(std::string(), ui::kGdkBlack);
    418   tab_to_search_partial_label_ =
    419       theme_service_->BuildLabel(std::string(), ui::kGdkBlack);
    420   GtkWidget* tab_to_search_label_hbox = gtk_hbox_new(FALSE, 0);
    421   gtk_box_pack_start(GTK_BOX(tab_to_search_label_hbox),
    422                      tab_to_search_full_label_, FALSE, FALSE, 0);
    423   gtk_box_pack_start(GTK_BOX(tab_to_search_label_hbox),
    424                      tab_to_search_partial_label_, FALSE, FALSE, 0);
    425   GtkWidget* tab_to_search_hbox = gtk_hbox_new(FALSE, 0);
    426   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
    427   tab_to_search_magnifier_ = gtk_image_new_from_pixbuf(
    428       rb.GetNativeImageNamed(IDR_KEYWORD_SEARCH_MAGNIFIER).ToGdkPixbuf());
    429   gtk_box_pack_start(GTK_BOX(tab_to_search_hbox), tab_to_search_magnifier_,
    430                      FALSE, FALSE, 0);
    431   gtk_util::CenterWidgetInHBox(tab_to_search_hbox, tab_to_search_label_hbox,
    432                                false, 0);
    433 
    434   // This creates a box around the keyword text with a border, background color,
    435   // and padding around the text.
    436   tab_to_search_box_ = gtk_util::CreateGtkBorderBin(
    437       tab_to_search_hbox, NULL, 1, 1, 1, 3);
    438   gtk_widget_set_name(tab_to_search_box_, "chrome-tab-to-search-box");
    439   gtk_util::ActAsRoundedWindow(tab_to_search_box_, kKeywordBorderColor,
    440                                kCornerSize,
    441                                gtk_util::ROUNDED_ALL, gtk_util::BORDER_ALL);
    442 
    443   // Put the event box in an alignment to get the padding correct.
    444   tab_to_search_alignment_ = gtk_alignment_new(0, 0, 1, 1);
    445   gtk_container_add(GTK_CONTAINER(tab_to_search_alignment_),
    446                     tab_to_search_box_);
    447   gtk_box_pack_start(GTK_BOX(entry_box_), tab_to_search_alignment_,
    448                      FALSE, FALSE, 0);
    449 
    450   // Show all children widgets of |tab_to_search_box_| initially, except
    451   // |tab_to_search_partial_label_|.
    452   gtk_widget_show_all(tab_to_search_box_);
    453   gtk_widget_hide(tab_to_search_partial_label_);
    454 
    455   location_entry_alignment_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
    456   gtk_container_add(GTK_CONTAINER(location_entry_alignment_),
    457                     location_entry_->GetNativeView());
    458   gtk_box_pack_start(GTK_BOX(entry_box_), location_entry_alignment_,
    459                      TRUE, TRUE, 0);
    460 
    461   // Tab to search notification (the hint on the right hand side).
    462   tab_to_search_hint_ = gtk_hbox_new(FALSE, 0);
    463   gtk_widget_set_name(tab_to_search_hint_, "chrome-tab-to-search-hint");
    464   tab_to_search_hint_leading_label_ =
    465       theme_service_->BuildLabel(std::string(), kHintTextColor);
    466   gtk_widget_set_sensitive(tab_to_search_hint_leading_label_, FALSE);
    467   tab_to_search_hint_icon_ = gtk_image_new_from_pixbuf(
    468       rb.GetNativeImageNamed(IDR_OMNIBOX_KEYWORD_HINT_TAB).ToGdkPixbuf());
    469   tab_to_search_hint_trailing_label_ =
    470       theme_service_->BuildLabel(std::string(), kHintTextColor);
    471   gtk_widget_set_sensitive(tab_to_search_hint_trailing_label_, FALSE);
    472   gtk_box_pack_start(GTK_BOX(tab_to_search_hint_),
    473                      tab_to_search_hint_leading_label_,
    474                      FALSE, FALSE, 0);
    475   gtk_box_pack_start(GTK_BOX(tab_to_search_hint_),
    476                      tab_to_search_hint_icon_,
    477                      FALSE, FALSE, 0);
    478   gtk_box_pack_start(GTK_BOX(tab_to_search_hint_),
    479                      tab_to_search_hint_trailing_label_,
    480                      FALSE, FALSE, 0);
    481   // Show all children widgets of |tab_to_search_hint_| initially.
    482   gtk_widget_show_all(tab_to_search_hint_);
    483   gtk_widget_hide(tab_to_search_hint_);
    484   // tab_to_search_hint_ gets hidden initially in OnChanged.  Hiding it here
    485   // doesn't work, someone is probably calling show_all on our parent box.
    486   gtk_box_pack_end(GTK_BOX(entry_box_), tab_to_search_hint_, FALSE, FALSE, 0);
    487 
    488   if (browser_defaults::bookmarks_enabled && !ShouldOnlyShowLocation()) {
    489     // Hide the star icon in popups, app windows, etc.
    490     CreateStarButton();
    491     gtk_box_pack_end(GTK_BOX(hbox_.get()), star_.get(), FALSE, FALSE, 0);
    492   }
    493 
    494   CreateScriptBubbleButton();
    495   gtk_box_pack_end(GTK_BOX(hbox_.get()), script_bubble_button_.get(), FALSE,
    496                    FALSE, 0);
    497 
    498   CreateZoomButton();
    499   gtk_box_pack_end(GTK_BOX(hbox_.get()), zoom_.get(), FALSE, FALSE, 0);
    500 
    501   content_setting_hbox_.Own(gtk_hbox_new(FALSE, InnerPadding() + 1));
    502   gtk_widget_set_name(content_setting_hbox_.get(),
    503                       "chrome-content-setting-hbox");
    504   gtk_box_pack_end(GTK_BOX(hbox_.get()), content_setting_hbox_.get(),
    505                    FALSE, FALSE, 1);
    506 
    507   for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
    508     ContentSettingImageViewGtk* content_setting_view =
    509         new ContentSettingImageViewGtk(
    510             static_cast<ContentSettingsType>(i), this);
    511     content_setting_views_.push_back(content_setting_view);
    512     gtk_box_pack_end(GTK_BOX(content_setting_hbox_.get()),
    513                      content_setting_view->widget(), FALSE, FALSE, 0);
    514   }
    515 
    516   page_action_hbox_.Own(gtk_hbox_new(FALSE, InnerPadding()));
    517   gtk_widget_set_name(page_action_hbox_.get(),
    518                       "chrome-page-action-hbox");
    519   gtk_box_pack_end(GTK_BOX(hbox_.get()), page_action_hbox_.get(),
    520                    FALSE, FALSE, 0);
    521 
    522   // Now that we've created the widget hierarchy, connect to the main |hbox_|'s
    523   // size-allocate so we can do proper resizing and eliding on
    524   // |security_info_label_|.
    525   g_signal_connect(hbox_.get(), "size-allocate",
    526                    G_CALLBACK(&OnHboxSizeAllocateThunk), this);
    527 
    528   registrar_.Add(this,
    529                  chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
    530                  content::Source<ThemeService>(theme_service_));
    531   registrar_.Add(this,
    532                  chrome::NOTIFICATION_EXTENSION_LOCATION_BAR_UPDATED,
    533                  content::Source<Profile>(browser()->profile()));
    534   edit_bookmarks_enabled_.Init(prefs::kEditBookmarksEnabled,
    535                                profile->GetPrefs(),
    536                                base::Bind(&LocationBarViewGtk::UpdateStarIcon,
    537                                           base::Unretained(this)));
    538 
    539   theme_service_->InitThemesFor(this);
    540 }
    541 
    542 void LocationBarViewGtk::BuildSiteTypeArea() {
    543   location_icon_image_ = gtk_image_new();
    544   gtk_widget_set_name(location_icon_image_, "chrome-location-icon");
    545 
    546   GtkWidget* icon_alignment = gtk_alignment_new(0, 0, 1, 1);
    547   gtk_alignment_set_padding(GTK_ALIGNMENT(icon_alignment), 0, 0, 2, 0);
    548   gtk_container_add(GTK_CONTAINER(icon_alignment), location_icon_image_);
    549   gtk_widget_show_all(icon_alignment);
    550 
    551   security_info_label_ = gtk_label_new(NULL);
    552   gtk_label_set_ellipsize(GTK_LABEL(security_info_label_),
    553                           PANGO_ELLIPSIZE_MIDDLE);
    554   gtk_widget_modify_fg(GTK_WIDGET(security_info_label_), GTK_STATE_NORMAL,
    555                        &kEvSecureTextColor);
    556   gtk_widget_set_name(security_info_label_,
    557                       "chrome-location-bar-security-info-label");
    558 
    559   GtkWidget* site_type_hbox = gtk_hbox_new(FALSE, 1);
    560   gtk_box_pack_start(GTK_BOX(site_type_hbox), icon_alignment,
    561                      FALSE, FALSE, 0);
    562   gtk_box_pack_start(GTK_BOX(site_type_hbox), security_info_label_,
    563                      FALSE, FALSE, 2);
    564 
    565   site_type_event_box_ = gtk_event_box_new();
    566   gtk_widget_modify_bg(site_type_event_box_, GTK_STATE_NORMAL,
    567                        &kEvSecureBackgroundColor);
    568   g_signal_connect(site_type_event_box_, "drag-data-get",
    569                    G_CALLBACK(&OnIconDragDataThunk), this);
    570   g_signal_connect(site_type_event_box_, "drag-begin",
    571                    G_CALLBACK(&OnIconDragBeginThunk), this);
    572   g_signal_connect(site_type_event_box_, "drag-end",
    573                    G_CALLBACK(&OnIconDragEndThunk), this);
    574 
    575   // Make the event box not visible so it does not paint a background.
    576   gtk_event_box_set_visible_window(GTK_EVENT_BOX(site_type_event_box_),
    577                                    FALSE);
    578   gtk_widget_set_name(site_type_event_box_,
    579                       "chrome-location-icon-eventbox");
    580   gtk_container_add(GTK_CONTAINER(site_type_event_box_),
    581                     site_type_hbox);
    582 
    583   // Put the event box in an alignment to get the padding correct.
    584   site_type_alignment_ = gtk_alignment_new(0, 0, 1, 1);
    585   gtk_container_add(GTK_CONTAINER(site_type_alignment_),
    586                     site_type_event_box_);
    587   gtk_box_pack_start(GTK_BOX(hbox_.get()), site_type_alignment_,
    588                      FALSE, FALSE, 0);
    589 
    590   gtk_widget_set_tooltip_text(location_icon_image_,
    591       l10n_util::GetStringUTF8(IDS_TOOLTIP_LOCATION_ICON).c_str());
    592 
    593   g_signal_connect(site_type_event_box_, "button-release-event",
    594                    G_CALLBACK(&OnIconReleasedThunk), this);
    595 }
    596 
    597 void LocationBarViewGtk::SetSiteTypeDragSource() {
    598   bool enable = !GetLocationEntry()->IsEditingOrEmpty();
    599   if (enable_location_drag_ == enable)
    600     return;
    601   enable_location_drag_ = enable;
    602 
    603   if (!enable) {
    604     gtk_drag_source_unset(site_type_event_box_);
    605     return;
    606   }
    607 
    608   gtk_drag_source_set(site_type_event_box_, GDK_BUTTON1_MASK,
    609                       NULL, 0, GDK_ACTION_COPY);
    610   ui::SetSourceTargetListFromCodeMask(site_type_event_box_,
    611                                       ui::TEXT_PLAIN |
    612                                       ui::TEXT_URI_LIST |
    613                                       ui::CHROME_NAMED_URL);
    614 }
    615 
    616 WebContents* LocationBarViewGtk::GetWebContents() const {
    617   return browser_->tab_strip_model()->GetActiveWebContents();
    618 }
    619 
    620 void LocationBarViewGtk::SetPreviewEnabledPageAction(
    621     ExtensionAction* page_action,
    622     bool preview_enabled) {
    623   DCHECK(page_action);
    624   for (ScopedVector<PageActionViewGtk>::iterator iter =
    625        page_action_views_.begin(); iter != page_action_views_.end();
    626        ++iter) {
    627     if ((*iter)->page_action() == page_action) {
    628       (*iter)->set_preview_enabled(preview_enabled);
    629       UpdatePageActions();
    630       return;
    631     }
    632   }
    633 }
    634 
    635 GtkWidget* LocationBarViewGtk::GetPageActionWidget(
    636     ExtensionAction* page_action) {
    637   DCHECK(page_action);
    638   for (ScopedVector<PageActionViewGtk>::iterator iter =
    639            page_action_views_.begin();
    640        iter != page_action_views_.end();
    641        ++iter) {
    642     if ((*iter)->page_action() == page_action)
    643       return (*iter)->widget();
    644   }
    645   return NULL;
    646 }
    647 
    648 void LocationBarViewGtk::Update(const WebContents* contents) {
    649   UpdateZoomIcon();
    650   UpdateScriptBubbleIcon();
    651   UpdateStarIcon();
    652   UpdateSiteTypeArea();
    653   UpdateContentSettingsIcons();
    654   UpdatePageActions();
    655   location_entry_->Update(contents);
    656   // The security level (background color) could have changed, etc.
    657   if (theme_service_->UsingNativeTheme()) {
    658     // In GTK mode, we need our parent to redraw, as it draws the text entry
    659     // border.
    660     gtk_widget_queue_draw(gtk_widget_get_parent(widget()));
    661   } else {
    662     gtk_widget_queue_draw(widget());
    663   }
    664   ZoomBubbleGtk::CloseBubble();
    665 }
    666 
    667 void LocationBarViewGtk::OnAutocompleteAccept(const GURL& url,
    668     WindowOpenDisposition disposition,
    669     content::PageTransition transition,
    670     const GURL& alternate_nav_url) {
    671   if (url.is_valid()) {
    672     location_input_ = UTF8ToUTF16(url.spec());
    673     disposition_ = disposition;
    674     transition_ = content::PageTransitionFromInt(
    675         transition | content::PAGE_TRANSITION_FROM_ADDRESS_BAR);
    676 
    677     if (command_updater_) {
    678       if (!alternate_nav_url.is_valid()) {
    679         command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
    680       } else {
    681         AlternateNavURLFetcher* fetcher =
    682             new AlternateNavURLFetcher(alternate_nav_url);
    683         // The AlternateNavURLFetcher will listen for the pending navigation
    684         // notification that will be issued as a result of the "open URL." It
    685         // will automatically install itself into that navigation controller.
    686         command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
    687         if (fetcher->state() == AlternateNavURLFetcher::NOT_STARTED) {
    688           // I'm not sure this should be reachable, but I'm not also sure enough
    689           // that it shouldn't to stick in a NOTREACHED().  In any case, this is
    690           // harmless.
    691           delete fetcher;
    692         } else {
    693           // The navigation controller will delete the fetcher.
    694         }
    695       }
    696     }
    697   }
    698 }
    699 
    700 void LocationBarViewGtk::OnChanged() {
    701   UpdateSiteTypeArea();
    702 
    703   const string16 keyword(location_entry_->model()->keyword());
    704   const bool is_keyword_hint = location_entry_->model()->is_keyword_hint();
    705   show_selected_keyword_ = !keyword.empty() && !is_keyword_hint;
    706   show_keyword_hint_ = !keyword.empty() && is_keyword_hint;
    707 
    708   if (show_selected_keyword_)
    709     SetKeywordLabel(keyword);
    710 
    711   if (show_keyword_hint_)
    712     SetKeywordHintLabel(keyword);
    713 
    714   AdjustChildrenVisibility();
    715 }
    716 
    717 void LocationBarViewGtk::OnSelectionBoundsChanged() {
    718   NOTIMPLEMENTED();
    719 }
    720 
    721 GtkWidget* LocationBarViewGtk::CreateIconButton(
    722     GtkWidget** image,
    723     int image_id,
    724     ViewID debug_id,
    725     int tooltip_id,
    726     gboolean (click_callback)(GtkWidget*, GdkEventButton*, gpointer)) {
    727   *image = image_id ?
    728       gtk_image_new_from_pixbuf(
    729           theme_service_->GetImageNamed(image_id).ToGdkPixbuf()) :
    730       gtk_image_new();
    731 
    732   GtkWidget* alignment = gtk_alignment_new(0, 0, 1, 1);
    733   gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0,
    734                             0, InnerPadding());
    735   gtk_container_add(GTK_CONTAINER(alignment), *image);
    736 
    737   GtkWidget* result = gtk_event_box_new();
    738   gtk_event_box_set_visible_window(GTK_EVENT_BOX(result), FALSE);
    739   gtk_container_add(GTK_CONTAINER(result), alignment);
    740   gtk_widget_show_all(result);
    741 
    742   if (debug_id != VIEW_ID_NONE)
    743     ViewIDUtil::SetID(result, debug_id);
    744 
    745   if (tooltip_id) {
    746     gtk_widget_set_tooltip_text(result,
    747                                 l10n_util::GetStringUTF8(tooltip_id).c_str());
    748   }
    749 
    750   g_signal_connect(result, "button-press-event",
    751                      G_CALLBACK(click_callback), this);
    752 
    753   return result;
    754 }
    755 
    756 void LocationBarViewGtk::CreateZoomButton() {
    757   zoom_.Own(CreateIconButton(&zoom_image_,
    758                              0,
    759                              VIEW_ID_ZOOM_BUTTON,
    760                              0,
    761                              OnZoomButtonPressThunk));
    762 }
    763 
    764 void LocationBarViewGtk::CreateScriptBubbleButton() {
    765   script_bubble_button_.Own(CreateIconButton(&script_bubble_button_image_,
    766                                              0,
    767                                              VIEW_ID_SCRIPT_BUBBLE,
    768                                              IDS_TOOLTIP_SCRIPT_BUBBLE,
    769                                              OnScriptBubbleButtonPressThunk));
    770   gtk_image_set_from_pixbuf(
    771       GTK_IMAGE(script_bubble_button_image_),
    772       theme_service_->GetImageNamed(
    773           IDR_EXTENSIONS_SCRIPT_BUBBLE).ToGdkPixbuf());
    774   g_signal_connect_after(script_bubble_button_image_, "expose-event",
    775                          G_CALLBACK(&OnScriptBubbleButtonExposeThunk), this);
    776 }
    777 
    778 void LocationBarViewGtk::CreateStarButton() {
    779   star_.Own(CreateIconButton(&star_image_,
    780                              0,
    781                              VIEW_ID_STAR_BUTTON,
    782                              IDS_TOOLTIP_STAR,
    783                              OnStarButtonPressThunk));
    784   // We need to track when the star button is resized to show any bubble
    785   // attached to it at this time.
    786   g_signal_connect(star_image_, "size-allocate",
    787                    G_CALLBACK(&OnStarButtonSizeAllocateThunk), this);
    788 }
    789 
    790 void LocationBarViewGtk::OnInputInProgress(bool in_progress) {
    791   // This is identical to the Windows code, except that we don't proxy the call
    792   // back through the Toolbar, and just access the model here.
    793   // The edit should make sure we're only notified when something changes.
    794   DCHECK(toolbar_model_->GetInputInProgress() != in_progress);
    795 
    796   toolbar_model_->SetInputInProgress(in_progress);
    797   Update(NULL);
    798 }
    799 
    800 void LocationBarViewGtk::OnKillFocus() {
    801 }
    802 
    803 void LocationBarViewGtk::OnSetFocus() {
    804   Profile* profile = browser_->profile();
    805   AccessibilityTextBoxInfo info(
    806       profile,
    807       l10n_util::GetStringUTF8(IDS_ACCNAME_LOCATION),
    808       std::string(),
    809       false);
    810   content::NotificationService::current()->Notify(
    811       chrome::NOTIFICATION_ACCESSIBILITY_CONTROL_FOCUSED,
    812       content::Source<Profile>(profile),
    813       content::Details<AccessibilityTextBoxInfo>(&info));
    814 
    815   // Update the keyword and search hint states.
    816   OnChanged();
    817 }
    818 
    819 gfx::Image LocationBarViewGtk::GetFavicon() const {
    820   return FaviconTabHelper::FromWebContents(GetWebContents())->GetFavicon();
    821 }
    822 
    823 string16 LocationBarViewGtk::GetTitle() const {
    824   return GetWebContents()->GetTitle();
    825 }
    826 
    827 InstantController* LocationBarViewGtk::GetInstant() {
    828   return browser_->instant_controller() ?
    829       browser_->instant_controller()->instant() : NULL;
    830 }
    831 
    832 void LocationBarViewGtk::ShowFirstRunBubble() {
    833   // We need the browser window to be shown before we can show the bubble, but
    834   // we get called before that's happened.
    835   base::MessageLoop::current()->PostTask(
    836       FROM_HERE,
    837       base::Bind(&LocationBarViewGtk::ShowFirstRunBubbleInternal,
    838                  weak_ptr_factory_.GetWeakPtr()));
    839 }
    840 
    841 string16 LocationBarViewGtk::GetInputString() const {
    842   return location_input_;
    843 }
    844 
    845 WindowOpenDisposition LocationBarViewGtk::GetWindowOpenDisposition() const {
    846   return disposition_;
    847 }
    848 
    849 content::PageTransition LocationBarViewGtk::GetPageTransition() const {
    850   return transition_;
    851 }
    852 
    853 void LocationBarViewGtk::AcceptInput() {
    854   location_entry_->model()->AcceptInput(CURRENT_TAB, false);
    855 }
    856 
    857 void LocationBarViewGtk::FocusLocation(bool select_all) {
    858   location_entry_->SetFocus();
    859   if (select_all)
    860     location_entry_->SelectAll(true);
    861 }
    862 
    863 void LocationBarViewGtk::FocusSearch() {
    864   location_entry_->SetFocus();
    865   location_entry_->SetForcedQuery();
    866 }
    867 
    868 void LocationBarViewGtk::UpdateContentSettingsIcons() {
    869   bool any_visible = false;
    870   for (ScopedVector<PageToolViewGtk>::iterator i(
    871            content_setting_views_.begin());
    872        i != content_setting_views_.end(); ++i) {
    873     (*i)->Update(
    874         toolbar_model_->GetInputInProgress() ? NULL : GetWebContents());
    875     any_visible = (*i)->IsVisible() || any_visible;
    876   }
    877 
    878   // If there are no visible content things, hide the top level box so it
    879   // doesn't mess with padding.
    880   gtk_widget_set_visible(content_setting_hbox_.get(), any_visible);
    881 }
    882 
    883 void LocationBarViewGtk::UpdatePageActions() {
    884   UpdateScriptBubbleIcon();
    885 
    886   std::vector<ExtensionAction*> new_page_actions;
    887 
    888   WebContents* contents = GetWebContents();
    889   if (contents) {
    890     LocationBarController* location_bar_controller =
    891         extensions::TabHelper::FromWebContents(contents)->
    892             location_bar_controller();
    893     new_page_actions = location_bar_controller->GetCurrentActions();
    894   }
    895 
    896   // Initialize on the first call, or re-initialize if more extensions have been
    897   // loaded or added after startup.
    898   if (new_page_actions != page_actions_) {
    899     page_actions_.swap(new_page_actions);
    900     page_action_views_.clear();
    901 
    902     for (size_t i = 0; i < page_actions_.size(); ++i) {
    903       page_action_views_.push_back(
    904           new PageActionViewGtk(this, page_actions_[i]));
    905       gtk_box_pack_end(GTK_BOX(page_action_hbox_.get()),
    906                        page_action_views_[i]->widget(), FALSE, FALSE, 0);
    907     }
    908     content::NotificationService::current()->Notify(
    909         chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_COUNT_CHANGED,
    910         content::Source<LocationBar>(this),
    911         content::NotificationService::NoDetails());
    912   }
    913 
    914   if (!page_action_views_.empty() && contents) {
    915     GURL url = browser()->tab_strip_model()->GetActiveWebContents()->GetURL();
    916 
    917     for (size_t i = 0; i < page_action_views_.size(); i++) {
    918       page_action_views_[i]->UpdateVisibility(
    919           toolbar_model_->GetInputInProgress() ? NULL : contents, url);
    920     }
    921     gtk_widget_queue_draw(hbox_.get());
    922   }
    923 
    924   // If there are no visible page actions, hide the hbox too, so that it does
    925   // not affect the padding in the location bar.
    926   gtk_widget_set_visible(page_action_hbox_.get(),
    927                          PageActionVisibleCount() && !ShouldOnlyShowLocation());
    928 }
    929 
    930 void LocationBarViewGtk::InvalidatePageActions() {
    931   size_t count_before = page_action_views_.size();
    932   page_action_views_.clear();
    933   if (page_action_views_.size() != count_before) {
    934     content::NotificationService::current()->Notify(
    935         chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_COUNT_CHANGED,
    936         content::Source<LocationBar>(this),
    937         content::NotificationService::NoDetails());
    938   }
    939 }
    940 
    941 void LocationBarViewGtk::UpdateOpenPDFInReaderPrompt() {
    942   // Not implemented on Gtk.
    943 }
    944 
    945 void LocationBarViewGtk::UpdateGeneratedCreditCardView() {
    946   NOTIMPLEMENTED();
    947 }
    948 
    949 void LocationBarViewGtk::SaveStateToContents(WebContents* contents) {
    950   location_entry_->SaveStateToTab(contents);
    951 }
    952 
    953 void LocationBarViewGtk::Revert() {
    954   location_entry_->RevertAll();
    955 }
    956 
    957 const OmniboxView* LocationBarViewGtk::GetLocationEntry() const {
    958   return location_entry_.get();
    959 }
    960 
    961 OmniboxView* LocationBarViewGtk::GetLocationEntry() {
    962   return location_entry_.get();
    963 }
    964 
    965 LocationBarTesting* LocationBarViewGtk::GetLocationBarForTesting() {
    966   return this;
    967 }
    968 
    969 int LocationBarViewGtk::PageActionCount() {
    970   return page_action_views_.size();
    971 }
    972 
    973 int LocationBarViewGtk::PageActionVisibleCount() {
    974   int count = 0;
    975   gtk_container_foreach(GTK_CONTAINER(page_action_hbox_.get()),
    976                         CountVisibleWidgets, &count);
    977   return count;
    978 }
    979 
    980 ExtensionAction* LocationBarViewGtk::GetPageAction(size_t index) {
    981   if (index >= page_action_views_.size()) {
    982     NOTREACHED();
    983     return NULL;
    984   }
    985 
    986   return page_action_views_[index]->page_action();
    987 }
    988 
    989 ExtensionAction* LocationBarViewGtk::GetVisiblePageAction(size_t index) {
    990   size_t visible_index = 0;
    991   for (size_t i = 0; i < page_action_views_.size(); ++i) {
    992     if (page_action_views_[i]->IsVisible()) {
    993       if (index == visible_index++)
    994         return page_action_views_[i]->page_action();
    995     }
    996   }
    997 
    998   NOTREACHED();
    999   return NULL;
   1000 }
   1001 
   1002 void LocationBarViewGtk::TestPageActionPressed(size_t index) {
   1003   if (index >= page_action_views_.size()) {
   1004     NOTREACHED();
   1005     return;
   1006   }
   1007 
   1008   page_action_views_[index]->TestActivatePageAction();
   1009 }
   1010 
   1011 bool LocationBarViewGtk::GetBookmarkStarVisibility() {
   1012   return starred_;
   1013 }
   1014 
   1015 void LocationBarViewGtk::Observe(int type,
   1016                                  const content::NotificationSource& source,
   1017                                  const content::NotificationDetails& details) {
   1018   switch (type) {
   1019     case chrome::NOTIFICATION_EXTENSION_LOCATION_BAR_UPDATED: {
   1020       // Only update if the updated action box was for the active tab contents.
   1021       WebContents* target_tab = content::Details<WebContents>(details).ptr();
   1022       if (target_tab == GetWebContents())
   1023         UpdatePageActions();
   1024       break;
   1025     }
   1026 
   1027     case chrome::NOTIFICATION_BROWSER_THEME_CHANGED: {
   1028       if (theme_service_->UsingNativeTheme()) {
   1029         gtk_widget_modify_bg(tab_to_search_box_, GTK_STATE_NORMAL, NULL);
   1030 
   1031         GdkColor border_color = theme_service_->GetGdkColor(
   1032             ThemeProperties::COLOR_FRAME);
   1033         gtk_util::SetRoundedWindowBorderColor(tab_to_search_box_, border_color);
   1034 
   1035         gtk_util::UndoForceFontSize(security_info_label_);
   1036         gtk_util::UndoForceFontSize(tab_to_search_full_label_);
   1037         gtk_util::UndoForceFontSize(tab_to_search_partial_label_);
   1038         gtk_util::UndoForceFontSize(tab_to_search_hint_leading_label_);
   1039         gtk_util::UndoForceFontSize(tab_to_search_hint_trailing_label_);
   1040 
   1041         gtk_alignment_set_padding(GTK_ALIGNMENT(location_entry_alignment_),
   1042                                   0, 0, 0, 0);
   1043         gtk_alignment_set_padding(GTK_ALIGNMENT(tab_to_search_alignment_),
   1044                                   1, 1, 1, 0);
   1045         gtk_alignment_set_padding(GTK_ALIGNMENT(site_type_alignment_),
   1046                                   1, 1, 1, 0);
   1047       } else {
   1048         gtk_widget_modify_bg(tab_to_search_box_, GTK_STATE_NORMAL,
   1049                              &kKeywordBackgroundColor);
   1050         gtk_util::SetRoundedWindowBorderColor(tab_to_search_box_,
   1051                                               kKeywordBorderColor);
   1052 
   1053         // Until we switch to vector graphics, force the font size of labels.
   1054         // 12.1px = 9pt @ 96dpi
   1055         gtk_util::ForceFontSizePixels(security_info_label_, 12.1);
   1056         gtk_util::ForceFontSizePixels(tab_to_search_full_label_,
   1057                                       browser_defaults::kOmniboxFontPixelSize);
   1058         gtk_util::ForceFontSizePixels(tab_to_search_partial_label_,
   1059                                       browser_defaults::kOmniboxFontPixelSize);
   1060         gtk_util::ForceFontSizePixels(tab_to_search_hint_leading_label_,
   1061                                       browser_defaults::kOmniboxFontPixelSize);
   1062         gtk_util::ForceFontSizePixels(tab_to_search_hint_trailing_label_,
   1063                                       browser_defaults::kOmniboxFontPixelSize);
   1064 
   1065         const int top_bottom = popup_window_mode_ ? kPopupEdgeThickness : 0;
   1066         gtk_alignment_set_padding(GTK_ALIGNMENT(location_entry_alignment_),
   1067                                   kTopMargin + kBorderThickness,
   1068                                   kBottomMargin + kBorderThickness,
   1069                                   top_bottom, top_bottom);
   1070         gtk_alignment_set_padding(GTK_ALIGNMENT(tab_to_search_alignment_),
   1071                                   1, 1, 0, 0);
   1072         gtk_alignment_set_padding(GTK_ALIGNMENT(site_type_alignment_),
   1073                                   1, 1, 0, 0);
   1074       }
   1075 
   1076       UpdateZoomIcon();
   1077       UpdateScriptBubbleIcon();
   1078       UpdateStarIcon();
   1079       UpdateSiteTypeArea();
   1080       UpdateContentSettingsIcons();
   1081       break;
   1082     }
   1083 
   1084     default:
   1085       NOTREACHED();
   1086   }
   1087 }
   1088 
   1089 gboolean LocationBarViewGtk::HandleExpose(GtkWidget* widget,
   1090                                           GdkEventExpose* event) {
   1091   // If we're not using GTK theming, draw our own border over the edge pixels
   1092   // of the background.
   1093   GtkThemeService* theme_service =
   1094       GtkThemeService::GetFrom(browser_->profile());
   1095   if (!theme_service->UsingNativeTheme()) {
   1096     // Perform a scoped paint to fill in the background color.
   1097     {
   1098       gfx::CanvasSkiaPaint canvas(event, /*opaque=*/false);
   1099 
   1100       GtkAllocation allocation;
   1101       gtk_widget_get_allocation(widget, &allocation);
   1102 
   1103       int thickness = popup_window_mode_ ?
   1104           kPopupEdgeThickness : kNormalEdgeThickness;
   1105       gfx::Rect bounds(allocation);
   1106       bounds.Inset(thickness, thickness);
   1107 
   1108       const SkColor color = SK_ColorWHITE;
   1109       if (popup_window_mode_) {
   1110         canvas.FillRect(bounds, color);
   1111       } else {
   1112         SkPaint paint;
   1113         paint.setStyle(SkPaint::kFill_Style);
   1114         paint.setColor(color);
   1115         const int kBorderCornerRadius = 2;
   1116         canvas.DrawRoundRect(bounds, kBorderCornerRadius, paint);
   1117       }
   1118     }
   1119 
   1120     if (popup_window_mode_) {
   1121       NineBox(IDR_OMNIBOX_POPUP_BORDER_TOP_LEFT,
   1122               IDR_OMNIBOX_POPUP_BORDER_TOP,
   1123               IDR_OMNIBOX_POPUP_BORDER_TOP_RIGHT,
   1124               IDR_OMNIBOX_POPUP_BORDER_LEFT,
   1125               IDR_OMNIBOX_POPUP_BORDER_CENTER,
   1126               IDR_OMNIBOX_POPUP_BORDER_RIGHT,
   1127               IDR_OMNIBOX_POPUP_BORDER_BOTTOM_LEFT,
   1128               IDR_OMNIBOX_POPUP_BORDER_BOTTOM,
   1129               IDR_OMNIBOX_POPUP_BORDER_BOTTOM_RIGHT).RenderToWidget(widget);
   1130     } else {
   1131       NineBox(IDR_OMNIBOX_BORDER_TOP_LEFT,
   1132               IDR_OMNIBOX_BORDER_TOP,
   1133               IDR_OMNIBOX_BORDER_TOP_RIGHT,
   1134               IDR_OMNIBOX_BORDER_LEFT,
   1135               IDR_OMNIBOX_BORDER_CENTER,
   1136               IDR_OMNIBOX_BORDER_RIGHT,
   1137               IDR_OMNIBOX_BORDER_BOTTOM_LEFT,
   1138               IDR_OMNIBOX_BORDER_BOTTOM,
   1139               IDR_OMNIBOX_BORDER_BOTTOM_RIGHT).RenderToWidget(widget);
   1140     }
   1141   }
   1142 
   1143   // Draw ExtensionAction backgrounds and borders, if necessary.  The borders
   1144   // appear exactly between the elements, so they can't draw the borders
   1145   // themselves.
   1146   gfx::CanvasSkiaPaint canvas(event, /*opaque=*/false);
   1147   for (ScopedVector<PageActionViewGtk>::const_iterator
   1148            page_action_view = page_action_views_.begin();
   1149        page_action_view != page_action_views_.end();
   1150        ++page_action_view) {
   1151     if ((*page_action_view)->IsVisible()) {
   1152       // Figure out where the page action is drawn so we can draw
   1153       // borders to its left and right.
   1154       GtkAllocation allocation;
   1155       gtk_widget_get_allocation((*page_action_view)->widget(), &allocation);
   1156       ExtensionAction* action = (*page_action_view)->page_action();
   1157       gfx::Rect bounds(allocation);
   1158       // Make the bounding rectangle include the whole vertical range of the
   1159       // location bar, and the mid-point pixels between adjacent page actions.
   1160       //
   1161       // For odd InnerPadding()s, "InnerPadding() + 1" includes the mid-point
   1162       // between two page actions in the bounding rectangle.  For even paddings,
   1163       // the +1 is dropped, which is right since there is no pixel at the
   1164       // mid-point.
   1165       bounds.Inset(-(InnerPadding() + 1) / 2,
   1166                    theme_service_->UsingNativeTheme() ? -1 : 0);
   1167       location_bar_util::PaintExtensionActionBackground(
   1168           *action, SessionID::IdForTab(GetWebContents()),
   1169           &canvas, bounds,
   1170           theme_service_->get_location_bar_text_color(),
   1171           theme_service_->get_location_bar_bg_color());
   1172     }
   1173   }
   1174   // Destroying |canvas| draws the background.
   1175 
   1176   return FALSE;  // Continue propagating the expose.
   1177 }
   1178 
   1179 void LocationBarViewGtk::UpdateSiteTypeArea() {
   1180   // The icon is always visible except when the |tab_to_search_alignment_| is
   1181   // visible.
   1182   if (!location_entry_->model()->keyword().empty() &&
   1183       !location_entry_->model()->is_keyword_hint()) {
   1184     gtk_widget_hide(site_type_area());
   1185     return;
   1186   }
   1187 
   1188   int resource_id = location_entry_->GetIcon();
   1189   gtk_image_set_from_pixbuf(
   1190       GTK_IMAGE(location_icon_image_),
   1191       theme_service_->GetImageNamed(resource_id).ToGdkPixbuf());
   1192 
   1193   if (toolbar_model_->GetSecurityLevel(false) == ToolbarModel::EV_SECURE) {
   1194     if (!gtk_util::IsActingAsRoundedWindow(site_type_event_box_)) {
   1195       // Fun fact: If wee try to make |site_type_event_box_| act as a
   1196       // rounded window while it doesn't have a visible window, GTK interprets
   1197       // this as a sign that it should paint the skyline texture into the
   1198       // omnibox.
   1199       gtk_event_box_set_visible_window(GTK_EVENT_BOX(site_type_event_box_),
   1200                                        TRUE);
   1201 
   1202       gtk_util::ActAsRoundedWindow(site_type_event_box_,
   1203                                    kEvSecureBorderColor,
   1204                                    kCornerSize,
   1205                                    gtk_util::ROUNDED_ALL,
   1206                                    gtk_util::BORDER_ALL);
   1207     }
   1208 
   1209     string16 info_text = toolbar_model_->GetEVCertName();
   1210     gtk_label_set_text(GTK_LABEL(security_info_label_),
   1211                        UTF16ToUTF8(info_text).c_str());
   1212 
   1213     UpdateEVCertificateLabelSize();
   1214 
   1215     gtk_widget_show(GTK_WIDGET(security_info_label_));
   1216   } else {
   1217     if (gtk_util::IsActingAsRoundedWindow(site_type_event_box_)) {
   1218       gtk_util::StopActingAsRoundedWindow(site_type_event_box_);
   1219 
   1220       gtk_event_box_set_visible_window(GTK_EVENT_BOX(site_type_event_box_),
   1221                                        FALSE);
   1222     }
   1223 
   1224     gtk_widget_hide(GTK_WIDGET(security_info_label_));
   1225   }
   1226 
   1227   if (GetLocationEntry()->IsEditingOrEmpty()) {
   1228     // Do not show the tooltip if the user has been editing the location
   1229     // bar, or the location bar is at the NTP.
   1230     gtk_widget_set_tooltip_text(location_icon_image_, "");
   1231   } else {
   1232     gtk_widget_set_tooltip_text(location_icon_image_,
   1233         l10n_util::GetStringUTF8(IDS_TOOLTIP_LOCATION_ICON).c_str());
   1234   }
   1235 
   1236   gtk_widget_show(site_type_area());
   1237 
   1238   SetSiteTypeDragSource();
   1239 }
   1240 
   1241 void LocationBarViewGtk::UpdateEVCertificateLabelSize() {
   1242   // Figure out the width of the average character.
   1243   PangoLayout* layout = gtk_label_get_layout(GTK_LABEL(security_info_label_));
   1244   PangoContext* context = pango_layout_get_context(layout);
   1245   PangoFontMetrics* metrics = pango_context_get_metrics(
   1246       context,
   1247       gtk_widget_get_style(security_info_label_)->font_desc,
   1248       pango_context_get_language(context));
   1249   int char_width =
   1250       pango_font_metrics_get_approximate_char_width(metrics) / PANGO_SCALE;
   1251 
   1252   // The EV label should never take up more than half the hbox. We try to
   1253   // correct our inaccurate measurement units ("the average character width")
   1254   // by dividing more than an even 2.
   1255   GtkAllocation security_label_allocation;
   1256   gtk_widget_get_allocation(security_info_label_, &security_label_allocation);
   1257   GtkAllocation entry_box_allocation;
   1258   gtk_widget_get_allocation(entry_box_, &entry_box_allocation);
   1259   int text_area = security_label_allocation.width +
   1260                   entry_box_allocation.width;
   1261   int max_chars = static_cast<int>(static_cast<float>(text_area) /
   1262                                    static_cast<float>(char_width) / 2.75);
   1263   // Don't let the label be smaller than 10 characters so that the country
   1264   // code is always visible.
   1265   gtk_label_set_max_width_chars(GTK_LABEL(security_info_label_),
   1266                                 std::max(10, max_chars));
   1267 
   1268   pango_font_metrics_unref(metrics);
   1269 }
   1270 
   1271 void LocationBarViewGtk::SetKeywordLabel(const string16& keyword) {
   1272   if (keyword.empty())
   1273     return;
   1274 
   1275   Profile* profile = browser_->profile();
   1276   TemplateURLService* template_url_service =
   1277       TemplateURLServiceFactory::GetForProfile(profile);
   1278   if (!template_url_service)
   1279     return;
   1280 
   1281   bool is_extension_keyword;
   1282   const string16 short_name = template_url_service->GetKeywordShortName(
   1283       keyword, &is_extension_keyword);
   1284   const string16 min_string = location_bar_util::CalculateMinString(short_name);
   1285   const string16 full_name = is_extension_keyword ?
   1286       short_name :
   1287       l10n_util::GetStringFUTF16(IDS_OMNIBOX_KEYWORD_TEXT, short_name);
   1288   const string16 partial_name = is_extension_keyword ?
   1289       min_string :
   1290       l10n_util::GetStringFUTF16(IDS_OMNIBOX_KEYWORD_TEXT, min_string);
   1291   gtk_label_set_text(GTK_LABEL(tab_to_search_full_label_),
   1292                      UTF16ToUTF8(full_name).c_str());
   1293   gtk_label_set_text(GTK_LABEL(tab_to_search_partial_label_),
   1294                      UTF16ToUTF8(partial_name).c_str());
   1295 
   1296   if (last_keyword_ != keyword) {
   1297     last_keyword_ = keyword;
   1298 
   1299     if (is_extension_keyword) {
   1300       const TemplateURL* template_url =
   1301           template_url_service->GetTemplateURLForKeyword(keyword);
   1302       gfx::Image image = extensions::OmniboxAPI::Get(profile)->
   1303           GetOmniboxIcon(template_url->GetExtensionId());
   1304       gtk_image_set_from_pixbuf(GTK_IMAGE(tab_to_search_magnifier_),
   1305                                 image.ToGdkPixbuf());
   1306     } else {
   1307       ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
   1308       gtk_image_set_from_pixbuf(GTK_IMAGE(tab_to_search_magnifier_),
   1309           rb.GetNativeImageNamed(IDR_OMNIBOX_SEARCH).ToGdkPixbuf());
   1310     }
   1311   }
   1312 }
   1313 
   1314 void LocationBarViewGtk::SetKeywordHintLabel(const string16& keyword) {
   1315   if (keyword.empty())
   1316     return;
   1317 
   1318   TemplateURLService* template_url_service =
   1319       TemplateURLServiceFactory::GetForProfile(browser_->profile());
   1320   if (!template_url_service)
   1321     return;
   1322 
   1323   bool is_extension_keyword;
   1324   const string16 short_name = template_url_service->
   1325       GetKeywordShortName(keyword, &is_extension_keyword);
   1326   int message_id = is_extension_keyword ?
   1327       IDS_OMNIBOX_EXTENSION_KEYWORD_HINT : IDS_OMNIBOX_KEYWORD_HINT;
   1328   std::vector<size_t> content_param_offsets;
   1329   const string16 keyword_hint = l10n_util::GetStringFUTF16(
   1330       message_id,
   1331       string16(),
   1332       short_name,
   1333       &content_param_offsets);
   1334   if (content_param_offsets.size() != 2) {
   1335     // See comments on an identical NOTREACHED() in search_provider.cc.
   1336     NOTREACHED();
   1337     return;
   1338   }
   1339 
   1340   std::string leading(UTF16ToUTF8(
   1341       keyword_hint.substr(0, content_param_offsets.front())));
   1342   std::string trailing(UTF16ToUTF8(
   1343       keyword_hint.substr(content_param_offsets.front())));
   1344   gtk_label_set_text(GTK_LABEL(tab_to_search_hint_leading_label_),
   1345                      leading.c_str());
   1346   gtk_label_set_text(GTK_LABEL(tab_to_search_hint_trailing_label_),
   1347                      trailing.c_str());
   1348 }
   1349 
   1350 void LocationBarViewGtk::ShowFirstRunBubbleInternal() {
   1351   if (!location_entry_.get() || !gtk_widget_get_window(widget()))
   1352     return;
   1353 
   1354   gfx::Rect bounds = gtk_util::WidgetBounds(location_icon_image_);
   1355   bounds.set_x(bounds.x() + kFirstRunBubbleLeftSpacing);
   1356   FirstRunBubble::Show(browser_, location_icon_image_, bounds);
   1357 }
   1358 
   1359 gboolean LocationBarViewGtk::OnIconReleased(GtkWidget* sender,
   1360                                             GdkEventButton* event) {
   1361   WebContents* tab = GetWebContents();
   1362 
   1363   if (event->button == 1) {
   1364     // Do not show page info if the user has been editing the location
   1365     // bar, or the location bar is at the NTP.
   1366     if (GetLocationEntry()->IsEditingOrEmpty())
   1367       return FALSE;
   1368 
   1369     // (0,0) event coordinates indicates that the release came at the end of
   1370     // a drag.
   1371     if (event->x == 0 && event->y == 0)
   1372       return FALSE;
   1373 
   1374     // Important to use GetVisibleEntry to match what's showing in the omnibox.
   1375     NavigationEntry* nav_entry = tab->GetController().GetVisibleEntry();
   1376     if (!nav_entry) {
   1377       NOTREACHED();
   1378       return FALSE;
   1379     }
   1380     chrome::ShowWebsiteSettings(browser_, tab, nav_entry->GetURL(),
   1381                                 nav_entry->GetSSL());
   1382     return TRUE;
   1383   } else if (event->button == 2) {
   1384     // When the user middle clicks on the location icon, try to open the
   1385     // contents of the PRIMARY selection in the current tab.
   1386     // If the click was outside our bounds, do nothing.
   1387     if (!gtk_util::WidgetBounds(sender).Contains(
   1388             gfx::Point(event->x, event->y))) {
   1389       return FALSE;
   1390     }
   1391 
   1392     GURL url;
   1393     if (!gtk_util::URLFromPrimarySelection(browser_->profile(), &url))
   1394       return FALSE;
   1395 
   1396     tab->OpenURL(OpenURLParams(
   1397         url, content::Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED,
   1398         false));
   1399     return TRUE;
   1400   }
   1401 
   1402   return FALSE;
   1403 }
   1404 
   1405 void LocationBarViewGtk::OnIconDragData(GtkWidget* sender,
   1406                                         GdkDragContext* context,
   1407                                         GtkSelectionData* data,
   1408                                         guint info, guint time) {
   1409   ui::WriteURLWithName(data, drag_url_, drag_title_, info);
   1410 }
   1411 
   1412 void LocationBarViewGtk::OnIconDragBegin(GtkWidget* sender,
   1413                                          GdkDragContext* context) {
   1414   gfx::Image favicon = GetFavicon();
   1415   if (favicon.IsEmpty())
   1416     return;
   1417   drag_icon_ = bookmark_utils::GetDragRepresentation(favicon.ToGdkPixbuf(),
   1418       GetTitle(), theme_service_);
   1419   gtk_drag_set_icon_widget(context, drag_icon_, 0, 0);
   1420 
   1421   WebContents* tab = GetWebContents();
   1422   if (!tab)
   1423     return;
   1424   drag_url_ = tab->GetURL();
   1425   drag_title_ = tab->GetTitle();
   1426 }
   1427 
   1428 void LocationBarViewGtk::OnIconDragEnd(GtkWidget* sender,
   1429                                        GdkDragContext* context) {
   1430   DCHECK(drag_icon_);
   1431   gtk_widget_destroy(drag_icon_);
   1432   drag_icon_ = NULL;
   1433   drag_url_ = GURL::EmptyGURL();
   1434   drag_title_.clear();
   1435 }
   1436 
   1437 void LocationBarViewGtk::OnHboxSizeAllocate(GtkWidget* sender,
   1438                                             GtkAllocation* allocation) {
   1439   if (hbox_width_ != allocation->width) {
   1440     hbox_width_ = allocation->width;
   1441     UpdateEVCertificateLabelSize();
   1442   }
   1443   if (browser_ && browser_->instant_controller()) {
   1444     browser_->instant_controller()->
   1445         SetOmniboxBounds(AllocationToRect(*allocation));
   1446   }
   1447 }
   1448 
   1449 void LocationBarViewGtk::OnEntryBoxSizeAllocate(GtkWidget* sender,
   1450                                                 GtkAllocation* allocation) {
   1451   if (entry_box_width_ != allocation->width) {
   1452     entry_box_width_ = allocation->width;
   1453     AdjustChildrenVisibility();
   1454   }
   1455 }
   1456 
   1457 gboolean LocationBarViewGtk::OnZoomButtonPress(GtkWidget* widget,
   1458                                                GdkEventButton* event) {
   1459   if (event->button == 1 && GetWebContents()) {
   1460     // If the zoom icon is clicked, show the zoom bubble and keep it open until
   1461     // it loses focus.
   1462     ZoomBubbleGtk::ShowBubble(GetWebContents(), false);
   1463     return TRUE;
   1464   }
   1465   return FALSE;
   1466 }
   1467 
   1468 gboolean LocationBarViewGtk::OnScriptBubbleButtonPress(GtkWidget* widget,
   1469                                                        GdkEventButton* event) {
   1470   if (event->button == 1 && GetWebContents()) {
   1471     ScriptBubbleGtk::Show(script_bubble_button_image_, GetWebContents());
   1472     return TRUE;
   1473   }
   1474   return FALSE;
   1475 }
   1476 
   1477 gboolean LocationBarViewGtk::OnScriptBubbleButtonExpose(GtkWidget* widget,
   1478                                                         GdkEventExpose* event) {
   1479   gfx::CanvasSkiaPaint canvas(event, false);
   1480   GtkAllocation allocation;
   1481   gtk_widget_get_allocation(widget, &allocation);
   1482   badge_util::PaintBadge(&canvas,
   1483                          gfx::Rect(allocation),
   1484                          base::UintToString(num_running_scripts_),
   1485                          SK_ColorWHITE,
   1486                          SkColorSetRGB(0, 170, 0),
   1487                          allocation.width,
   1488                          extensions::ActionInfo::TYPE_PAGE);
   1489   return FALSE;
   1490 }
   1491 
   1492 void LocationBarViewGtk::OnStarButtonSizeAllocate(GtkWidget* sender,
   1493                                                   GtkAllocation* allocation) {
   1494   if (!on_star_sized_.is_null()) {
   1495     on_star_sized_.Run();
   1496     on_star_sized_.Reset();
   1497   }
   1498   star_sized_ = true;
   1499 }
   1500 
   1501 gboolean LocationBarViewGtk::OnStarButtonPress(GtkWidget* widget,
   1502                                                GdkEventButton* event) {
   1503   if (event->button == 1) {
   1504     chrome::ExecuteCommand(browser_, IDC_BOOKMARK_PAGE);
   1505     return TRUE;
   1506   }
   1507   return FALSE;
   1508 }
   1509 
   1510 void LocationBarViewGtk::ShowZoomBubble() {
   1511   if (toolbar_model_->GetInputInProgress() || !GetWebContents())
   1512     return;
   1513 
   1514   ZoomBubbleGtk::ShowBubble(GetWebContents(), true);
   1515 }
   1516 
   1517 void LocationBarViewGtk::ShowStarBubble(const GURL& url,
   1518                                         bool newly_bookmarked) {
   1519   if (!star_.get())
   1520     return;
   1521 
   1522   if (star_sized_) {
   1523     BookmarkBubbleGtk::Show(star_.get(), browser_->profile(), url,
   1524                             newly_bookmarked);
   1525   } else {
   1526     on_star_sized_ = base::Bind(&BookmarkBubbleGtk::Show,
   1527                                 star_.get(), browser_->profile(),
   1528                                 url, newly_bookmarked);
   1529   }
   1530 }
   1531 
   1532 void LocationBarViewGtk::SetStarred(bool starred) {
   1533   if (starred == starred_)
   1534     return;
   1535 
   1536   starred_ = starred;
   1537   UpdateStarIcon();
   1538 }
   1539 
   1540 void LocationBarViewGtk::ZoomChangedForActiveTab(bool can_show_bubble) {
   1541   UpdateZoomIcon();
   1542 
   1543   if (can_show_bubble && gtk_widget_get_visible(zoom_.get()))
   1544     ShowZoomBubble();
   1545 }
   1546 
   1547 void LocationBarViewGtk::UpdateZoomIcon() {
   1548   WebContents* web_contents = GetWebContents();
   1549   if (!zoom_.get() || !web_contents)
   1550     return;
   1551 
   1552   ZoomController* zoom_controller =
   1553       ZoomController::FromWebContents(web_contents);
   1554   if (!zoom_controller || zoom_controller->IsAtDefaultZoom() ||
   1555       toolbar_model_->GetInputInProgress()) {
   1556     gtk_widget_hide(zoom_.get());
   1557     ZoomBubbleGtk::CloseBubble();
   1558     return;
   1559   }
   1560 
   1561   const int zoom_resource = zoom_controller->GetResourceForZoomLevel();
   1562   gtk_image_set_from_pixbuf(GTK_IMAGE(zoom_image_),
   1563       theme_service_->GetImageNamed(zoom_resource).ToGdkPixbuf());
   1564 
   1565   string16 tooltip = l10n_util::GetStringFUTF16Int(
   1566       IDS_TOOLTIP_ZOOM, zoom_controller->zoom_percent());
   1567   gtk_widget_set_tooltip_text(zoom_.get(), UTF16ToUTF8(tooltip).c_str());
   1568 
   1569   gtk_widget_show(zoom_.get());
   1570 }
   1571 
   1572 void LocationBarViewGtk::UpdateScriptBubbleIcon() {
   1573   num_running_scripts_ = 0;
   1574   if (GetWebContents()) {
   1575     extensions::TabHelper* tab_helper =
   1576         extensions::TabHelper::FromWebContents(GetWebContents());
   1577     if (tab_helper && tab_helper->script_bubble_controller()) {
   1578       num_running_scripts_ = tab_helper->script_bubble_controller()->
   1579           extensions_running_scripts().size();
   1580     }
   1581   }
   1582 
   1583   if (num_running_scripts_ == 0u)
   1584     gtk_widget_hide(script_bubble_button_.get());
   1585   else
   1586     gtk_widget_show(script_bubble_button_.get());
   1587 }
   1588 
   1589 void LocationBarViewGtk::UpdateStarIcon() {
   1590   if (!star_.get())
   1591     return;
   1592   // Indicate the star icon is not correctly sized. It will be marked as sized
   1593   // when the next size-allocate signal is received by the star widget.
   1594   star_sized_ = false;
   1595   bool star_enabled = !toolbar_model_->GetInputInProgress() &&
   1596                       edit_bookmarks_enabled_.GetValue();
   1597   command_updater_->UpdateCommandEnabled(IDC_BOOKMARK_PAGE, star_enabled);
   1598   command_updater_->UpdateCommandEnabled(IDC_BOOKMARK_PAGE_FROM_STAR,
   1599                                          star_enabled);
   1600   if (star_enabled) {
   1601     gtk_widget_show_all(star_.get());
   1602     int id = starred_ ? IDR_STAR_LIT : IDR_STAR;
   1603     gtk_image_set_from_pixbuf(GTK_IMAGE(star_image_),
   1604                               theme_service_->GetImageNamed(id).ToGdkPixbuf());
   1605     gtk_widget_set_tooltip_text(star_.get(), l10n_util::GetStringUTF8(
   1606           starred_ ? IDS_TOOLTIP_STARRED : IDS_TOOLTIP_STAR).c_str());
   1607   } else {
   1608     gtk_widget_hide_all(star_.get());
   1609   }
   1610 }
   1611 
   1612 bool LocationBarViewGtk::ShouldOnlyShowLocation() {
   1613   return !browser_->is_type_tabbed();
   1614 }
   1615 
   1616 void LocationBarViewGtk::AdjustChildrenVisibility() {
   1617   int text_width = location_entry_->TextWidth();
   1618   int available_width = entry_box_width_ - text_width - InnerPadding();
   1619 
   1620   // Only one of |tab_to_search_alignment_| and |tab_to_search_hint_| can be
   1621   // visible at the same time.
   1622   if (!show_selected_keyword_ &&
   1623       gtk_widget_get_visible(tab_to_search_alignment_)) {
   1624     gtk_widget_hide(tab_to_search_alignment_);
   1625   } else if (!show_keyword_hint_ &&
   1626              gtk_widget_get_visible(tab_to_search_hint_)) {
   1627     gtk_widget_hide(tab_to_search_hint_);
   1628   }
   1629 
   1630   if (show_selected_keyword_) {
   1631     GtkRequisition box, full_label, partial_label;
   1632     gtk_widget_size_request(tab_to_search_box_, &box);
   1633     gtk_widget_size_request(tab_to_search_full_label_, &full_label);
   1634     gtk_widget_size_request(tab_to_search_partial_label_, &partial_label);
   1635     int full_partial_width_diff = full_label.width - partial_label.width;
   1636     int full_box_width;
   1637     int partial_box_width;
   1638     if (gtk_widget_get_visible(tab_to_search_full_label_)) {
   1639       full_box_width = box.width;
   1640       partial_box_width = full_box_width - full_partial_width_diff;
   1641     } else {
   1642       partial_box_width = box.width;
   1643       full_box_width = partial_box_width + full_partial_width_diff;
   1644     }
   1645 
   1646     if (partial_box_width >= entry_box_width_ - InnerPadding()) {
   1647       gtk_widget_hide(tab_to_search_alignment_);
   1648     } else if (full_box_width >= available_width) {
   1649       gtk_widget_hide(tab_to_search_full_label_);
   1650       gtk_widget_show(tab_to_search_partial_label_);
   1651       gtk_widget_show(tab_to_search_alignment_);
   1652     } else if (full_box_width < available_width) {
   1653       gtk_widget_hide(tab_to_search_partial_label_);
   1654       gtk_widget_show(tab_to_search_full_label_);
   1655       gtk_widget_show(tab_to_search_alignment_);
   1656     }
   1657   } else if (show_keyword_hint_) {
   1658     GtkRequisition leading, icon, trailing;
   1659     gtk_widget_size_request(tab_to_search_hint_leading_label_, &leading);
   1660     gtk_widget_size_request(tab_to_search_hint_icon_, &icon);
   1661     gtk_widget_size_request(tab_to_search_hint_trailing_label_, &trailing);
   1662     int full_width = leading.width + icon.width + trailing.width;
   1663 
   1664     if (icon.width >= entry_box_width_ - InnerPadding()) {
   1665       gtk_widget_hide(tab_to_search_hint_);
   1666     } else if (full_width >= available_width) {
   1667       gtk_widget_hide(tab_to_search_hint_leading_label_);
   1668       gtk_widget_hide(tab_to_search_hint_trailing_label_);
   1669       gtk_widget_show(tab_to_search_hint_);
   1670     } else if (full_width < available_width) {
   1671       gtk_widget_show(tab_to_search_hint_leading_label_);
   1672       gtk_widget_show(tab_to_search_hint_trailing_label_);
   1673       gtk_widget_show(tab_to_search_hint_);
   1674     }
   1675   }
   1676 }
   1677 
   1678 ////////////////////////////////////////////////////////////////////////////////
   1679 // LocationBarViewGtk::PageToolViewGtk
   1680 
   1681 LocationBarViewGtk::PageToolViewGtk::PageToolViewGtk(
   1682     const LocationBarViewGtk* parent)
   1683     : alignment_(gtk_alignment_new(0, 0, 1, 1)),
   1684       event_box_(gtk_event_box_new()),
   1685       hbox_(gtk_hbox_new(FALSE, InnerPadding())),
   1686       image_(gtk_image_new()),
   1687       label_(gtk_label_new(NULL)),
   1688       parent_(parent),
   1689       animation_(this),
   1690       weak_factory_(this) {
   1691   gtk_alignment_set_padding(GTK_ALIGNMENT(alignment_.get()), 1, 1, 0, 0);
   1692   gtk_container_add(GTK_CONTAINER(alignment_.get()), event_box_.get());
   1693 
   1694   // Make the event box not visible so it does not paint a background.
   1695   gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box_.get()), FALSE);
   1696   g_signal_connect(event_box_.get(), "button-press-event",
   1697                    G_CALLBACK(&OnButtonPressedThunk), this);
   1698   g_signal_connect(event_box_.get(), "expose-event",
   1699                    G_CALLBACK(&OnExposeThunk), this);
   1700 
   1701   gtk_widget_set_no_show_all(label_.get(), TRUE);
   1702   gtk_label_set_line_wrap(GTK_LABEL(label_.get()), FALSE);
   1703 
   1704   gtk_box_pack_start(GTK_BOX(hbox_), image_.get(), FALSE, FALSE, 0);
   1705   gtk_box_pack_start(GTK_BOX(hbox_), label_.get(), FALSE, FALSE, 0);
   1706 
   1707   gtk_container_set_border_width(GTK_CONTAINER(hbox_), kHboxBorder);
   1708 
   1709   gtk_container_add(GTK_CONTAINER(event_box_.get()), hbox_);
   1710   gtk_widget_hide(widget());
   1711 
   1712   animation_.SetSlideDuration(kPageToolAnimationTime);
   1713 }
   1714 
   1715 LocationBarViewGtk::PageToolViewGtk::~PageToolViewGtk() {
   1716   image_.Destroy();
   1717   label_.Destroy();
   1718   event_box_.Destroy();
   1719   alignment_.Destroy();
   1720 }
   1721 
   1722 GtkWidget* LocationBarViewGtk::PageToolViewGtk::widget() {
   1723   return alignment_.get();
   1724 }
   1725 
   1726 bool LocationBarViewGtk::PageToolViewGtk::IsVisible() {
   1727   return gtk_widget_get_visible(widget());
   1728 }
   1729 
   1730 void LocationBarViewGtk::PageToolViewGtk::StartAnimating() {
   1731   if (animation_.IsShowing() || animation_.IsClosing())
   1732     return;
   1733 
   1734   gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box_.get()), TRUE);
   1735   GdkColor border_color = button_border_color();
   1736   gtk_util::ActAsRoundedWindow(event_box_.get(), border_color,
   1737                                kCornerSize,
   1738                                gtk_util::ROUNDED_ALL, gtk_util::BORDER_ALL);
   1739 
   1740   gtk_widget_set_size_request(label_.get(), -1, -1);
   1741   gtk_widget_size_request(label_.get(), &label_req_);
   1742   gtk_widget_set_size_request(label_.get(), 0, -1);
   1743   gtk_widget_show(label_.get());
   1744 
   1745   animation_.Show();
   1746 }
   1747 
   1748 void LocationBarViewGtk::PageToolViewGtk::CloseAnimation() {
   1749   animation_.Hide();
   1750 }
   1751 
   1752 void LocationBarViewGtk::PageToolViewGtk::AnimationProgressed(
   1753     const ui::Animation* animation) {
   1754   gtk_widget_set_size_request(
   1755       label_.get(),
   1756       animation->GetCurrentValue() * label_req_.width,
   1757       -1);
   1758 }
   1759 
   1760 void LocationBarViewGtk::PageToolViewGtk::AnimationEnded(
   1761     const ui::Animation* animation) {
   1762 }
   1763 
   1764 void LocationBarViewGtk::PageToolViewGtk::AnimationCanceled(
   1765     const ui::Animation* animation) {
   1766 }
   1767 
   1768 gboolean LocationBarViewGtk::PageToolViewGtk::OnButtonPressed(
   1769     GtkWidget* sender, GdkEvent* event) {
   1770   OnClick(sender);
   1771   return TRUE;
   1772 }
   1773 
   1774 gboolean LocationBarViewGtk::PageToolViewGtk::OnExpose(
   1775     GtkWidget* sender, GdkEventExpose* event) {
   1776   TRACE_EVENT0("ui::gtk", "LocationBarViewGtk::PageToolViewGtk::OnExpose");
   1777 
   1778   if (!(animation_.IsShowing() || animation_.IsClosing()))
   1779     return FALSE;
   1780 
   1781   GtkAllocation allocation;
   1782   gtk_widget_get_allocation(sender, &allocation);
   1783   const int height = allocation.height;
   1784 
   1785   cairo_t* cr = gdk_cairo_create(gtk_widget_get_window(sender));
   1786   gdk_cairo_rectangle(cr, &event->area);
   1787   cairo_clip(cr);
   1788 
   1789   cairo_pattern_t* pattern = cairo_pattern_create_linear(0, 0, 0, height);
   1790 
   1791   const GdkColor top_color = gradient_top_color();
   1792   const GdkColor bottom_color = gradient_bottom_color();
   1793   cairo_pattern_add_color_stop_rgb(
   1794       pattern, 0.0,
   1795       top_color.red/255.0,
   1796       top_color.blue/255.0,
   1797       top_color.green/255.0);
   1798   cairo_pattern_add_color_stop_rgb(
   1799       pattern, 1.0,
   1800       bottom_color.red/255.0,
   1801       bottom_color.blue/255.0,
   1802       bottom_color.green/255.0);
   1803 
   1804   cairo_set_source(cr, pattern);
   1805   cairo_paint(cr);
   1806   cairo_pattern_destroy(pattern);
   1807   cairo_destroy(cr);
   1808 
   1809   return FALSE;
   1810 }
   1811 
   1812 ////////////////////////////////////////////////////////////////////////////////
   1813 // LocationBarViewGtk::PageActionViewGtk
   1814 
   1815 LocationBarViewGtk::PageActionViewGtk::PageActionViewGtk(
   1816     LocationBarViewGtk* owner,
   1817     ExtensionAction* page_action)
   1818     : owner_(NULL),
   1819       page_action_(page_action),
   1820       current_tab_id_(-1),
   1821       window_(NULL),
   1822       accel_group_(NULL),
   1823       preview_enabled_(false),
   1824       scoped_icon_animation_observer_(
   1825           page_action->GetIconAnimation(
   1826               SessionID::IdForTab(owner->GetWebContents())),
   1827           this) {
   1828   event_box_.Own(gtk_event_box_new());
   1829   gtk_widget_set_size_request(event_box_.get(),
   1830                               extensions::IconsInfo::kPageActionIconMaxSize,
   1831                               extensions::IconsInfo::kPageActionIconMaxSize);
   1832 
   1833   // Make the event box not visible so it does not paint a background.
   1834   gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box_.get()), FALSE);
   1835   g_signal_connect(event_box_.get(), "button-press-event",
   1836                    G_CALLBACK(&OnButtonPressedThunk), this);
   1837   g_signal_connect_after(event_box_.get(), "expose-event",
   1838                          G_CALLBACK(OnExposeEventThunk), this);
   1839   g_signal_connect(event_box_.get(), "realize",
   1840                    G_CALLBACK(OnRealizeThunk), this);
   1841 
   1842   image_.Own(gtk_image_new());
   1843   gtk_container_add(GTK_CONTAINER(event_box_.get()), image_.get());
   1844 
   1845   const Extension* extension = owner->browser()->profile()->
   1846       GetExtensionService()->GetExtensionById(page_action->extension_id(),
   1847                                               false);
   1848   DCHECK(extension);
   1849 
   1850   icon_factory_.reset(
   1851       new ExtensionActionIconFactory(
   1852           owner->browser()->profile(), extension, page_action, this));
   1853 
   1854   // We set the owner last of all so that we can determine whether we are in
   1855   // the process of initializing this class or not.
   1856   owner_ = owner;
   1857 }
   1858 
   1859 LocationBarViewGtk::PageActionViewGtk::~PageActionViewGtk() {
   1860   DisconnectPageActionAccelerator();
   1861 
   1862   image_.Destroy();
   1863   event_box_.Destroy();
   1864 }
   1865 
   1866 bool LocationBarViewGtk::PageActionViewGtk::IsVisible() {
   1867   return gtk_widget_get_visible(widget());
   1868 }
   1869 
   1870 void LocationBarViewGtk::PageActionViewGtk::UpdateVisibility(
   1871     WebContents* contents, const GURL& url) {
   1872   // Save this off so we can pass it back to the extension when the action gets
   1873   // executed. See PageActionImageView::OnMousePressed.
   1874   current_tab_id_ = contents ? ExtensionTabUtil::GetTabId(contents) : -1;
   1875   current_url_ = url;
   1876 
   1877   bool visible = contents &&
   1878       (preview_enabled_ || page_action_->GetIsVisible(current_tab_id_));
   1879   if (visible) {
   1880     // Set the tooltip.
   1881     gtk_widget_set_tooltip_text(event_box_.get(),
   1882         page_action_->GetTitle(current_tab_id_).c_str());
   1883 
   1884     // Set the image.
   1885     gfx::Image icon = icon_factory_->GetIcon(current_tab_id_);
   1886     if (!icon.IsEmpty()) {
   1887       GdkPixbuf* pixbuf = icon.ToGdkPixbuf();
   1888       DCHECK(pixbuf);
   1889       gtk_image_set_from_pixbuf(GTK_IMAGE(image_.get()), pixbuf);
   1890     }
   1891   }
   1892 
   1893   bool old_visible = IsVisible();
   1894   if (visible)
   1895     gtk_widget_show_all(event_box_.get());
   1896   else
   1897     gtk_widget_hide_all(event_box_.get());
   1898 
   1899   if (visible != old_visible) {
   1900     content::NotificationService::current()->Notify(
   1901         chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED,
   1902         content::Source<ExtensionAction>(page_action_),
   1903         content::Details<WebContents>(contents));
   1904   }
   1905 }
   1906 
   1907 void LocationBarViewGtk::PageActionViewGtk::OnIconUpdated() {
   1908   // If we have no owner, that means this class is still being constructed.
   1909   WebContents* web_contents = owner_ ? owner_->GetWebContents() : NULL;
   1910   if (web_contents)
   1911     UpdateVisibility(web_contents, current_url_);
   1912 }
   1913 
   1914 void LocationBarViewGtk::PageActionViewGtk::TestActivatePageAction() {
   1915   GdkEventButton event = {};
   1916   event.type = GDK_BUTTON_PRESS;
   1917   event.button = 1;
   1918   OnButtonPressed(widget(), &event);
   1919 }
   1920 
   1921 void LocationBarViewGtk::PageActionViewGtk::Observe(
   1922     int type,
   1923     const content::NotificationSource& source,
   1924     const content::NotificationDetails& details) {
   1925   DCHECK_EQ(type, chrome::NOTIFICATION_WINDOW_CLOSED);
   1926   DisconnectPageActionAccelerator();
   1927 }
   1928 
   1929 void LocationBarViewGtk::PageActionViewGtk::ConnectPageActionAccelerator() {
   1930   const ExtensionSet* extensions = owner_->browser()->profile()->
   1931       GetExtensionService()->extensions();
   1932   const Extension* extension =
   1933       extensions->GetByID(page_action_->extension_id());
   1934   window_ = owner_->browser()->window()->GetNativeWindow();
   1935 
   1936   extensions::CommandService* command_service =
   1937       extensions::CommandService::Get(owner_->browser()->profile());
   1938 
   1939   extensions::Command command_page_action;
   1940   if (command_service->GetPageActionCommand(
   1941           extension->id(),
   1942           extensions::CommandService::ACTIVE_ONLY,
   1943           &command_page_action,
   1944           NULL)) {
   1945     // Found the page action shortcut command, register it.
   1946     page_action_keybinding_.reset(
   1947         new ui::Accelerator(command_page_action.accelerator()));
   1948   }
   1949 
   1950   extensions::Command command_script_badge;
   1951   if (command_service->GetScriptBadgeCommand(
   1952           extension->id(),
   1953           extensions::CommandService::ACTIVE_ONLY,
   1954           &command_script_badge,
   1955           NULL)) {
   1956     // Found the script badge shortcut command, register it.
   1957     script_badge_keybinding_.reset(
   1958         new ui::Accelerator(command_script_badge.accelerator()));
   1959   }
   1960 
   1961   if (page_action_keybinding_.get() || script_badge_keybinding_.get()) {
   1962     accel_group_ = gtk_accel_group_new();
   1963     gtk_window_add_accel_group(window_, accel_group_);
   1964 
   1965     if (page_action_keybinding_.get()) {
   1966       gtk_accel_group_connect(
   1967           accel_group_,
   1968           ui::GetGdkKeyCodeForAccelerator(*page_action_keybinding_),
   1969           ui::GetGdkModifierForAccelerator(*page_action_keybinding_),
   1970           GtkAccelFlags(0),
   1971           g_cclosure_new(G_CALLBACK(OnGtkAccelerator), this, NULL));
   1972     }
   1973     if (script_badge_keybinding_.get()) {
   1974       gtk_accel_group_connect(
   1975           accel_group_,
   1976           ui::GetGdkKeyCodeForAccelerator(*script_badge_keybinding_),
   1977           ui::GetGdkModifierForAccelerator(*script_badge_keybinding_),
   1978           GtkAccelFlags(0),
   1979           g_cclosure_new(G_CALLBACK(OnGtkAccelerator), this, NULL));
   1980     }
   1981 
   1982     // Since we've added an accelerator, we'll need to unregister it before
   1983     // the window is closed, so we listen for the window being closed.
   1984     registrar_.Add(this,
   1985                    chrome::NOTIFICATION_WINDOW_CLOSED,
   1986                    content::Source<GtkWindow>(window_));
   1987   }
   1988 }
   1989 
   1990 void LocationBarViewGtk::PageActionViewGtk::OnIconChanged() {
   1991   UpdateVisibility(owner_->GetWebContents(), current_url_);
   1992 }
   1993 
   1994 void LocationBarViewGtk::PageActionViewGtk::DisconnectPageActionAccelerator() {
   1995   if (accel_group_) {
   1996     if (page_action_keybinding_.get()) {
   1997       gtk_accel_group_disconnect_key(
   1998           accel_group_,
   1999           ui::GetGdkKeyCodeForAccelerator(*page_action_keybinding_),
   2000           ui::GetGdkModifierForAccelerator(*page_action_keybinding_));
   2001     }
   2002     if (script_badge_keybinding_.get()) {
   2003       gtk_accel_group_disconnect_key(
   2004           accel_group_,
   2005           ui::GetGdkKeyCodeForAccelerator(*script_badge_keybinding_),
   2006           ui::GetGdkModifierForAccelerator(*script_badge_keybinding_));
   2007     }
   2008     gtk_window_remove_accel_group(window_, accel_group_);
   2009     g_object_unref(accel_group_);
   2010     accel_group_ = NULL;
   2011     page_action_keybinding_.reset(NULL);
   2012     script_badge_keybinding_.reset(NULL);
   2013   }
   2014 }
   2015 
   2016 gboolean LocationBarViewGtk::PageActionViewGtk::OnButtonPressed(
   2017     GtkWidget* sender,
   2018     GdkEventButton* event) {
   2019   // Double and triple-clicks generate both a GDK_BUTTON_PRESS and a
   2020   // GDK_[23]BUTTON_PRESS event. We don't want to double-trigger by acting on
   2021   // both.
   2022   if (event->type != GDK_BUTTON_PRESS)
   2023     return TRUE;
   2024 
   2025   WebContents* web_contents = owner_->GetWebContents();
   2026   if (!web_contents)
   2027     return TRUE;
   2028 
   2029   ExtensionService* extension_service =
   2030       owner_->browser()->profile()->GetExtensionService();
   2031   if (!extension_service)
   2032     return TRUE;
   2033 
   2034   const Extension* extension =
   2035       extension_service->extensions()->GetByID(page_action()->extension_id());
   2036   if (!extension)
   2037     return TRUE;
   2038 
   2039   LocationBarController* controller =
   2040       extensions::TabHelper::FromWebContents(web_contents)->
   2041           location_bar_controller();
   2042 
   2043   switch (controller->OnClicked(extension->id(), event->button)) {
   2044     case LocationBarController::ACTION_NONE:
   2045       break;
   2046 
   2047     case LocationBarController::ACTION_SHOW_POPUP:
   2048       ExtensionPopupGtk::Show(
   2049           page_action_->GetPopupUrl(current_tab_id_),
   2050           owner_->browser_,
   2051           event_box_.get(),
   2052           ExtensionPopupGtk::SHOW);
   2053       break;
   2054 
   2055     case LocationBarController::ACTION_SHOW_CONTEXT_MENU:
   2056       context_menu_model_ =
   2057           new ExtensionContextMenuModel(extension, owner_->browser_, this);
   2058       context_menu_.reset(
   2059           new MenuGtk(NULL, context_menu_model_.get()));
   2060       context_menu_->PopupForWidget(sender, event->button, event->time);
   2061       break;
   2062 
   2063     case LocationBarController::ACTION_SHOW_SCRIPT_POPUP:
   2064       ExtensionPopupGtk::Show(
   2065           extensions::ExtensionInfoUI::GetURL(extension->id()),
   2066           owner_->browser_,
   2067           event_box_.get(),
   2068           ExtensionPopupGtk::SHOW);
   2069       break;
   2070   }
   2071 
   2072   return TRUE;
   2073 }
   2074 
   2075 gboolean LocationBarViewGtk::PageActionViewGtk::OnExposeEvent(
   2076     GtkWidget* widget,
   2077     GdkEventExpose* event) {
   2078   TRACE_EVENT0("ui::gtk", "LocationBarViewGtk::PageActionViewGtk::OnExpose");
   2079   WebContents* contents = owner_->GetWebContents();
   2080   if (!contents)
   2081     return FALSE;
   2082 
   2083   int tab_id = ExtensionTabUtil::GetTabId(contents);
   2084   if (tab_id < 0)
   2085     return FALSE;
   2086 
   2087   std::string badge_text = page_action_->GetBadgeText(tab_id);
   2088   if (badge_text.empty())
   2089     return FALSE;
   2090 
   2091   gfx::CanvasSkiaPaint canvas(event, false);
   2092   GtkAllocation allocation;
   2093   gtk_widget_get_allocation(widget, &allocation);
   2094   page_action_->PaintBadge(&canvas, gfx::Rect(allocation), tab_id);
   2095   return FALSE;
   2096 }
   2097 
   2098 void LocationBarViewGtk::PageActionViewGtk::OnRealize(GtkWidget* widget) {
   2099   ConnectPageActionAccelerator();
   2100 }
   2101 
   2102 // static
   2103 gboolean LocationBarViewGtk::PageActionViewGtk::OnGtkAccelerator(
   2104     GtkAccelGroup* accel_group,
   2105     GObject* acceleratable,
   2106     guint keyval,
   2107     GdkModifierType modifier,
   2108     void* user_data) {
   2109   PageActionViewGtk* view = static_cast<PageActionViewGtk*>(user_data);
   2110   if (!gtk_widget_get_visible(view->widget()))
   2111     return FALSE;
   2112 
   2113   GdkEventButton event = {};
   2114   event.type = GDK_BUTTON_PRESS;
   2115   event.button = 1;
   2116   return view->OnButtonPressed(view->widget(), &event);
   2117 }
   2118 
   2119 void LocationBarViewGtk::PageActionViewGtk::InspectPopup(
   2120     ExtensionAction* action) {
   2121   ExtensionPopupGtk::Show(
   2122       action->GetPopupUrl(current_tab_id_),
   2123       owner_->browser_,
   2124       event_box_.get(),
   2125       ExtensionPopupGtk::SHOW_AND_INSPECT);
   2126 }
   2127