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