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