Home | History | Annotate | Download | only in gtk
      1 // Copyright (c) 2011 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/command_line.h"
     13 #include "base/i18n/rtl.h"
     14 #include "base/logging.h"
     15 #include "base/string_util.h"
     16 #include "base/utf_string_conversions.h"
     17 #include "chrome/app/chrome_command_ids.h"
     18 #include "chrome/browser/accessibility_events.h"
     19 #include "chrome/browser/alternate_nav_url_fetcher.h"
     20 #include "chrome/browser/autocomplete/autocomplete_edit_view_gtk.h"
     21 #include "chrome/browser/autocomplete/autocomplete_popup_model.h"
     22 #include "chrome/browser/command_updater.h"
     23 #include "chrome/browser/content_setting_bubble_model.h"
     24 #include "chrome/browser/content_setting_image_model.h"
     25 #include "chrome/browser/defaults.h"
     26 #include "chrome/browser/extensions/extension_browser_event_router.h"
     27 #include "chrome/browser/extensions/extension_service.h"
     28 #include "chrome/browser/extensions/extension_tabs_module.h"
     29 #include "chrome/browser/instant/instant_controller.h"
     30 #include "chrome/browser/profiles/profile.h"
     31 #include "chrome/browser/search_engines/template_url.h"
     32 #include "chrome/browser/search_engines/template_url_model.h"
     33 #include "chrome/browser/ui/browser.h"
     34 #include "chrome/browser/ui/browser_list.h"
     35 #include "chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.h"
     36 #include "chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.h"
     37 #include "chrome/browser/ui/gtk/cairo_cached_surface.h"
     38 #include "chrome/browser/ui/gtk/content_setting_bubble_gtk.h"
     39 #include "chrome/browser/ui/gtk/extensions/extension_popup_gtk.h"
     40 #include "chrome/browser/ui/gtk/first_run_bubble.h"
     41 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
     42 #include "chrome/browser/ui/gtk/gtk_util.h"
     43 #include "chrome/browser/ui/gtk/nine_box.h"
     44 #include "chrome/browser/ui/gtk/rounded_window.h"
     45 #include "chrome/browser/ui/gtk/view_id_util.h"
     46 #include "chrome/browser/ui/omnibox/location_bar_util.h"
     47 #include "chrome/common/chrome_switches.h"
     48 #include "chrome/common/extensions/extension.h"
     49 #include "chrome/common/extensions/extension_action.h"
     50 #include "chrome/common/extensions/extension_resource.h"
     51 #include "chrome/common/pref_names.h"
     52 #include "content/browser/tab_contents/tab_contents.h"
     53 #include "content/common/notification_service.h"
     54 #include "content/common/page_transition_types.h"
     55 #include "grit/generated_resources.h"
     56 #include "grit/theme_resources.h"
     57 #include "net/base/net_util.h"
     58 #include "ui/base/dragdrop/gtk_dnd_util.h"
     59 #include "ui/base/l10n/l10n_util.h"
     60 #include "ui/base/resource/resource_bundle.h"
     61 #include "ui/gfx/canvas_skia_paint.h"
     62 #include "ui/gfx/font.h"
     63 #include "ui/gfx/gtk_util.h"
     64 #include "webkit/glue/window_open_disposition.h"
     65 
     66 namespace {
     67 
     68 // We are positioned with a little bit of extra space that we don't use now.
     69 const int kTopMargin = 1;
     70 const int kBottomMargin = 1;
     71 const int kLeftMargin = 1;
     72 const int kRightMargin = 1;
     73 // We draw a border on the top and bottom (but not on left or right).
     74 const int kBorderThickness = 1;
     75 
     76 // Left margin of first run bubble.
     77 const int kFirstRunBubbleLeftMargin = 8;
     78 // Extra vertical spacing for first run bubble.
     79 const int kFirstRunBubbleTopMargin = 5;
     80 // Spacing needed to align the bubble with the left side of the omnibox.
     81 const int kFirstRunBubbleLeftSpacing = 4;
     82 
     83 // The padding around the top, bottom, and sides of the location bar hbox.
     84 // We don't want to edit control's text to be right against the edge,
     85 // as well the tab to search box and other widgets need to have the padding on
     86 // top and bottom to avoid drawing larger than the location bar space.
     87 const int kHboxBorder = 2;
     88 
     89 // Padding between the elements in the bar.
     90 const int kInnerPadding = 2;
     91 
     92 // Padding between the right of the star and the edge of the URL entry.
     93 const int kStarRightPadding = 2;
     94 
     95 // Colors used to draw the EV certificate rounded bubble.
     96 const GdkColor kEvSecureTextColor = GDK_COLOR_RGB(0x07, 0x95, 0x00);
     97 const GdkColor kEvSecureBackgroundColor = GDK_COLOR_RGB(0xef, 0xfc, 0xef);
     98 const GdkColor kEvSecureBorderColor = GDK_COLOR_RGB(0x90, 0xc3, 0x90);
     99 
    100 // Colors used to draw the Tab to Search rounded bubble.
    101 const GdkColor kKeywordBackgroundColor = GDK_COLOR_RGB(0xf0, 0xf4, 0xfa);
    102 const GdkColor kKeywordBorderColor = GDK_COLOR_RGB(0xcb, 0xde, 0xf7);
    103 
    104 // Use weak gray for showing search and keyword hint text.
    105 const GdkColor kHintTextColor = GDK_COLOR_RGB(0x75, 0x75, 0x75);
    106 
    107 // Size of the rounding of the "Search site for:" box.
    108 const int kCornerSize = 3;
    109 
    110 // The time, in ms, that the content setting label is fully displayed, for the
    111 // cases where we animate it into and out of view.
    112 const int kContentSettingImageDisplayTime = 3200;
    113 // The time, in ms, of the animation (open and close).
    114 const int kContentSettingImageAnimationTime = 150;
    115 
    116 // Color of border of content setting area (icon/label).
    117 const GdkColor kContentSettingBorderColor = GDK_COLOR_RGB(0xe9, 0xb9, 0x66);
    118 // Colors for the background gradient.
    119 const double kContentSettingTopColor[] = { 0xff / 255.0,
    120                                            0xf8 / 255.0,
    121                                            0xd4 / 255.0 };
    122 const double kContentSettingBottomColor[] = { 0xff / 255.0,
    123                                               0xe6 / 255.0,
    124                                               0xaf / 255.0 };
    125 
    126 // If widget is visible, increment the int pointed to by count.
    127 // Suitible for use with gtk_container_foreach.
    128 void CountVisibleWidgets(GtkWidget* widget, gpointer count) {
    129   if (GTK_WIDGET_VISIBLE(widget))
    130     *static_cast<int*>(count) += 1;
    131 }
    132 
    133 }  // namespace
    134 
    135 ////////////////////////////////////////////////////////////////////////////////
    136 // LocationBarViewGtk
    137 
    138 // static
    139 const GdkColor LocationBarViewGtk::kBackgroundColor =
    140     GDK_COLOR_RGB(255, 255, 255);
    141 
    142 LocationBarViewGtk::LocationBarViewGtk(Browser* browser)
    143     : star_image_(NULL),
    144       starred_(false),
    145       site_type_alignment_(NULL),
    146       site_type_event_box_(NULL),
    147       location_icon_image_(NULL),
    148       drag_icon_(NULL),
    149       enable_location_drag_(false),
    150       security_info_label_(NULL),
    151       tab_to_search_alignment_(NULL),
    152       tab_to_search_box_(NULL),
    153       tab_to_search_full_label_(NULL),
    154       tab_to_search_partial_label_(NULL),
    155       tab_to_search_hint_(NULL),
    156       tab_to_search_hint_leading_label_(NULL),
    157       tab_to_search_hint_icon_(NULL),
    158       tab_to_search_hint_trailing_label_(NULL),
    159       profile_(NULL),
    160       command_updater_(browser->command_updater()),
    161       toolbar_model_(browser->toolbar_model()),
    162       browser_(browser),
    163       disposition_(CURRENT_TAB),
    164       transition_(PageTransition::TYPED),
    165       first_run_bubble_(this),
    166       popup_window_mode_(false),
    167       theme_service_(NULL),
    168       hbox_width_(0),
    169       entry_box_width_(0),
    170       show_selected_keyword_(false),
    171       show_keyword_hint_(false) {
    172 }
    173 
    174 LocationBarViewGtk::~LocationBarViewGtk() {
    175   // All of our widgets should have be children of / owned by the alignment.
    176   star_.Destroy();
    177   hbox_.Destroy();
    178   content_setting_hbox_.Destroy();
    179   page_action_hbox_.Destroy();
    180 }
    181 
    182 void LocationBarViewGtk::Init(bool popup_window_mode) {
    183   popup_window_mode_ = popup_window_mode;
    184 
    185   // Create the widget first, so we can pass it to the AutocompleteEditViewGtk.
    186   hbox_.Own(gtk_hbox_new(FALSE, kInnerPadding));
    187   gtk_container_set_border_width(GTK_CONTAINER(hbox_.get()), kHboxBorder);
    188   // We will paint for the alignment, to paint the background and border.
    189   gtk_widget_set_app_paintable(hbox_.get(), TRUE);
    190   // Redraw the whole location bar when it changes size (e.g., when toggling
    191   // the home button on/off.
    192   gtk_widget_set_redraw_on_allocate(hbox_.get(), TRUE);
    193 
    194   // Now initialize the AutocompleteEditViewGtk.
    195   location_entry_.reset(new AutocompleteEditViewGtk(this,
    196                                                     toolbar_model_,
    197                                                     profile_,
    198                                                     command_updater_,
    199                                                     popup_window_mode_,
    200                                                     hbox_.get()));
    201   location_entry_->Init();
    202 
    203   g_signal_connect(hbox_.get(), "expose-event",
    204                    G_CALLBACK(&HandleExposeThunk), this);
    205 
    206   BuildSiteTypeArea();
    207 
    208   // Put |tab_to_search_box_|, |location_entry_|, and |tab_to_search_hint_| into
    209   // a sub hbox, so that we can make this part horizontally shrinkable without
    210   // affecting other elements in the location bar.
    211   entry_box_ = gtk_hbox_new(FALSE, kInnerPadding);
    212   gtk_widget_show(entry_box_);
    213   gtk_widget_set_size_request(entry_box_, 0, -1);
    214   gtk_box_pack_start(GTK_BOX(hbox_.get()), entry_box_, TRUE, TRUE, 0);
    215 
    216   // We need to adjust the visibility of the search hint widgets according to
    217   // the horizontal space in the |entry_box_|.
    218   g_signal_connect(entry_box_, "size-allocate",
    219                    G_CALLBACK(&OnEntryBoxSizeAllocateThunk), this);
    220 
    221   // Tab to search (the keyword box on the left hand side).
    222   tab_to_search_full_label_ = gtk_label_new(NULL);
    223   tab_to_search_partial_label_ = gtk_label_new(NULL);
    224   GtkWidget* tab_to_search_label_hbox = gtk_hbox_new(FALSE, 0);
    225   gtk_box_pack_start(GTK_BOX(tab_to_search_label_hbox),
    226                      tab_to_search_full_label_, FALSE, FALSE, 0);
    227   gtk_box_pack_start(GTK_BOX(tab_to_search_label_hbox),
    228                      tab_to_search_partial_label_, FALSE, FALSE, 0);
    229   GtkWidget* tab_to_search_hbox = gtk_hbox_new(FALSE, 0);
    230   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    231   tab_to_search_magnifier_ = gtk_image_new_from_pixbuf(
    232       rb.GetPixbufNamed(IDR_KEYWORD_SEARCH_MAGNIFIER));
    233   gtk_box_pack_start(GTK_BOX(tab_to_search_hbox), tab_to_search_magnifier_,
    234                      FALSE, FALSE, 0);
    235   gtk_util::CenterWidgetInHBox(tab_to_search_hbox, tab_to_search_label_hbox,
    236                                false, 0);
    237 
    238   // This creates a box around the keyword text with a border, background color,
    239   // and padding around the text.
    240   tab_to_search_box_ = gtk_util::CreateGtkBorderBin(
    241       tab_to_search_hbox, NULL, 1, 1, 1, 3);
    242   gtk_widget_set_name(tab_to_search_box_, "chrome-tab-to-search-box");
    243   gtk_util::ActAsRoundedWindow(tab_to_search_box_, kKeywordBorderColor,
    244                                kCornerSize,
    245                                gtk_util::ROUNDED_ALL, gtk_util::BORDER_ALL);
    246 
    247   // Put the event box in an alignment to get the padding correct.
    248   tab_to_search_alignment_ = gtk_alignment_new(0, 0, 1, 1);
    249   gtk_container_add(GTK_CONTAINER(tab_to_search_alignment_),
    250                     tab_to_search_box_);
    251   gtk_box_pack_start(GTK_BOX(entry_box_), tab_to_search_alignment_,
    252                      FALSE, FALSE, 0);
    253 
    254   // Show all children widgets of |tab_to_search_box_| initially, except
    255   // |tab_to_search_partial_label_|.
    256   gtk_widget_show_all(tab_to_search_box_);
    257   gtk_widget_hide(tab_to_search_partial_label_);
    258 
    259   location_entry_alignment_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
    260   gtk_container_add(GTK_CONTAINER(location_entry_alignment_),
    261                     location_entry_->GetNativeView());
    262   gtk_box_pack_start(GTK_BOX(entry_box_), location_entry_alignment_,
    263                      TRUE, TRUE, 0);
    264 
    265   // Tab to search notification (the hint on the right hand side).
    266   tab_to_search_hint_ = gtk_hbox_new(FALSE, 0);
    267   gtk_widget_set_name(tab_to_search_hint_, "chrome-tab-to-search-hint");
    268   tab_to_search_hint_leading_label_ = gtk_label_new(NULL);
    269   gtk_widget_set_sensitive(tab_to_search_hint_leading_label_, FALSE);
    270   tab_to_search_hint_icon_ = gtk_image_new_from_pixbuf(
    271       rb.GetPixbufNamed(IDR_LOCATION_BAR_KEYWORD_HINT_TAB));
    272   tab_to_search_hint_trailing_label_ = gtk_label_new(NULL);
    273   gtk_widget_set_sensitive(tab_to_search_hint_trailing_label_, FALSE);
    274   gtk_box_pack_start(GTK_BOX(tab_to_search_hint_),
    275                      tab_to_search_hint_leading_label_,
    276                      FALSE, FALSE, 0);
    277   gtk_box_pack_start(GTK_BOX(tab_to_search_hint_),
    278                      tab_to_search_hint_icon_,
    279                      FALSE, FALSE, 0);
    280   gtk_box_pack_start(GTK_BOX(tab_to_search_hint_),
    281                      tab_to_search_hint_trailing_label_,
    282                      FALSE, FALSE, 0);
    283   // Show all children widgets of |tab_to_search_hint_| initially.
    284   gtk_widget_show_all(tab_to_search_hint_);
    285   gtk_widget_hide(tab_to_search_hint_);
    286   // tab_to_search_hint_ gets hidden initially in OnChanged.  Hiding it here
    287   // doesn't work, someone is probably calling show_all on our parent box.
    288   gtk_box_pack_end(GTK_BOX(entry_box_), tab_to_search_hint_, FALSE, FALSE, 0);
    289 
    290   // We don't show the star in popups, app windows, etc.
    291   if (browser_defaults::bookmarks_enabled && !ShouldOnlyShowLocation()) {
    292     CreateStarButton();
    293     gtk_box_pack_end(GTK_BOX(hbox_.get()), star_.get(), FALSE, FALSE, 0);
    294   }
    295 
    296   content_setting_hbox_.Own(gtk_hbox_new(FALSE, kInnerPadding + 1));
    297   gtk_widget_set_name(content_setting_hbox_.get(),
    298                       "chrome-content-setting-hbox");
    299   gtk_box_pack_end(GTK_BOX(hbox_.get()), content_setting_hbox_.get(),
    300                    FALSE, FALSE, 1);
    301 
    302   for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
    303     ContentSettingImageViewGtk* content_setting_view =
    304         new ContentSettingImageViewGtk(
    305             static_cast<ContentSettingsType>(i), this, profile_);
    306     content_setting_views_.push_back(content_setting_view);
    307     gtk_box_pack_end(GTK_BOX(content_setting_hbox_.get()),
    308                      content_setting_view->widget(), FALSE, FALSE, 0);
    309   }
    310 
    311   page_action_hbox_.Own(gtk_hbox_new(FALSE, kInnerPadding));
    312   gtk_widget_set_name(page_action_hbox_.get(),
    313                       "chrome-page-action-hbox");
    314   gtk_box_pack_end(GTK_BOX(hbox_.get()), page_action_hbox_.get(),
    315                    FALSE, FALSE, 0);
    316 
    317   // Now that we've created the widget hierarchy, connect to the main |hbox_|'s
    318   // size-allocate so we can do proper resizing and eliding on
    319   // |security_info_label_|.
    320   g_signal_connect(hbox_.get(), "size-allocate",
    321                    G_CALLBACK(&OnHboxSizeAllocateThunk), this);
    322 
    323   registrar_.Add(this,
    324                  NotificationType::BROWSER_THEME_CHANGED,
    325                  NotificationService::AllSources());
    326   edit_bookmarks_enabled_.Init(prefs::kEditBookmarksEnabled,
    327                                profile_->GetPrefs(), this);
    328 
    329   theme_service_ = GtkThemeService::GetFrom(profile_);
    330   theme_service_->InitThemesFor(this);
    331 }
    332 
    333 void LocationBarViewGtk::BuildSiteTypeArea() {
    334   location_icon_image_ = gtk_image_new();
    335   gtk_widget_set_name(location_icon_image_, "chrome-location-icon");
    336 
    337   GtkWidget* icon_alignment = gtk_alignment_new(0, 0, 1, 1);
    338   gtk_alignment_set_padding(GTK_ALIGNMENT(icon_alignment), 0, 0, 2, 0);
    339   gtk_container_add(GTK_CONTAINER(icon_alignment), location_icon_image_);
    340   gtk_widget_show_all(icon_alignment);
    341 
    342   security_info_label_ = gtk_label_new(NULL);
    343   gtk_label_set_ellipsize(GTK_LABEL(security_info_label_),
    344                           PANGO_ELLIPSIZE_MIDDLE);
    345   gtk_widget_modify_fg(GTK_WIDGET(security_info_label_), GTK_STATE_NORMAL,
    346                        &kEvSecureTextColor);
    347   gtk_widget_set_name(security_info_label_,
    348                       "chrome-location-bar-security-info-label");
    349 
    350   GtkWidget* site_type_hbox = gtk_hbox_new(FALSE, 1);
    351   gtk_box_pack_start(GTK_BOX(site_type_hbox), icon_alignment,
    352                      FALSE, FALSE, 0);
    353   gtk_box_pack_start(GTK_BOX(site_type_hbox), security_info_label_,
    354                      FALSE, FALSE, 2);
    355 
    356   site_type_event_box_ = gtk_event_box_new();
    357   gtk_widget_modify_bg(site_type_event_box_, GTK_STATE_NORMAL,
    358                        &kEvSecureBackgroundColor);
    359   g_signal_connect(site_type_event_box_, "drag-data-get",
    360                    G_CALLBACK(&OnIconDragDataThunk), this);
    361   g_signal_connect(site_type_event_box_, "drag-begin",
    362                    G_CALLBACK(&OnIconDragBeginThunk), this);
    363   g_signal_connect(site_type_event_box_, "drag-end",
    364                    G_CALLBACK(&OnIconDragEndThunk), this);
    365 
    366   // Make the event box not visible so it does not paint a background.
    367   gtk_event_box_set_visible_window(GTK_EVENT_BOX(site_type_event_box_),
    368                                    FALSE);
    369   gtk_widget_set_name(site_type_event_box_,
    370                       "chrome-location-icon-eventbox");
    371   gtk_container_add(GTK_CONTAINER(site_type_event_box_),
    372                     site_type_hbox);
    373 
    374   // Put the event box in an alignment to get the padding correct.
    375   site_type_alignment_ = gtk_alignment_new(0, 0, 1, 1);
    376   gtk_container_add(GTK_CONTAINER(site_type_alignment_),
    377                     site_type_event_box_);
    378   gtk_box_pack_start(GTK_BOX(hbox_.get()), site_type_alignment_,
    379                      FALSE, FALSE, 0);
    380 
    381   gtk_widget_set_tooltip_text(location_icon_image_,
    382       l10n_util::GetStringUTF8(IDS_TOOLTIP_LOCATION_ICON).c_str());
    383 
    384   g_signal_connect(site_type_event_box_, "button-release-event",
    385                    G_CALLBACK(&OnIconReleasedThunk), this);
    386 }
    387 
    388 void LocationBarViewGtk::SetSiteTypeDragSource() {
    389   bool enable = !location_entry()->IsEditingOrEmpty();
    390   if (enable_location_drag_ == enable)
    391     return;
    392   enable_location_drag_ = enable;
    393 
    394   if (!enable) {
    395     gtk_drag_source_unset(site_type_event_box_);
    396     return;
    397   }
    398 
    399   gtk_drag_source_set(site_type_event_box_, GDK_BUTTON1_MASK,
    400                       NULL, 0, GDK_ACTION_COPY);
    401   ui::SetSourceTargetListFromCodeMask(site_type_event_box_,
    402                                       ui::TEXT_PLAIN |
    403                                       ui::TEXT_URI_LIST |
    404                                       ui::CHROME_NAMED_URL);
    405 }
    406 
    407 void LocationBarViewGtk::SetProfile(Profile* profile) {
    408   profile_ = profile;
    409 }
    410 
    411 TabContents* LocationBarViewGtk::GetTabContents() const {
    412   return browser_->GetSelectedTabContents();
    413 }
    414 
    415 void LocationBarViewGtk::SetPreviewEnabledPageAction(
    416     ExtensionAction *page_action,
    417     bool preview_enabled) {
    418   DCHECK(page_action);
    419   UpdatePageActions();
    420   for (ScopedVector<PageActionViewGtk>::iterator iter =
    421        page_action_views_.begin(); iter != page_action_views_.end();
    422        ++iter) {
    423     if ((*iter)->page_action() == page_action) {
    424       (*iter)->set_preview_enabled(preview_enabled);
    425       UpdatePageActions();
    426       return;
    427     }
    428   }
    429 }
    430 
    431 GtkWidget* LocationBarViewGtk::GetPageActionWidget(
    432     ExtensionAction *page_action) {
    433   DCHECK(page_action);
    434   for (ScopedVector<PageActionViewGtk>::iterator iter =
    435            page_action_views_.begin();
    436        iter != page_action_views_.end();
    437        ++iter) {
    438     if ((*iter)->page_action() == page_action)
    439       return (*iter)->widget();
    440   }
    441   return NULL;
    442 }
    443 
    444 void LocationBarViewGtk::Update(const TabContents* contents) {
    445   UpdateStarIcon();
    446   UpdateSiteTypeArea();
    447   UpdateContentSettingsIcons();
    448   UpdatePageActions();
    449   location_entry_->Update(contents);
    450   // The security level (background color) could have changed, etc.
    451   if (theme_service_->UseGtkTheme()) {
    452     // In GTK mode, we need our parent to redraw, as it draws the text entry
    453     // border.
    454     gtk_widget_queue_draw(widget()->parent);
    455   } else {
    456     gtk_widget_queue_draw(widget());
    457   }
    458 }
    459 
    460 void LocationBarViewGtk::OnAutocompleteAccept(const GURL& url,
    461     WindowOpenDisposition disposition,
    462     PageTransition::Type transition,
    463     const GURL& alternate_nav_url) {
    464   if (url.is_valid()) {
    465     location_input_ = UTF8ToWide(url.spec());
    466     disposition_ = disposition;
    467     transition_ = transition;
    468 
    469     if (command_updater_) {
    470       if (!alternate_nav_url.is_valid()) {
    471         command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
    472       } else {
    473         AlternateNavURLFetcher* fetcher =
    474             new AlternateNavURLFetcher(alternate_nav_url);
    475         // The AlternateNavURLFetcher will listen for the pending navigation
    476         // notification that will be issued as a result of the "open URL." It
    477         // will automatically install itself into that navigation controller.
    478         command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
    479         if (fetcher->state() == AlternateNavURLFetcher::NOT_STARTED) {
    480           // I'm not sure this should be reachable, but I'm not also sure enough
    481           // that it shouldn't to stick in a NOTREACHED().  In any case, this is
    482           // harmless.
    483           delete fetcher;
    484         } else {
    485           // The navigation controller will delete the fetcher.
    486         }
    487       }
    488     }
    489   }
    490 }
    491 
    492 void LocationBarViewGtk::OnChanged() {
    493   UpdateSiteTypeArea();
    494 
    495   const string16 keyword(location_entry_->model()->keyword());
    496   const bool is_keyword_hint = location_entry_->model()->is_keyword_hint();
    497   show_selected_keyword_ = !keyword.empty() && !is_keyword_hint;
    498   show_keyword_hint_ = !keyword.empty() && is_keyword_hint;
    499 
    500   if (show_selected_keyword_)
    501     SetKeywordLabel(keyword);
    502 
    503   if (show_keyword_hint_)
    504     SetKeywordHintLabel(keyword);
    505 
    506   AdjustChildrenVisibility();
    507 }
    508 
    509 void LocationBarViewGtk::OnSelectionBoundsChanged() {
    510   NOTIMPLEMENTED();
    511 }
    512 
    513 void LocationBarViewGtk::CreateStarButton() {
    514   star_image_ = gtk_image_new();
    515 
    516   GtkWidget* alignment = gtk_alignment_new(0, 0, 1, 1);
    517   gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0,
    518                             0, kStarRightPadding);
    519   gtk_container_add(GTK_CONTAINER(alignment), star_image_);
    520 
    521   star_.Own(gtk_event_box_new());
    522   gtk_event_box_set_visible_window(GTK_EVENT_BOX(star_.get()), FALSE);
    523   gtk_container_add(GTK_CONTAINER(star_.get()), alignment);
    524   gtk_widget_show_all(star_.get());
    525   ViewIDUtil::SetID(star_.get(), VIEW_ID_STAR_BUTTON);
    526 
    527   gtk_widget_set_tooltip_text(star_.get(),
    528       l10n_util::GetStringUTF8(IDS_TOOLTIP_STAR).c_str());
    529   g_signal_connect(star_.get(), "button-press-event",
    530                    G_CALLBACK(OnStarButtonPressThunk), this);
    531 }
    532 
    533 void LocationBarViewGtk::OnInputInProgress(bool in_progress) {
    534   // This is identical to the Windows code, except that we don't proxy the call
    535   // back through the Toolbar, and just access the model here.
    536   // The edit should make sure we're only notified when something changes.
    537   DCHECK(toolbar_model_->input_in_progress() != in_progress);
    538 
    539   toolbar_model_->set_input_in_progress(in_progress);
    540   Update(NULL);
    541 }
    542 
    543 void LocationBarViewGtk::OnKillFocus() {
    544 }
    545 
    546 void LocationBarViewGtk::OnSetFocus() {
    547   AccessibilityTextBoxInfo info(
    548       profile_,
    549       l10n_util::GetStringUTF8(IDS_ACCNAME_LOCATION).c_str(),
    550       false);
    551   NotificationService::current()->Notify(
    552       NotificationType::ACCESSIBILITY_CONTROL_FOCUSED,
    553       Source<Profile>(profile_),
    554       Details<AccessibilityTextBoxInfo>(&info));
    555 
    556   // Update the keyword and search hint states.
    557   OnChanged();
    558 }
    559 
    560 SkBitmap LocationBarViewGtk::GetFavicon() const {
    561   return GetTabContents()->GetFavicon();
    562 }
    563 
    564 string16 LocationBarViewGtk::GetTitle() const {
    565   return GetTabContents()->GetTitle();
    566 }
    567 
    568 InstantController* LocationBarViewGtk::GetInstant() {
    569   return browser_->instant();
    570 }
    571 
    572 TabContentsWrapper* LocationBarViewGtk::GetTabContentsWrapper() const {
    573   return browser_->GetSelectedTabContentsWrapper();
    574 }
    575 
    576 void LocationBarViewGtk::ShowFirstRunBubble(FirstRun::BubbleType bubble_type) {
    577   // We need the browser window to be shown before we can show the bubble, but
    578   // we get called before that's happened.
    579   Task* task = first_run_bubble_.NewRunnableMethod(
    580       &LocationBarViewGtk::ShowFirstRunBubbleInternal, bubble_type);
    581   MessageLoop::current()->PostTask(FROM_HERE, task);
    582 }
    583 
    584 void LocationBarViewGtk::SetSuggestedText(const string16& text,
    585                                           InstantCompleteBehavior behavior) {
    586   location_entry_->model()->SetSuggestedText(text, behavior);
    587 }
    588 
    589 std::wstring LocationBarViewGtk::GetInputString() const {
    590   return location_input_;
    591 }
    592 
    593 WindowOpenDisposition LocationBarViewGtk::GetWindowOpenDisposition() const {
    594   return disposition_;
    595 }
    596 
    597 PageTransition::Type LocationBarViewGtk::GetPageTransition() const {
    598   return transition_;
    599 }
    600 
    601 void LocationBarViewGtk::AcceptInput() {
    602   location_entry_->model()->AcceptInput(CURRENT_TAB, false);
    603 }
    604 
    605 void LocationBarViewGtk::FocusLocation(bool select_all) {
    606   location_entry_->SetFocus();
    607   if (select_all)
    608     location_entry_->SelectAll(true);
    609 }
    610 
    611 void LocationBarViewGtk::FocusSearch() {
    612   location_entry_->SetFocus();
    613   location_entry_->SetForcedQuery();
    614 }
    615 
    616 void LocationBarViewGtk::UpdateContentSettingsIcons() {
    617   TabContents* tab_contents = GetTabContents();
    618   bool any_visible = false;
    619   for (ScopedVector<ContentSettingImageViewGtk>::iterator i(
    620            content_setting_views_.begin());
    621        i != content_setting_views_.end(); ++i) {
    622     (*i)->UpdateFromTabContents(
    623         toolbar_model_->input_in_progress() ? NULL : tab_contents);
    624     any_visible = (*i)->IsVisible() || any_visible;
    625   }
    626 
    627   // If there are no visible content things, hide the top level box so it
    628   // doesn't mess with padding.
    629   if (any_visible)
    630     gtk_widget_show(content_setting_hbox_.get());
    631   else
    632     gtk_widget_hide(content_setting_hbox_.get());
    633 }
    634 
    635 void LocationBarViewGtk::UpdatePageActions() {
    636   std::vector<ExtensionAction*> page_actions;
    637   ExtensionService* service = profile_->GetExtensionService();
    638   if (!service)
    639     return;
    640 
    641   // Find all the page actions.
    642   for (size_t i = 0; i < service->extensions()->size(); ++i) {
    643     if (service->extensions()->at(i)->page_action())
    644       page_actions.push_back(service->extensions()->at(i)->page_action());
    645   }
    646 
    647   // Initialize on the first call, or re-inialize if more extensions have been
    648   // loaded or added after startup.
    649   if (page_actions.size() != page_action_views_.size()) {
    650     page_action_views_.reset();  // Delete the old views (if any).
    651 
    652     for (size_t i = 0; i < page_actions.size(); ++i) {
    653       page_action_views_.push_back(
    654           new PageActionViewGtk(this, profile_, page_actions[i]));
    655       gtk_box_pack_end(GTK_BOX(page_action_hbox_.get()),
    656                        page_action_views_[i]->widget(), FALSE, FALSE, 0);
    657     }
    658     NotificationService::current()->Notify(
    659         NotificationType::EXTENSION_PAGE_ACTION_COUNT_CHANGED,
    660         Source<LocationBar>(this),
    661         NotificationService::NoDetails());
    662   }
    663 
    664   TabContents* contents = GetTabContents();
    665   if (!page_action_views_.empty() && contents) {
    666     GURL url = GURL(WideToUTF8(toolbar_model_->GetText()));
    667 
    668     for (size_t i = 0; i < page_action_views_.size(); i++) {
    669       page_action_views_[i]->UpdateVisibility(
    670           toolbar_model_->input_in_progress() ? NULL : contents, url);
    671     }
    672   }
    673 
    674   // If there are no visible page actions, hide the hbox too, so that it does
    675   // not affect the padding in the location bar.
    676   if (PageActionVisibleCount() && !ShouldOnlyShowLocation())
    677     gtk_widget_show(page_action_hbox_.get());
    678   else
    679     gtk_widget_hide(page_action_hbox_.get());
    680 }
    681 
    682 void LocationBarViewGtk::InvalidatePageActions() {
    683   size_t count_before = page_action_views_.size();
    684   page_action_views_.reset();
    685   if (page_action_views_.size() != count_before) {
    686     NotificationService::current()->Notify(
    687         NotificationType::EXTENSION_PAGE_ACTION_COUNT_CHANGED,
    688         Source<LocationBar>(this),
    689         NotificationService::NoDetails());
    690   }
    691 }
    692 
    693 void LocationBarViewGtk::SaveStateToContents(TabContents* contents) {
    694   location_entry_->SaveStateToTab(contents);
    695 }
    696 
    697 void LocationBarViewGtk::Revert() {
    698   location_entry_->RevertAll();
    699 }
    700 
    701 const AutocompleteEditView* LocationBarViewGtk::location_entry() const {
    702   return location_entry_.get();
    703 }
    704 
    705 AutocompleteEditView* LocationBarViewGtk::location_entry() {
    706   return location_entry_.get();
    707 }
    708 
    709 LocationBarTesting* LocationBarViewGtk::GetLocationBarForTesting() {
    710   return this;
    711 }
    712 
    713 int LocationBarViewGtk::PageActionCount() {
    714   return page_action_views_.size();
    715 }
    716 
    717 int LocationBarViewGtk::PageActionVisibleCount() {
    718   int count = 0;
    719   gtk_container_foreach(GTK_CONTAINER(page_action_hbox_.get()),
    720                         CountVisibleWidgets, &count);
    721   return count;
    722 }
    723 
    724 ExtensionAction* LocationBarViewGtk::GetPageAction(size_t index) {
    725   if (index >= page_action_views_.size()) {
    726     NOTREACHED();
    727     return NULL;
    728   }
    729 
    730   return page_action_views_[index]->page_action();
    731 }
    732 
    733 ExtensionAction* LocationBarViewGtk::GetVisiblePageAction(size_t index) {
    734   size_t visible_index = 0;
    735   for (size_t i = 0; i < page_action_views_.size(); ++i) {
    736     if (page_action_views_[i]->IsVisible()) {
    737       if (index == visible_index++)
    738         return page_action_views_[i]->page_action();
    739     }
    740   }
    741 
    742   NOTREACHED();
    743   return NULL;
    744 }
    745 
    746 void LocationBarViewGtk::TestPageActionPressed(size_t index) {
    747   if (index >= page_action_views_.size()) {
    748     NOTREACHED();
    749     return;
    750   }
    751 
    752   page_action_views_[index]->TestActivatePageAction();
    753 }
    754 
    755 void LocationBarViewGtk::Observe(NotificationType type,
    756                                  const NotificationSource& source,
    757                                  const NotificationDetails& details) {
    758   if (type.value == NotificationType::PREF_CHANGED) {
    759     UpdateStarIcon();
    760     return;
    761   }
    762 
    763   DCHECK_EQ(type.value, NotificationType::BROWSER_THEME_CHANGED);
    764 
    765   if (theme_service_->UseGtkTheme()) {
    766     gtk_widget_modify_bg(tab_to_search_box_, GTK_STATE_NORMAL, NULL);
    767 
    768     GdkColor border_color = theme_service_->GetGdkColor(
    769         ThemeService::COLOR_FRAME);
    770     gtk_util::SetRoundedWindowBorderColor(tab_to_search_box_, border_color);
    771 
    772     gtk_util::SetLabelColor(tab_to_search_full_label_, NULL);
    773     gtk_util::SetLabelColor(tab_to_search_partial_label_, NULL);
    774     gtk_util::SetLabelColor(tab_to_search_hint_leading_label_, NULL);
    775     gtk_util::SetLabelColor(tab_to_search_hint_trailing_label_, NULL);
    776 
    777     gtk_util::UndoForceFontSize(security_info_label_);
    778     gtk_util::UndoForceFontSize(tab_to_search_full_label_);
    779     gtk_util::UndoForceFontSize(tab_to_search_partial_label_);
    780     gtk_util::UndoForceFontSize(tab_to_search_hint_leading_label_);
    781     gtk_util::UndoForceFontSize(tab_to_search_hint_trailing_label_);
    782 
    783     gtk_alignment_set_padding(GTK_ALIGNMENT(location_entry_alignment_),
    784                               0, 0, 0, 0);
    785     gtk_alignment_set_padding(GTK_ALIGNMENT(tab_to_search_alignment_),
    786                               1, 1, 1, 0);
    787     gtk_alignment_set_padding(GTK_ALIGNMENT(site_type_alignment_),
    788                               1, 1, 1, 0);
    789   } else {
    790     gtk_widget_modify_bg(tab_to_search_box_, GTK_STATE_NORMAL,
    791                          &kKeywordBackgroundColor);
    792     gtk_util::SetRoundedWindowBorderColor(tab_to_search_box_,
    793                                           kKeywordBorderColor);
    794 
    795     gtk_util::SetLabelColor(tab_to_search_full_label_, &gtk_util::kGdkBlack);
    796     gtk_util::SetLabelColor(tab_to_search_partial_label_, &gtk_util::kGdkBlack);
    797     gtk_util::SetLabelColor(tab_to_search_hint_leading_label_,
    798                             &kHintTextColor);
    799     gtk_util::SetLabelColor(tab_to_search_hint_trailing_label_,
    800                             &kHintTextColor);
    801 
    802     // Until we switch to vector graphics, force the font size of labels.
    803     // 12.1px = 9pt @ 96dpi
    804     gtk_util::ForceFontSizePixels(security_info_label_, 12.1);
    805     gtk_util::ForceFontSizePixels(tab_to_search_full_label_,
    806         browser_defaults::kAutocompleteEditFontPixelSize);
    807     gtk_util::ForceFontSizePixels(tab_to_search_partial_label_,
    808         browser_defaults::kAutocompleteEditFontPixelSize);
    809     gtk_util::ForceFontSizePixels(tab_to_search_hint_leading_label_,
    810         browser_defaults::kAutocompleteEditFontPixelSize);
    811     gtk_util::ForceFontSizePixels(tab_to_search_hint_trailing_label_,
    812         browser_defaults::kAutocompleteEditFontPixelSize);
    813 
    814     const int top_bottom = popup_window_mode_ ? kBorderThickness : 0;
    815     gtk_alignment_set_padding(GTK_ALIGNMENT(location_entry_alignment_),
    816                               kTopMargin + kBorderThickness,
    817                               kBottomMargin + kBorderThickness,
    818                               top_bottom, top_bottom);
    819     gtk_alignment_set_padding(GTK_ALIGNMENT(tab_to_search_alignment_),
    820                               1, 1, 0, 0);
    821     gtk_alignment_set_padding(GTK_ALIGNMENT(site_type_alignment_),
    822                               1, 1, 0, 0);
    823   }
    824 
    825   UpdateStarIcon();
    826   UpdateSiteTypeArea();
    827   UpdateContentSettingsIcons();
    828 }
    829 
    830 gboolean LocationBarViewGtk::HandleExpose(GtkWidget* widget,
    831                                           GdkEventExpose* event) {
    832   // If we're not using GTK theming, draw our own border over the edge pixels
    833   // of the background.
    834   if (!profile_ ||
    835       !GtkThemeService::GetFrom(profile_)->UseGtkTheme()) {
    836     int left, center, right;
    837     if (popup_window_mode_) {
    838       left = right = IDR_LOCATIONBG_POPUPMODE_EDGE;
    839       center = IDR_LOCATIONBG_POPUPMODE_CENTER;
    840     } else {
    841       left = IDR_LOCATIONBG_L;
    842       center = IDR_LOCATIONBG_C;
    843       right = IDR_LOCATIONBG_R;
    844     }
    845 
    846     NineBox background(left, center, right,
    847                        0, 0, 0, 0, 0, 0);
    848     background.RenderToWidget(widget);
    849   }
    850 
    851   return FALSE;  // Continue propagating the expose.
    852 }
    853 
    854 void LocationBarViewGtk::UpdateSiteTypeArea() {
    855   // The icon is always visible except when the |tab_to_search_alignment_| is
    856   // visible.
    857   if (!location_entry_->model()->keyword().empty() &&
    858       !location_entry_->model()->is_keyword_hint()) {
    859     gtk_widget_hide(site_type_area());
    860     return;
    861   }
    862 
    863   int resource_id = location_entry_->GetIcon();
    864   gtk_image_set_from_pixbuf(GTK_IMAGE(location_icon_image_),
    865                             theme_service_->GetPixbufNamed(resource_id));
    866 
    867   if (toolbar_model_->GetSecurityLevel() == ToolbarModel::EV_SECURE) {
    868     if (!gtk_util::IsActingAsRoundedWindow(site_type_event_box_)) {
    869       // Fun fact: If wee try to make |site_type_event_box_| act as a
    870       // rounded window while it doesn't have a visible window, GTK interprets
    871       // this as a sign that it should paint the skyline texture into the
    872       // omnibox.
    873       gtk_event_box_set_visible_window(GTK_EVENT_BOX(site_type_event_box_),
    874                                        TRUE);
    875 
    876       gtk_util::ActAsRoundedWindow(site_type_event_box_,
    877                                    kEvSecureBorderColor,
    878                                    kCornerSize,
    879                                    gtk_util::ROUNDED_ALL,
    880                                    gtk_util::BORDER_ALL);
    881     }
    882 
    883     std::wstring info_text = toolbar_model_->GetEVCertName();
    884     gtk_label_set_text(GTK_LABEL(security_info_label_),
    885                        WideToUTF8(info_text).c_str());
    886 
    887     UpdateEVCertificateLabelSize();
    888 
    889     gtk_widget_show(GTK_WIDGET(security_info_label_));
    890   } else {
    891     if (gtk_util::IsActingAsRoundedWindow(site_type_event_box_)) {
    892       gtk_util::StopActingAsRoundedWindow(site_type_event_box_);
    893 
    894       gtk_event_box_set_visible_window(GTK_EVENT_BOX(site_type_event_box_),
    895                                        FALSE);
    896     }
    897 
    898     gtk_widget_hide(GTK_WIDGET(security_info_label_));
    899   }
    900 
    901   if (location_entry()->IsEditingOrEmpty()) {
    902     // Do not show the tooltip if the user has been editing the location
    903     // bar, or the location bar is at the NTP.
    904     gtk_widget_set_tooltip_text(location_icon_image_, "");
    905   } else {
    906     gtk_widget_set_tooltip_text(location_icon_image_,
    907         l10n_util::GetStringUTF8(IDS_TOOLTIP_LOCATION_ICON).c_str());
    908   }
    909 
    910   gtk_widget_show(site_type_area());
    911 
    912   SetSiteTypeDragSource();
    913 }
    914 
    915 void LocationBarViewGtk::UpdateEVCertificateLabelSize() {
    916   // Figure out the width of the average character.
    917   PangoLayout* layout = gtk_label_get_layout(GTK_LABEL(security_info_label_));
    918   PangoContext* context = pango_layout_get_context(layout);
    919   PangoFontMetrics* metrics = pango_context_get_metrics(
    920       context,
    921       gtk_widget_get_style(security_info_label_)->font_desc,
    922       pango_context_get_language(context));
    923   int char_width =
    924       pango_font_metrics_get_approximate_char_width(metrics) / PANGO_SCALE;
    925 
    926   // The EV label should never take up more than half the hbox. We try to
    927   // correct our inaccurate measurement units ("the average character width")
    928   // by dividing more than an even 2.
    929   int text_area = security_info_label_->allocation.width +
    930                   entry_box_->allocation.width;
    931   int max_chars = static_cast<int>(static_cast<float>(text_area) /
    932                                    static_cast<float>(char_width) / 2.75);
    933   // Don't let the label be smaller than 10 characters so that the country
    934   // code is always visible.
    935   gtk_label_set_max_width_chars(GTK_LABEL(security_info_label_),
    936                                 std::max(10, max_chars));
    937 
    938   pango_font_metrics_unref(metrics);
    939 }
    940 
    941 void LocationBarViewGtk::SetKeywordLabel(const string16& keyword) {
    942   if (keyword.empty())
    943     return;
    944 
    945   DCHECK(profile_);
    946   if (!profile_->GetTemplateURLModel())
    947     return;
    948 
    949   bool is_extension_keyword;
    950   const string16 short_name = profile_->GetTemplateURLModel()->
    951       GetKeywordShortName(keyword, &is_extension_keyword);
    952   int message_id = is_extension_keyword ?
    953       IDS_OMNIBOX_EXTENSION_KEYWORD_TEXT : IDS_OMNIBOX_KEYWORD_TEXT;
    954   string16 full_name = l10n_util::GetStringFUTF16(message_id,
    955                                                   short_name);
    956   string16 partial_name = l10n_util::GetStringFUTF16(
    957       message_id,
    958       WideToUTF16Hack(
    959           location_bar_util::CalculateMinString(UTF16ToWideHack(short_name))));
    960   gtk_label_set_text(GTK_LABEL(tab_to_search_full_label_),
    961                      UTF16ToUTF8(full_name).c_str());
    962   gtk_label_set_text(GTK_LABEL(tab_to_search_partial_label_),
    963                      UTF16ToUTF8(partial_name).c_str());
    964 
    965   if (last_keyword_ != keyword) {
    966     last_keyword_ = keyword;
    967 
    968     if (is_extension_keyword) {
    969       const TemplateURL* template_url =
    970           profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword);
    971       const SkBitmap& bitmap = profile_->GetExtensionService()->
    972           GetOmniboxIcon(template_url->GetExtensionId());
    973       GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&bitmap);
    974       gtk_image_set_from_pixbuf(GTK_IMAGE(tab_to_search_magnifier_), pixbuf);
    975       g_object_unref(pixbuf);
    976     } else {
    977       ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    978       gtk_image_set_from_pixbuf(GTK_IMAGE(tab_to_search_magnifier_),
    979                                 rb.GetPixbufNamed(IDR_OMNIBOX_SEARCH));
    980     }
    981   }
    982 }
    983 
    984 void LocationBarViewGtk::SetKeywordHintLabel(const string16& keyword) {
    985   if (keyword.empty())
    986     return;
    987 
    988   DCHECK(profile_);
    989   if (!profile_->GetTemplateURLModel())
    990     return;
    991 
    992   bool is_extension_keyword;
    993   const string16 short_name = profile_->GetTemplateURLModel()->
    994       GetKeywordShortName(keyword, &is_extension_keyword);
    995   int message_id = is_extension_keyword ?
    996       IDS_OMNIBOX_EXTENSION_KEYWORD_HINT : IDS_OMNIBOX_KEYWORD_HINT;
    997   std::vector<size_t> content_param_offsets;
    998   const string16 keyword_hint = l10n_util::GetStringFUTF16(
    999       message_id,
   1000       string16(),
   1001       short_name,
   1002       &content_param_offsets);
   1003   if (content_param_offsets.size() != 2) {
   1004     // See comments on an identical NOTREACHED() in search_provider.cc.
   1005     NOTREACHED();
   1006     return;
   1007   }
   1008 
   1009   std::string leading(UTF16ToUTF8(
   1010       keyword_hint.substr(0, content_param_offsets.front())));
   1011   std::string trailing(UTF16ToUTF8(
   1012       keyword_hint.substr(content_param_offsets.front())));
   1013   gtk_label_set_text(GTK_LABEL(tab_to_search_hint_leading_label_),
   1014                      leading.c_str());
   1015   gtk_label_set_text(GTK_LABEL(tab_to_search_hint_trailing_label_),
   1016                      trailing.c_str());
   1017 }
   1018 
   1019 void LocationBarViewGtk::ShowFirstRunBubbleInternal(
   1020     FirstRun::BubbleType bubble_type) {
   1021   if (!location_entry_.get() || !widget()->window)
   1022     return;
   1023 
   1024   gfx::Rect bounds = gtk_util::WidgetBounds(location_icon_image_);
   1025   bounds.set_x(bounds.x() + kFirstRunBubbleLeftSpacing);
   1026 
   1027   FirstRunBubble::Show(profile_, location_icon_image_, bounds, bubble_type);
   1028 }
   1029 
   1030 gboolean LocationBarViewGtk::OnIconReleased(GtkWidget* sender,
   1031                                             GdkEventButton* event) {
   1032   TabContents* tab = GetTabContents();
   1033 
   1034   if (event->button == 1) {
   1035     // Do not show page info if the user has been editing the location
   1036     // bar, or the location bar is at the NTP.
   1037     if (location_entry()->IsEditingOrEmpty())
   1038       return FALSE;
   1039 
   1040     // (0,0) event coordinates indicates that the release came at the end of
   1041     // a drag.
   1042     if (event->x == 0 && event->y == 0)
   1043       return FALSE;
   1044 
   1045     NavigationEntry* nav_entry = tab->controller().GetActiveEntry();
   1046     if (!nav_entry) {
   1047       NOTREACHED();
   1048       return FALSE;
   1049     }
   1050     tab->ShowPageInfo(nav_entry->url(), nav_entry->ssl(), true);
   1051     return TRUE;
   1052   } else if (event->button == 2) {
   1053     // When the user middle clicks on the location icon, try to open the
   1054     // contents of the PRIMARY selection in the current tab.
   1055     // If the click was outside our bounds, do nothing.
   1056     if (!gtk_util::WidgetBounds(sender).Contains(
   1057             gfx::Point(event->x, event->y))) {
   1058       return FALSE;
   1059     }
   1060 
   1061     GURL url;
   1062     if (!gtk_util::URLFromPrimarySelection(profile_, &url))
   1063       return FALSE;
   1064 
   1065     tab->OpenURL(url, GURL(), CURRENT_TAB, PageTransition::TYPED);
   1066     return TRUE;
   1067   }
   1068 
   1069   return FALSE;
   1070 }
   1071 
   1072 void LocationBarViewGtk::OnIconDragData(GtkWidget* sender,
   1073                                         GdkDragContext* context,
   1074                                         GtkSelectionData* data,
   1075                                         guint info, guint time) {
   1076   TabContents* tab = GetTabContents();
   1077   if (!tab)
   1078     return;
   1079   ui::WriteURLWithName(data, tab->GetURL(), tab->GetTitle(), info);
   1080 }
   1081 
   1082 void LocationBarViewGtk::OnIconDragBegin(GtkWidget* sender,
   1083                                          GdkDragContext* context) {
   1084   SkBitmap favicon = GetFavicon();
   1085   GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&favicon);
   1086   if (!pixbuf)
   1087     return;
   1088   drag_icon_ = bookmark_utils::GetDragRepresentation(pixbuf,
   1089       GetTitle(), theme_service_);
   1090   g_object_unref(pixbuf);
   1091   gtk_drag_set_icon_widget(context, drag_icon_, 0, 0);
   1092 }
   1093 
   1094 void LocationBarViewGtk::OnIconDragEnd(GtkWidget* sender,
   1095                                        GdkDragContext* context) {
   1096   DCHECK(drag_icon_);
   1097   gtk_widget_destroy(drag_icon_);
   1098   drag_icon_ = NULL;
   1099 }
   1100 
   1101 void LocationBarViewGtk::OnHboxSizeAllocate(GtkWidget* sender,
   1102                                             GtkAllocation* allocation) {
   1103   if (hbox_width_ != allocation->width) {
   1104     hbox_width_ = allocation->width;
   1105     UpdateEVCertificateLabelSize();
   1106   }
   1107 }
   1108 
   1109 void LocationBarViewGtk::OnEntryBoxSizeAllocate(GtkWidget* sender,
   1110                                                 GtkAllocation* allocation) {
   1111   if (entry_box_width_ != allocation->width) {
   1112     entry_box_width_ = allocation->width;
   1113     AdjustChildrenVisibility();
   1114   }
   1115 }
   1116 
   1117 gboolean LocationBarViewGtk::OnStarButtonPress(GtkWidget* widget,
   1118                                                GdkEventButton* event) {
   1119   browser_->ExecuteCommand(IDC_BOOKMARK_PAGE);
   1120   return FALSE;
   1121 }
   1122 
   1123 void LocationBarViewGtk::ShowStarBubble(const GURL& url,
   1124                                         bool newly_bookmarked) {
   1125   if (!star_.get())
   1126     return;
   1127 
   1128   BookmarkBubbleGtk::Show(star_.get(), profile_, url, newly_bookmarked);
   1129 }
   1130 
   1131 void LocationBarViewGtk::SetStarred(bool starred) {
   1132   if (starred == starred_)
   1133     return;
   1134 
   1135   starred_ = starred;
   1136   UpdateStarIcon();
   1137 }
   1138 
   1139 void LocationBarViewGtk::UpdateStarIcon() {
   1140   if (!star_.get())
   1141     return;
   1142   bool star_enabled = !toolbar_model_->input_in_progress() &&
   1143                       edit_bookmarks_enabled_.GetValue();
   1144   command_updater_->UpdateCommandEnabled(IDC_BOOKMARK_PAGE, star_enabled);
   1145   if (star_enabled) {
   1146     gtk_widget_show_all(star_.get());
   1147     gtk_image_set_from_pixbuf(GTK_IMAGE(star_image_),
   1148         theme_service_->GetPixbufNamed(
   1149             starred_ ? IDR_STAR_LIT : IDR_STAR));
   1150   } else {
   1151     gtk_widget_hide_all(star_.get());
   1152   }
   1153 }
   1154 
   1155 bool LocationBarViewGtk::ShouldOnlyShowLocation() {
   1156   return browser_->type() != Browser::TYPE_NORMAL;
   1157 }
   1158 
   1159 void LocationBarViewGtk::AdjustChildrenVisibility() {
   1160   int text_width = location_entry_->TextWidth();
   1161   int available_width = entry_box_width_ - text_width - kInnerPadding;
   1162 
   1163   // Only one of |tab_to_search_alignment_| and |tab_to_search_hint_| can be
   1164   // visible at the same time.
   1165   if (!show_selected_keyword_ && GTK_WIDGET_VISIBLE(tab_to_search_alignment_))
   1166     gtk_widget_hide(tab_to_search_alignment_);
   1167   else if (!show_keyword_hint_ && GTK_WIDGET_VISIBLE(tab_to_search_hint_))
   1168     gtk_widget_hide(tab_to_search_hint_);
   1169 
   1170   if (show_selected_keyword_) {
   1171     GtkRequisition box, full_label, partial_label;
   1172     gtk_widget_size_request(tab_to_search_box_, &box);
   1173     gtk_widget_size_request(tab_to_search_full_label_, &full_label);
   1174     gtk_widget_size_request(tab_to_search_partial_label_, &partial_label);
   1175     int full_partial_width_diff = full_label.width - partial_label.width;
   1176     int full_box_width;
   1177     int partial_box_width;
   1178     if (GTK_WIDGET_VISIBLE(tab_to_search_full_label_)) {
   1179       full_box_width = box.width;
   1180       partial_box_width = full_box_width - full_partial_width_diff;
   1181     } else {
   1182       partial_box_width = box.width;
   1183       full_box_width = partial_box_width + full_partial_width_diff;
   1184     }
   1185 
   1186     if (partial_box_width >= entry_box_width_ - kInnerPadding) {
   1187       gtk_widget_hide(tab_to_search_alignment_);
   1188     } else if (full_box_width >= available_width) {
   1189       gtk_widget_hide(tab_to_search_full_label_);
   1190       gtk_widget_show(tab_to_search_partial_label_);
   1191       gtk_widget_show(tab_to_search_alignment_);
   1192     } else if (full_box_width < available_width) {
   1193       gtk_widget_hide(tab_to_search_partial_label_);
   1194       gtk_widget_show(tab_to_search_full_label_);
   1195       gtk_widget_show(tab_to_search_alignment_);
   1196     }
   1197   } else if (show_keyword_hint_) {
   1198     GtkRequisition leading, icon, trailing;
   1199     gtk_widget_size_request(tab_to_search_hint_leading_label_, &leading);
   1200     gtk_widget_size_request(tab_to_search_hint_icon_, &icon);
   1201     gtk_widget_size_request(tab_to_search_hint_trailing_label_, &trailing);
   1202     int full_width = leading.width + icon.width + trailing.width;
   1203 
   1204     if (icon.width >= entry_box_width_ - kInnerPadding) {
   1205       gtk_widget_hide(tab_to_search_hint_);
   1206     } else if (full_width >= available_width) {
   1207       gtk_widget_hide(tab_to_search_hint_leading_label_);
   1208       gtk_widget_hide(tab_to_search_hint_trailing_label_);
   1209       gtk_widget_show(tab_to_search_hint_);
   1210     } else if (full_width < available_width) {
   1211       gtk_widget_show(tab_to_search_hint_leading_label_);
   1212       gtk_widget_show(tab_to_search_hint_trailing_label_);
   1213       gtk_widget_show(tab_to_search_hint_);
   1214     }
   1215   }
   1216 }
   1217 
   1218 ////////////////////////////////////////////////////////////////////////////////
   1219 // LocationBarViewGtk::ContentSettingImageViewGtk
   1220 LocationBarViewGtk::ContentSettingImageViewGtk::ContentSettingImageViewGtk(
   1221     ContentSettingsType content_type,
   1222     const LocationBarViewGtk* parent,
   1223     Profile* profile)
   1224     : content_setting_image_model_(
   1225           ContentSettingImageModel::CreateContentSettingImageModel(
   1226               content_type)),
   1227       alignment_(gtk_alignment_new(0, 0, 1, 1)),
   1228       event_box_(gtk_event_box_new()),
   1229       hbox_(gtk_hbox_new(FALSE, kInnerPadding)),
   1230       image_(gtk_image_new()),
   1231       label_(gtk_label_new(NULL)),
   1232       parent_(parent),
   1233       profile_(profile),
   1234       info_bubble_(NULL),
   1235       animation_(this),
   1236       method_factory_(this) {
   1237   gtk_alignment_set_padding(GTK_ALIGNMENT(alignment_.get()), 1, 1, 0, 0);
   1238   gtk_container_add(GTK_CONTAINER(alignment_.get()), event_box_.get());
   1239 
   1240   // Make the event box not visible so it does not paint a background.
   1241   gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box_.get()), FALSE);
   1242   g_signal_connect(event_box_.get(), "button-press-event",
   1243                    G_CALLBACK(&OnButtonPressedThunk), this);
   1244   g_signal_connect(event_box_.get(), "expose-event",
   1245                    G_CALLBACK(&OnExposeThunk), this);
   1246 
   1247   gtk_widget_set_no_show_all(label_.get(), TRUE);
   1248   gtk_label_set_line_wrap(GTK_LABEL(label_.get()), FALSE);
   1249 
   1250   gtk_box_pack_start(GTK_BOX(hbox_), image_.get(), FALSE, FALSE, 0);
   1251   gtk_box_pack_start(GTK_BOX(hbox_), label_.get(), FALSE, FALSE, 0);
   1252 
   1253   // The +1 accounts for the pixel that is devoted to drawing the border.
   1254   gtk_container_set_border_width(GTK_CONTAINER(hbox_), kHboxBorder + 1);
   1255 
   1256   gtk_container_add(GTK_CONTAINER(event_box_.get()), hbox_);
   1257   gtk_widget_hide(widget());
   1258 
   1259   animation_.SetSlideDuration(kContentSettingImageAnimationTime);
   1260 }
   1261 
   1262 LocationBarViewGtk::ContentSettingImageViewGtk::~ContentSettingImageViewGtk() {
   1263   image_.Destroy();
   1264   label_.Destroy();
   1265   event_box_.Destroy();
   1266   alignment_.Destroy();
   1267 
   1268   if (info_bubble_)
   1269     info_bubble_->Close();
   1270 }
   1271 
   1272 void LocationBarViewGtk::ContentSettingImageViewGtk::UpdateFromTabContents(
   1273     TabContents* tab_contents) {
   1274   content_setting_image_model_->UpdateFromTabContents(tab_contents);
   1275   if (!content_setting_image_model_->is_visible()) {
   1276     gtk_widget_hide(widget());
   1277     return;
   1278   }
   1279 
   1280   gtk_image_set_from_pixbuf(GTK_IMAGE(image_.get()),
   1281       GtkThemeService::GetFrom(profile_)->GetPixbufNamed(
   1282           content_setting_image_model_->get_icon()));
   1283 
   1284   gtk_widget_set_tooltip_text(widget(),
   1285       content_setting_image_model_->get_tooltip().c_str());
   1286   gtk_widget_show_all(widget());
   1287 
   1288   TabSpecificContentSettings* content_settings = tab_contents ?
   1289       tab_contents->GetTabSpecificContentSettings() : NULL;
   1290   if (!content_settings || content_settings->IsBlockageIndicated(
   1291       content_setting_image_model_->get_content_settings_type()))
   1292     return;
   1293 
   1294   // The content blockage was not yet indicated to the user. Start indication
   1295   // animation and clear "not yet shown" flag.
   1296   content_settings->SetBlockageHasBeenIndicated(
   1297       content_setting_image_model_->get_content_settings_type());
   1298 
   1299   int label_string_id =
   1300       content_setting_image_model_->explanatory_string_id();
   1301   // Check if the animation is enabled and if the string for animation is
   1302   // available. If there's no string for the content type, we don't animate.
   1303   if (CommandLine::ForCurrentProcess()->HasSwitch(
   1304       switches::kDisableBlockContentAnimation) || !label_string_id)
   1305     return;
   1306 
   1307   gtk_label_set_text(GTK_LABEL(label_.get()),
   1308       l10n_util::GetStringUTF8(label_string_id).c_str());
   1309   StartAnimating();
   1310 }
   1311 
   1312 void LocationBarViewGtk::ContentSettingImageViewGtk::StartAnimating() {
   1313   if (animation_.IsShowing() || animation_.IsClosing())
   1314     return;
   1315 
   1316   gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box_.get()), TRUE);
   1317   gtk_util::ActAsRoundedWindow(event_box_.get(), kContentSettingBorderColor,
   1318                                kCornerSize,
   1319                                gtk_util::ROUNDED_ALL, gtk_util::BORDER_ALL);
   1320 
   1321   gtk_widget_set_size_request(label_.get(), -1, -1);
   1322   gtk_widget_size_request(label_.get(), &label_req_);
   1323   gtk_widget_set_size_request(label_.get(), 0, -1);
   1324   gtk_widget_show(label_.get());
   1325 
   1326   animation_.Show();
   1327 }
   1328 
   1329 void LocationBarViewGtk::ContentSettingImageViewGtk::CloseAnimation() {
   1330   animation_.Hide();
   1331 }
   1332 
   1333 void LocationBarViewGtk::ContentSettingImageViewGtk::AnimationProgressed(
   1334     const ui::Animation* animation) {
   1335   gtk_widget_set_size_request(
   1336       label_.get(),
   1337       animation->GetCurrentValue() * label_req_.width,
   1338       -1);
   1339 }
   1340 
   1341 void LocationBarViewGtk::ContentSettingImageViewGtk::AnimationEnded(
   1342     const ui::Animation* animation) {
   1343   if (animation_.IsShowing()) {
   1344     MessageLoop::current()->PostDelayedTask(FROM_HERE,
   1345         method_factory_.NewRunnableMethod(
   1346             &ContentSettingImageViewGtk::CloseAnimation),
   1347         kContentSettingImageDisplayTime);
   1348   } else {
   1349     gtk_widget_hide(label_.get());
   1350     gtk_util::StopActingAsRoundedWindow(event_box_.get());
   1351     gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box_.get()), FALSE);
   1352   }
   1353 }
   1354 
   1355 void LocationBarViewGtk::ContentSettingImageViewGtk::AnimationCanceled(
   1356     const ui::Animation* animation) {
   1357 }
   1358 
   1359 gboolean LocationBarViewGtk::ContentSettingImageViewGtk::OnButtonPressed(
   1360     GtkWidget* sender, GdkEvent* event) {
   1361   TabContents* tab_contents = parent_->GetTabContents();
   1362   if (!tab_contents)
   1363     return TRUE;
   1364   const ContentSettingsType content_settings_type =
   1365       content_setting_image_model_->get_content_settings_type();
   1366   if (content_settings_type == CONTENT_SETTINGS_TYPE_PRERENDER)
   1367     return TRUE;
   1368   GURL url = tab_contents->GetURL();
   1369   std::wstring display_host;
   1370   net::AppendFormattedHost(url,
   1371       UTF8ToWide(profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)),
   1372       &display_host,
   1373       NULL, NULL);
   1374 
   1375   info_bubble_ = new ContentSettingBubbleGtk(
   1376       sender, this,
   1377       ContentSettingBubbleModel::CreateContentSettingBubbleModel(
   1378           tab_contents, profile_, content_settings_type),
   1379       profile_, tab_contents);
   1380   return TRUE;
   1381 }
   1382 
   1383 gboolean LocationBarViewGtk::ContentSettingImageViewGtk::OnExpose(
   1384     GtkWidget* sender, GdkEventExpose* event) {
   1385   if (!(animation_.IsShowing() || animation_.IsClosing()))
   1386     return FALSE;
   1387 
   1388   const int height = sender->allocation.height;
   1389 
   1390   cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(sender->window));
   1391   gdk_cairo_rectangle(cr, &event->area);
   1392   cairo_clip(cr);
   1393 
   1394   cairo_pattern_t* pattern = cairo_pattern_create_linear(0, 0, 0, height);
   1395 
   1396   cairo_pattern_add_color_stop_rgb(pattern, 0.0,
   1397                                    kContentSettingTopColor[0],
   1398                                    kContentSettingTopColor[1],
   1399                                    kContentSettingTopColor[2]);
   1400   cairo_pattern_add_color_stop_rgb(pattern, 1.0,
   1401                                    kContentSettingBottomColor[0],
   1402                                    kContentSettingBottomColor[1],
   1403                                    kContentSettingBottomColor[2]);
   1404   cairo_set_source(cr, pattern);
   1405   cairo_paint(cr);
   1406   cairo_pattern_destroy(pattern);
   1407   cairo_destroy(cr);
   1408 
   1409   return FALSE;
   1410 }
   1411 
   1412 void LocationBarViewGtk::ContentSettingImageViewGtk::InfoBubbleClosing(
   1413     InfoBubbleGtk* info_bubble,
   1414     bool closed_by_escape) {
   1415   info_bubble_ = NULL;
   1416 }
   1417 
   1418 ////////////////////////////////////////////////////////////////////////////////
   1419 // LocationBarViewGtk::PageActionViewGtk
   1420 
   1421 LocationBarViewGtk::PageActionViewGtk::PageActionViewGtk(
   1422     LocationBarViewGtk* owner, Profile* profile,
   1423     ExtensionAction* page_action)
   1424     : owner_(NULL),
   1425       profile_(profile),
   1426       page_action_(page_action),
   1427       last_icon_pixbuf_(NULL),
   1428       tracker_(this),
   1429       preview_enabled_(false) {
   1430   event_box_.Own(gtk_event_box_new());
   1431   gtk_widget_set_size_request(event_box_.get(),
   1432                               Extension::kPageActionIconMaxSize,
   1433                               Extension::kPageActionIconMaxSize);
   1434 
   1435   // Make the event box not visible so it does not paint a background.
   1436   gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box_.get()), FALSE);
   1437   g_signal_connect(event_box_.get(), "button-press-event",
   1438                    G_CALLBACK(&OnButtonPressedThunk), this);
   1439   g_signal_connect_after(event_box_.get(), "expose-event",
   1440                          G_CALLBACK(OnExposeEventThunk), this);
   1441 
   1442   image_.Own(gtk_image_new());
   1443   gtk_container_add(GTK_CONTAINER(event_box_.get()), image_.get());
   1444 
   1445   const Extension* extension = profile->GetExtensionService()->
   1446       GetExtensionById(page_action->extension_id(), false);
   1447   DCHECK(extension);
   1448 
   1449   // Load all the icons declared in the manifest. This is the contents of the
   1450   // icons array, plus the default_icon property, if any.
   1451   std::vector<std::string> icon_paths(*page_action->icon_paths());
   1452   if (!page_action_->default_icon_path().empty())
   1453     icon_paths.push_back(page_action_->default_icon_path());
   1454 
   1455   for (std::vector<std::string>::iterator iter = icon_paths.begin();
   1456        iter != icon_paths.end(); ++iter) {
   1457     tracker_.LoadImage(extension, extension->GetResource(*iter),
   1458                        gfx::Size(Extension::kPageActionIconMaxSize,
   1459                                  Extension::kPageActionIconMaxSize),
   1460                        ImageLoadingTracker::DONT_CACHE);
   1461   }
   1462 
   1463   // We set the owner last of all so that we can determine whether we are in
   1464   // the process of initializing this class or not.
   1465   owner_ = owner;
   1466 }
   1467 
   1468 LocationBarViewGtk::PageActionViewGtk::~PageActionViewGtk() {
   1469   image_.Destroy();
   1470   event_box_.Destroy();
   1471   for (PixbufMap::iterator iter = pixbufs_.begin(); iter != pixbufs_.end();
   1472        ++iter) {
   1473     g_object_unref(iter->second);
   1474   }
   1475   if (last_icon_pixbuf_)
   1476     g_object_unref(last_icon_pixbuf_);
   1477 }
   1478 
   1479 void LocationBarViewGtk::PageActionViewGtk::UpdateVisibility(
   1480     TabContents* contents, const GURL& url) {
   1481   // Save this off so we can pass it back to the extension when the action gets
   1482   // executed. See PageActionImageView::OnMousePressed.
   1483   current_tab_id_ = contents ? ExtensionTabUtil::GetTabId(contents) : -1;
   1484   current_url_ = url;
   1485 
   1486   bool visible = contents &&
   1487       (preview_enabled_ || page_action_->GetIsVisible(current_tab_id_));
   1488   if (visible) {
   1489     // Set the tooltip.
   1490     gtk_widget_set_tooltip_text(event_box_.get(),
   1491         page_action_->GetTitle(current_tab_id_).c_str());
   1492 
   1493     // Set the image.
   1494     // It can come from three places. In descending order of priority:
   1495     // - The developer can set it dynamically by path or bitmap. It will be in
   1496     //   page_action_->GetIcon().
   1497     // - The developer can set it dyanmically by index. It will be in
   1498     //   page_action_->GetIconIndex().
   1499     // - It can be set in the manifest by path. It will be in page_action_->
   1500     //   default_icon_path().
   1501 
   1502     // First look for a dynamically set bitmap.
   1503     SkBitmap icon = page_action_->GetIcon(current_tab_id_);
   1504     GdkPixbuf* pixbuf = NULL;
   1505     if (!icon.isNull()) {
   1506       if (icon.pixelRef() != last_icon_skbitmap_.pixelRef()) {
   1507         if (last_icon_pixbuf_)
   1508           g_object_unref(last_icon_pixbuf_);
   1509         last_icon_skbitmap_ = icon;
   1510         last_icon_pixbuf_ = gfx::GdkPixbufFromSkBitmap(&icon);
   1511       }
   1512       DCHECK(last_icon_pixbuf_);
   1513       pixbuf = last_icon_pixbuf_;
   1514     } else {
   1515       // Otherwise look for a dynamically set index, or fall back to the
   1516       // default path.
   1517       int icon_index = page_action_->GetIconIndex(current_tab_id_);
   1518       std::string icon_path = (icon_index < 0) ?
   1519           page_action_->default_icon_path() :
   1520           page_action_->icon_paths()->at(icon_index);
   1521       if (!icon_path.empty()) {
   1522         PixbufMap::iterator iter = pixbufs_.find(icon_path);
   1523         if (iter != pixbufs_.end())
   1524           pixbuf = iter->second;
   1525       }
   1526     }
   1527     // The pixbuf might not be loaded yet.
   1528     if (pixbuf)
   1529       gtk_image_set_from_pixbuf(GTK_IMAGE(image_.get()), pixbuf);
   1530   }
   1531 
   1532   bool old_visible = IsVisible();
   1533   if (visible)
   1534     gtk_widget_show_all(event_box_.get());
   1535   else
   1536     gtk_widget_hide_all(event_box_.get());
   1537 
   1538   if (visible != old_visible) {
   1539     NotificationService::current()->Notify(
   1540         NotificationType::EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED,
   1541         Source<ExtensionAction>(page_action_),
   1542         Details<TabContents>(contents));
   1543   }
   1544 }
   1545 
   1546 void LocationBarViewGtk::PageActionViewGtk::OnImageLoaded(
   1547     SkBitmap* image, const ExtensionResource& resource, int index) {
   1548   // We loaded icons()->size() icons, plus one extra if the page action had
   1549   // a default icon.
   1550   int total_icons = static_cast<int>(page_action_->icon_paths()->size());
   1551   if (!page_action_->default_icon_path().empty())
   1552     total_icons++;
   1553   DCHECK(index < total_icons);
   1554 
   1555   // Map the index of the loaded image back to its name. If we ever get an
   1556   // index greater than the number of icons, it must be the default icon.
   1557   if (image) {
   1558     GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(image);
   1559     if (index < static_cast<int>(page_action_->icon_paths()->size()))
   1560       pixbufs_[page_action_->icon_paths()->at(index)] = pixbuf;
   1561     else
   1562       pixbufs_[page_action_->default_icon_path()] = pixbuf;
   1563   }
   1564 
   1565   // If we have no owner, that means this class is still being constructed and
   1566   // we should not UpdatePageActions, since it leads to the PageActions being
   1567   // destroyed again and new ones recreated (causing an infinite loop).
   1568   if (owner_)
   1569     owner_->UpdatePageActions();
   1570 }
   1571 
   1572 void LocationBarViewGtk::PageActionViewGtk::TestActivatePageAction() {
   1573   GdkEventButton event = {};
   1574   event.button = 1;
   1575   OnButtonPressed(widget(), &event);
   1576 }
   1577 
   1578 void LocationBarViewGtk::PageActionViewGtk::InspectPopup(
   1579     ExtensionAction* action) {
   1580   ShowPopup(true);
   1581 }
   1582 
   1583 bool LocationBarViewGtk::PageActionViewGtk::ShowPopup(bool devtools) {
   1584   if (!page_action_->HasPopup(current_tab_id_))
   1585     return false;
   1586 
   1587   ExtensionPopupGtk::Show(
   1588       page_action_->GetPopupUrl(current_tab_id_),
   1589       owner_->browser_,
   1590       event_box_.get(),
   1591       devtools);
   1592   return true;
   1593 }
   1594 
   1595 gboolean LocationBarViewGtk::PageActionViewGtk::OnButtonPressed(
   1596     GtkWidget* sender,
   1597     GdkEventButton* event) {
   1598   if (event->button != 3) {
   1599     if (!ShowPopup(false)) {
   1600       ExtensionService* service = profile_->GetExtensionService();
   1601       service->browser_event_router()->PageActionExecuted(
   1602           profile_,
   1603           page_action_->extension_id(),
   1604           page_action_->id(),
   1605           current_tab_id_,
   1606           current_url_.spec(),
   1607           event->button);
   1608     }
   1609   } else {
   1610     const Extension* extension = profile_->GetExtensionService()->
   1611         GetExtensionById(page_action()->extension_id(), false);
   1612 
   1613     if (extension->ShowConfigureContextMenus()) {
   1614       context_menu_model_ =
   1615           new ExtensionContextMenuModel(extension, owner_->browser_, this);
   1616       context_menu_.reset(
   1617           new MenuGtk(NULL, context_menu_model_.get()));
   1618       context_menu_->PopupForWidget(sender, event->button, event->time);
   1619     }
   1620   }
   1621 
   1622   return TRUE;
   1623 }
   1624 
   1625 gboolean LocationBarViewGtk::PageActionViewGtk::OnExposeEvent(
   1626     GtkWidget* widget, GdkEventExpose* event) {
   1627   TabContents* contents = owner_->GetTabContents();
   1628   if (!contents)
   1629     return FALSE;
   1630 
   1631   int tab_id = ExtensionTabUtil::GetTabId(contents);
   1632   if (tab_id < 0)
   1633     return FALSE;
   1634 
   1635   std::string badge_text = page_action_->GetBadgeText(tab_id);
   1636   if (badge_text.empty())
   1637     return FALSE;
   1638 
   1639   gfx::CanvasSkiaPaint canvas(event, false);
   1640   gfx::Rect bounding_rect(widget->allocation);
   1641   page_action_->PaintBadge(&canvas, bounding_rect, tab_id);
   1642   return FALSE;
   1643 }
   1644