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.
5 #include "chrome/browser/ui/gtk/location_bar_view_gtk.h"
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"
98 using content::NavigationEntry;
99 using content::OpenURLParams;
100 using content::WebContents;
101 using extensions::LocationBarController;
102 using extensions::Extension;
106 // We draw a border on the top and bottom (but not on left or right).
107 const int kBorderThickness = 1;
109 const int kPopupEdgeThickness = 1;
110 const int kNormalEdgeThickness = 2;
112 // Spacing needed to align the bubble with the left side of the omnibox.
113 const int kFirstRunBubbleLeftSpacing = 4;
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;
121 // Padding between the elements in the bar.
122 const int kInnerPadding = 2;
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);
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);
133 // Use weak gray for showing search and keyword hint text.
134 const GdkColor kHintTextColor = GDK_COLOR_RGB(0x75, 0x75, 0x75);
136 // Size of the rounding of the "Search site for:" box.
137 const int kCornerSize = 3;
139 // Default page tool animation time (open and close). In ms.
140 const int kPageToolAnimationTime = 150;
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;
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);
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;
161 class ContentSettingImageViewGtk : public LocationBarViewGtk::PageToolViewGtk,
162 public BubbleDelegateGtk {
164 ContentSettingImageViewGtk(ContentSettingsType content_type,
165 LocationBarViewGtk* parent);
166 virtual ~ContentSettingImageViewGtk();
169 virtual void Update(WebContents* web_contents) OVERRIDE;
171 // gfx::AnimationDelegate
172 virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE;
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;
182 virtual void BubbleClosing(BubbleGtk* bubble,
183 bool closed_by_escape) OVERRIDE;
185 // The owning LocationBarViewGtk.
186 LocationBarViewGtk* parent_;
188 scoped_ptr<ContentSettingImageModel> content_setting_image_model_;
190 // The currently shown bubble if any.
191 ContentSettingBubbleGtk* content_setting_bubble_;
193 DISALLOW_COPY_AND_ASSIGN(ContentSettingImageViewGtk);
196 ContentSettingImageViewGtk::ContentSettingImageViewGtk(
197 ContentSettingsType content_type,
198 LocationBarViewGtk* parent)
201 content_setting_image_model_(
202 ContentSettingImageModel::CreateContentSettingImageModel(
204 content_setting_bubble_(NULL) {
205 animation_.SetSlideDuration(kContentSettingImageAnimationTime);
208 ContentSettingImageViewGtk::~ContentSettingImageViewGtk() {
209 if (content_setting_bubble_)
210 content_setting_bubble_->Close();
213 void ContentSettingImageViewGtk::Update(WebContents* web_contents) {
215 content_setting_image_model_->UpdateFromWebContents(web_contents);
217 if (!content_setting_image_model_->is_visible()) {
218 gtk_widget_hide(widget());
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());
226 gtk_widget_set_tooltip_text(widget(),
227 content_setting_image_model_->get_tooltip().c_str());
228 gtk_widget_show_all(widget());
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()))
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());
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)
250 gtk_label_set_text(GTK_LABEL(label_.get()),
251 l10n_util::GetStringUTF8(label_string_id).c_str());
255 void ContentSettingImageViewGtk::AnimationEnded(
256 const gfx::Animation* animation) {
257 if (animation_.IsShowing()) {
258 base::MessageLoop::current()->PostDelayedTask(
260 base::Bind(&ContentSettingImageViewGtk::CloseAnimation,
261 weak_factory_.GetWeakPtr()),
262 base::TimeDelta::FromMilliseconds(kContentSettingImageDisplayTime));
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);
270 GdkColor ContentSettingImageViewGtk::GetButtonBorderColor() const {
271 return kContentSettingBorderColor;
274 GdkColor ContentSettingImageViewGtk::GetGradientTopColor() const {
275 return kContentSettingTopColor;
278 GdkColor ContentSettingImageViewGtk::GetGradientBottomColor() const {
279 return kContentSettingBottomColor;
282 void ContentSettingImageViewGtk::OnClick(
284 WebContents* web_contents = parent_->GetWebContents();
287 Profile* profile = parent_->browser()->profile();
288 content_setting_bubble_ = new ContentSettingBubbleGtk(
290 ContentSettingBubbleModel::CreateContentSettingBubbleModel(
291 parent_->browser()->content_setting_bubble_model_delegate(),
294 content_setting_image_model_->get_content_settings_type()),
299 void ContentSettingImageViewGtk::BubbleClosing(
301 bool closed_by_escape) {
302 content_setting_bubble_ = NULL;
305 gfx::Rect AllocationToRect(const GtkAllocation& allocation) {
306 return gfx::Rect(allocation.x, allocation.y,
307 allocation.width, allocation.height);
312 ////////////////////////////////////////////////////////////////////////////////
313 // LocationBarViewGtk
316 const GdkColor LocationBarViewGtk::kBackgroundColor =
317 GDK_COLOR_RGB(255, 255, 255);
319 LocationBarViewGtk::LocationBarViewGtk(Browser* browser)
320 : OmniboxEditController(browser->command_controller()->command_updater()),
321 LocationBar(browser->profile()),
323 manage_passwords_icon_image_(NULL),
327 site_type_alignment_(NULL),
328 site_type_event_box_(NULL),
329 location_icon_image_(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),
342 popup_window_mode_(false),
343 theme_service_(NULL),
346 show_selected_keyword_(false),
347 show_keyword_hint_(false),
348 weak_ptr_factory_(this) {
351 LocationBarViewGtk::~LocationBarViewGtk() {
352 // All of our widgets should be children of / owned by the alignment.
354 manage_passwords_icon_.Destroy();
357 content_setting_hbox_.Destroy();
358 page_action_hbox_.Destroy();
361 void LocationBarViewGtk::Init(bool popup_window_mode) {
362 popup_window_mode_ = popup_window_mode;
364 theme_service_ = GtkThemeService::GetFrom(profile());
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);
375 // Now initialize the OmniboxViewGtk.
376 omnibox_view_.reset(new OmniboxViewGtk(this, browser_, profile(),
378 popup_window_mode_, hbox_.get()));
379 omnibox_view_->Init();
381 g_signal_connect(hbox_.get(), "expose-event",
382 G_CALLBACK(&HandleExposeThunk), this);
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);
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);
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_,
415 gtk_util::CenterWidgetInHBox(tab_to_search_hbox, tab_to_search_label_hbox,
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,
425 gtk_util::ROUNDED_ALL, gtk_util::BORDER_ALL);
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_),
431 gtk_box_pack_start(GTK_BOX(entry_box_), tab_to_search_alignment_,
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_);
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_,
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_,
459 gtk_box_pack_start(GTK_BOX(tab_to_search_hint_),
460 tab_to_search_hint_icon_,
462 gtk_box_pack_start(GTK_BOX(tab_to_search_hint_),
463 tab_to_search_hint_trailing_label_,
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);
472 if (browser_defaults::bookmarks_enabled && !ShouldOnlyShowLocation()) {
473 // Hide the star icon in popups, app windows, etc.
475 gtk_box_pack_end(GTK_BOX(hbox_.get()), star_.get(), FALSE, FALSE, 0);
479 gtk_box_pack_end(GTK_BOX(hbox_.get()), zoom_.get(), FALSE, FALSE, 0);
481 CreateManagePasswordsIconButton();
482 gtk_box_pack_end(GTK_BOX(hbox_.get()), manage_passwords_icon_.get(), FALSE,
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(),
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);
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(),
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);
513 chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
514 content::Source<ThemeService>(theme_service_));
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)));
523 theme_service_->InitThemesFor(this);
526 void LocationBarViewGtk::SetPreviewEnabledPageAction(
527 ExtensionAction* page_action,
528 bool preview_enabled) {
530 for (ScopedVector<PageActionViewGtk>::iterator iter =
531 page_action_views_.begin(); iter != page_action_views_.end();
533 if ((*iter)->page_action() == page_action) {
534 (*iter)->set_preview_enabled(preview_enabled);
541 GtkWidget* LocationBarViewGtk::GetPageActionWidget(
542 ExtensionAction* page_action) {
544 for (ScopedVector<PageActionViewGtk>::iterator iter =
545 page_action_views_.begin();
546 iter != page_action_views_.end();
548 if ((*iter)->page_action() == page_action)
549 return (*iter)->widget();
554 void LocationBarViewGtk::ShowStarBubble(const GURL& url,
555 bool newly_bookmarked) {
560 BookmarkBubbleGtk::Show(star_.get(), profile(), url, newly_bookmarked);
562 on_star_sized_ = base::Bind(&BookmarkBubbleGtk::Show, star_.get(),
563 profile(), url, newly_bookmarked);
567 void LocationBarViewGtk::ShowManagePasswordsBubble() {
568 if (GetToolbarModel()->input_in_progress() || !GetWebContents())
571 ManagePasswordsBubbleGtk::ShowBubble(GetWebContents());
574 void LocationBarViewGtk::ZoomChangedForActiveTab(bool can_show_bubble) {
577 if (can_show_bubble && gtk_widget_get_visible(zoom_.get()))
581 void LocationBarViewGtk::SetStarred(bool starred) {
582 if (starred == starred_)
589 void LocationBarViewGtk::Update(const WebContents* contents) {
592 UpdateSiteTypeArea();
593 UpdateContentSettingsIcons();
596 omnibox_view_->OnTabChanged(contents);
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
603 gtk_widget_queue_draw(gtk_widget_get_parent(widget()));
605 gtk_widget_queue_draw(widget());
607 ZoomBubbleGtk::CloseBubble();
610 void LocationBarViewGtk::OnChanged() {
611 UpdateSiteTypeArea();
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;
618 if (show_selected_keyword_)
619 SetKeywordLabel(keyword);
621 if (show_keyword_hint_)
622 SetKeywordHintLabel(keyword);
624 AdjustChildrenVisibility();
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);
634 // Update the keyword and search hint states.
638 void LocationBarViewGtk::ShowURL() {
639 omnibox_view_->ShowURL();
642 InstantController* LocationBarViewGtk::GetInstant() {
643 return browser_->instant_controller() ?
644 browser_->instant_controller()->instant() : NULL;
647 WebContents* LocationBarViewGtk::GetWebContents() {
648 return browser_->tab_strip_model()->GetActiveWebContents();
651 ToolbarModel* LocationBarViewGtk::GetToolbarModel() {
652 return browser_->toolbar_model();
655 const ToolbarModel* LocationBarViewGtk::GetToolbarModel() const {
656 return browser_->toolbar_model();
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(
664 base::Bind(&LocationBarViewGtk::ShowFirstRunBubbleInternal,
665 weak_ptr_factory_.GetWeakPtr()));
668 GURL LocationBarViewGtk::GetDestinationURL() const {
669 return destination_url();
672 WindowOpenDisposition LocationBarViewGtk::GetWindowOpenDisposition() const {
673 return disposition();
676 content::PageTransition LocationBarViewGtk::GetPageTransition() const {
680 void LocationBarViewGtk::AcceptInput() {
681 omnibox_view_->model()->AcceptInput(CURRENT_TAB, false);
684 void LocationBarViewGtk::FocusLocation(bool select_all) {
685 omnibox_view_->SetFocus();
687 omnibox_view_->SelectAll(true);
690 void LocationBarViewGtk::FocusSearch() {
691 omnibox_view_->SetFocus();
692 omnibox_view_->SetForcedQuery();
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;
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);
709 void LocationBarViewGtk::UpdateManagePasswordsIconAndBubble() {
710 UpdateManagePasswordsIcon();
713 void LocationBarViewGtk::UpdatePageActions() {
714 std::vector<ExtensionAction*> new_page_actions;
716 WebContents* contents = GetWebContents();
718 LocationBarController* location_bar_controller =
719 extensions::TabHelper::FromWebContents(contents)->
720 location_bar_controller();
721 new_page_actions = location_bar_controller->GetCurrentActions();
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();
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);
736 content::NotificationService::current()->Notify(
737 chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_COUNT_CHANGED,
738 content::Source<LocationBar>(this),
739 content::NotificationService::NoDetails());
742 if (!page_action_views_.empty() && contents) {
743 GURL url = GetWebContents()->GetURL();
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);
749 gtk_widget_queue_draw(hbox_.get());
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());
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());
769 void LocationBarViewGtk::UpdateOpenPDFInReaderPrompt() {
770 // Not implemented on Gtk.
773 void LocationBarViewGtk::UpdateGeneratedCreditCardView() {
777 void LocationBarViewGtk::SaveStateToContents(WebContents* contents) {
778 omnibox_view_->SaveStateToTab(contents);
781 void LocationBarViewGtk::Revert() {
782 omnibox_view_->RevertAll();
785 const OmniboxView* LocationBarViewGtk::GetOmniboxView() const {
786 return omnibox_view_.get();
789 OmniboxView* LocationBarViewGtk::GetOmniboxView() {
790 return omnibox_view_.get();
793 LocationBarTesting* LocationBarViewGtk::GetLocationBarForTesting() {
797 int LocationBarViewGtk::PageActionCount() {
798 return page_action_views_.size();
801 int LocationBarViewGtk::PageActionVisibleCount() {
803 gtk_container_foreach(GTK_CONTAINER(page_action_hbox_.get()),
804 CountVisibleWidgets, &count);
808 ExtensionAction* LocationBarViewGtk::GetPageAction(size_t index) {
809 if (index >= page_action_views_.size()) {
814 return page_action_views_[index]->page_action();
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();
830 void LocationBarViewGtk::TestPageActionPressed(size_t index) {
831 if (index >= page_action_views_.size()) {
836 page_action_views_[index]->TestActivatePageAction();
839 bool LocationBarViewGtk::GetBookmarkStarVisibility() {
843 void LocationBarViewGtk::Observe(int type,
844 const content::NotificationSource& source,
845 const content::NotificationDetails& details) {
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())
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);
859 GdkColor border_color = theme_service_->GetGdkColor(
860 ThemeProperties::COLOR_FRAME);
861 gtk_util::SetRoundedWindowBorderColor(tab_to_search_box_, border_color);
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_);
869 gtk_alignment_set_padding(GTK_ALIGNMENT(omnibox_view_alignment_),
871 gtk_alignment_set_padding(GTK_ALIGNMENT(tab_to_search_alignment_),
873 gtk_alignment_set_padding(GTK_ALIGNMENT(site_type_alignment_),
876 gtk_widget_modify_bg(tab_to_search_box_, GTK_STATE_NORMAL,
877 &kKeywordBackgroundColor);
878 gtk_util::SetRoundedWindowBorderColor(tab_to_search_box_,
879 kKeywordBorderColor);
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);
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_),
899 gtk_alignment_set_padding(GTK_ALIGNMENT(site_type_alignment_),
904 UpdateManagePasswordsIcon();
906 UpdateSiteTypeArea();
907 UpdateContentSettingsIcons();
916 void LocationBarViewGtk::BuildSiteTypeArea() {
917 location_icon_image_ = gtk_image_new();
918 gtk_widget_set_name(location_icon_image_, "chrome-location-icon");
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);
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");
933 GtkWidget* site_type_hbox = gtk_hbox_new(FALSE, 1);
934 gtk_box_pack_start(GTK_BOX(site_type_hbox), icon_alignment,
936 gtk_box_pack_start(GTK_BOX(site_type_hbox), security_info_label_,
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);
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_),
952 gtk_widget_set_name(site_type_event_box_,
953 "chrome-location-icon-eventbox");
954 gtk_container_add(GTK_CONTAINER(site_type_event_box_),
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_,
964 gtk_widget_set_tooltip_text(location_icon_image_,
965 l10n_util::GetStringUTF8(IDS_TOOLTIP_LOCATION_ICON).c_str());
967 g_signal_connect(site_type_event_box_, "button-release-event",
968 G_CALLBACK(&OnIconReleasedThunk), this);
971 void LocationBarViewGtk::SetSiteTypeDragSource() {
972 bool enable = !GetOmniboxView()->IsEditingOrEmpty();
973 if (enable_location_drag_ == enable)
975 enable_location_drag_ = enable;
978 gtk_drag_source_unset(site_type_event_box_);
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_,
987 ui::CHROME_NAMED_URL);
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.
998 gfx::CanvasSkiaPaint canvas(event, /*opaque=*/false);
1000 GtkAllocation allocation;
1001 gtk_widget_get_allocation(widget, &allocation);
1003 int thickness = popup_window_mode_ ?
1004 kPopupEdgeThickness : kNormalEdgeThickness;
1005 gfx::Rect bounds(allocation);
1006 bounds.Inset(thickness, thickness);
1008 const SkColor color = SK_ColorWHITE;
1009 if (popup_window_mode_) {
1010 canvas.FillRect(bounds, color);
1013 paint.setStyle(SkPaint::kFill_Style);
1014 paint.setColor(color);
1015 const int kBorderCornerRadius = 2;
1016 canvas.DrawRoundRect(bounds, kBorderCornerRadius, paint);
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);
1032 NineBox(IDR_TEXTFIELD_TOP_LEFT,
1034 IDR_TEXTFIELD_TOP_RIGHT,
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);
1045 return FALSE; // Continue propagating the expose.
1048 gboolean LocationBarViewGtk::OnIconReleased(GtkWidget* sender,
1049 GdkEventButton* event) {
1050 WebContents* tab = GetWebContents();
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())
1058 // (0,0) event coordinates indicates that the release came at the end of
1060 if (event->x == 0 && event->y == 0)
1063 // Important to use GetVisibleEntry to match what's showing in the omnibox.
1064 NavigationEntry* nav_entry = tab->GetController().GetVisibleEntry();
1069 chrome::ShowWebsiteSettings(browser_, tab, nav_entry->GetURL(),
1070 nav_entry->GetSSL());
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))) {
1082 if (!gtk_util::URLFromPrimarySelection(profile(), &url))
1085 tab->OpenURL(OpenURLParams(
1086 url, content::Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED,
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);
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())
1108 drag_url_ = web_contents->GetURL();
1109 drag_title_ = web_contents->GetTitle();
1110 drag_icon_ = GetDragRepresentation(favicon.ToGdkPixbuf(), drag_title_,
1112 gtk_drag_set_icon_widget(context, drag_icon_, 0, 0);
1115 void LocationBarViewGtk::OnIconDragEnd(GtkWidget* sender,
1116 GdkDragContext* context) {
1118 gtk_widget_destroy(drag_icon_);
1120 drag_url_ = GURL::EmptyGURL();
1121 drag_title_.clear();
1124 void LocationBarViewGtk::OnHboxSizeAllocate(GtkWidget* sender,
1125 GtkAllocation* allocation) {
1126 if (hbox_width_ != allocation->width) {
1127 hbox_width_ = allocation->width;
1128 UpdateEVCertificateLabelSize();
1130 InstantService* instant_service =
1131 InstantServiceFactory::GetForProfile(profile());
1132 if (instant_service) {
1133 instant_service->OnOmniboxStartMarginChanged(
1134 AllocationToRect(*allocation).x());
1138 void LocationBarViewGtk::OnEntryBoxSizeAllocate(GtkWidget* sender,
1139 GtkAllocation* allocation) {
1140 if (entry_box_width_ != allocation->width) {
1141 entry_box_width_ = allocation->width;
1142 AdjustChildrenVisibility();
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
1151 ZoomBubbleGtk::ShowBubble(GetWebContents(), false);
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
1163 ManagePasswordsBubbleGtk::ShowBubble(GetWebContents());
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();
1178 gboolean LocationBarViewGtk::OnStarButtonPress(GtkWidget* widget,
1179 GdkEventButton* event) {
1180 if (event->button != 1)
1182 chrome::ExecuteCommand(browser_, IDC_BOOKMARK_PAGE_FROM_STAR);
1186 void LocationBarViewGtk::UpdateSiteTypeArea() {
1187 // The icon is always visible except when the |tab_to_search_alignment_| is
1189 if (!omnibox_view_->model()->keyword().empty() &&
1190 !omnibox_view_->model()->is_keyword_hint()) {
1191 gtk_widget_hide(site_type_area());
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());
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
1206 gtk_event_box_set_visible_window(GTK_EVENT_BOX(site_type_event_box_),
1209 gtk_util::ActAsRoundedWindow(site_type_event_box_,
1210 kEvSecureBorderColor,
1212 gtk_util::ROUNDED_ALL,
1213 gtk_util::BORDER_ALL);
1216 base::string16 info_text = GetToolbarModel()->GetEVCertName();
1217 gtk_label_set_text(GTK_LABEL(security_info_label_),
1218 base::UTF16ToUTF8(info_text).c_str());
1220 UpdateEVCertificateLabelSize();
1222 gtk_widget_show(GTK_WIDGET(security_info_label_));
1224 if (gtk_util::IsActingAsRoundedWindow(site_type_event_box_)) {
1225 gtk_util::StopActingAsRoundedWindow(site_type_event_box_);
1227 gtk_event_box_set_visible_window(GTK_EVENT_BOX(site_type_event_box_),
1231 gtk_widget_hide(GTK_WIDGET(security_info_label_));
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_, "");
1239 gtk_widget_set_tooltip_text(location_icon_image_,
1240 l10n_util::GetStringUTF8(IDS_TOOLTIP_LOCATION_ICON).c_str());
1243 gtk_widget_show(site_type_area());
1245 SetSiteTypeDragSource();
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(
1254 gtk_widget_get_style(security_info_label_)->font_desc,
1255 pango_context_get_language(context));
1257 pango_font_metrics_get_approximate_char_width(metrics) / PANGO_SCALE;
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));
1275 pango_font_metrics_unref(metrics);
1278 void LocationBarViewGtk::SetKeywordLabel(const base::string16& keyword) {
1279 if (keyword.empty())
1282 TemplateURLService* template_url_service =
1283 TemplateURLServiceFactory::GetForProfile(profile());
1284 if (!template_url_service)
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 ?
1294 l10n_util::GetStringFUTF16(IDS_OMNIBOX_KEYWORD_TEXT, short_name);
1295 const base::string16 partial_name = is_extension_keyword ?
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());
1303 if (last_keyword_ != keyword) {
1304 last_keyword_ = keyword;
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());
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());
1321 void LocationBarViewGtk::SetKeywordHintLabel(const base::string16& keyword) {
1322 if (keyword.empty())
1325 TemplateURLService* template_url_service =
1326 TemplateURLServiceFactory::GetForProfile(profile());
1327 if (!template_url_service)
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(
1340 &content_param_offsets);
1341 if (content_param_offsets.size() != 2) {
1342 // See comments on an identical NOTREACHED() in search_provider.cc.
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_),
1353 gtk_label_set_text(GTK_LABEL(tab_to_search_hint_trailing_label_),
1357 void LocationBarViewGtk::ShowFirstRunBubbleInternal() {
1358 if (!omnibox_view_.get() || !gtk_widget_get_window(widget()))
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);
1366 void LocationBarViewGtk::ShowZoomBubble() {
1367 if (GetToolbarModel()->input_in_progress() || !GetWebContents())
1370 ZoomBubbleGtk::ShowBubble(GetWebContents(), true);
1373 void LocationBarViewGtk::AdjustChildrenVisibility() {
1374 int text_width = omnibox_view_->GetTextWidth();
1375 int available_width = entry_box_width_ - text_width - kInnerPadding;
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_);
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;
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;
1399 partial_box_width = box.width;
1400 full_box_width = partial_box_width + full_partial_width_diff;
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_);
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;
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_);
1435 GtkWidget* LocationBarViewGtk::CreateIconButton(
1440 gboolean (click_callback)(GtkWidget*, GdkEventButton*, gpointer)) {
1442 gtk_image_new_from_pixbuf(
1443 theme_service_->GetImageNamed(image_id).ToGdkPixbuf()) :
1446 GtkWidget* alignment = gtk_alignment_new(0, 0, 1, 1);
1447 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0,
1449 gtk_container_add(GTK_CONTAINER(alignment), *image);
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);
1456 if (debug_id != VIEW_ID_NONE)
1457 ViewIDUtil::SetID(result, debug_id);
1460 gtk_widget_set_tooltip_text(result,
1461 l10n_util::GetStringUTF8(tooltip_id).c_str());
1464 g_signal_connect(result, "button-press-event",
1465 G_CALLBACK(click_callback), this);
1470 void LocationBarViewGtk::CreateZoomButton() {
1471 zoom_.Own(CreateIconButton(&zoom_image_,
1473 VIEW_ID_ZOOM_BUTTON,
1475 OnZoomButtonPressThunk));
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));
1484 void LocationBarViewGtk::CreateStarButton() {
1485 star_.Own(CreateIconButton(&star_image_,
1487 VIEW_ID_STAR_BUTTON,
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);
1496 void LocationBarViewGtk::UpdateZoomIcon() {
1497 WebContents* web_contents = GetWebContents();
1498 if (!zoom_.get() || !web_contents)
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();
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());
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());
1518 gtk_widget_show(zoom_.get());
1521 void LocationBarViewGtk::UpdateManagePasswordsIcon() {
1522 WebContents* web_contents = GetWebContents();
1523 if (!manage_passwords_icon_.get() || !web_contents)
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();
1536 gtk_image_set_from_pixbuf(
1537 GTK_IMAGE(manage_passwords_icon_image_),
1538 theme_service_->GetImageNamed(IDR_SAVE_PASSWORD).ToGdkPixbuf());
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());
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();
1553 void LocationBarViewGtk::UpdateStarIcon() {
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());
1570 gtk_widget_hide_all(star_.get());
1574 bool LocationBarViewGtk::ShouldOnlyShowLocation() {
1575 return !browser_->is_type_tabbed();
1578 void LocationBarViewGtk::HideURL() {
1579 omnibox_view_->HideURL();
1582 ////////////////////////////////////////////////////////////////////////////////
1583 // LocationBarViewGtk::PageToolViewGtk
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)),
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());
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);
1603 gtk_widget_set_no_show_all(label_.get(), TRUE);
1604 gtk_label_set_line_wrap(GTK_LABEL(label_.get()), FALSE);
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);
1609 gtk_container_set_border_width(GTK_CONTAINER(hbox_), kHboxBorder);
1611 gtk_container_add(GTK_CONTAINER(event_box_.get()), hbox_);
1612 gtk_widget_hide(widget());
1614 animation_.SetSlideDuration(kPageToolAnimationTime);
1617 LocationBarViewGtk::PageToolViewGtk::~PageToolViewGtk() {
1620 event_box_.Destroy();
1621 alignment_.Destroy();
1624 bool LocationBarViewGtk::PageToolViewGtk::IsVisible() {
1625 return gtk_widget_get_visible(widget());
1628 void LocationBarViewGtk::PageToolViewGtk::AnimationProgressed(
1629 const gfx::Animation* animation) {
1630 gtk_widget_set_size_request(
1632 animation->GetCurrentValue() * label_req_.width,
1636 void LocationBarViewGtk::PageToolViewGtk::AnimationEnded(
1637 const gfx::Animation* animation) {
1640 void LocationBarViewGtk::PageToolViewGtk::AnimationCanceled(
1641 const gfx::Animation* animation) {
1644 void LocationBarViewGtk::PageToolViewGtk::StartAnimating() {
1645 if (animation_.IsShowing() || animation_.IsClosing())
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,
1652 gtk_util::ROUNDED_ALL, gtk_util::BORDER_ALL);
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());
1662 void LocationBarViewGtk::PageToolViewGtk::CloseAnimation() {
1666 gboolean LocationBarViewGtk::PageToolViewGtk::OnButtonPressed(
1667 GtkWidget* sender, GdkEvent* event) {
1672 gboolean LocationBarViewGtk::PageToolViewGtk::OnExpose(
1673 GtkWidget* sender, GdkEventExpose* event) {
1674 TRACE_EVENT0("ui::gtk", "LocationBarViewGtk::PageToolViewGtk::OnExpose");
1676 if (!(animation_.IsShowing() || animation_.IsClosing()))
1679 GtkAllocation allocation;
1680 gtk_widget_get_allocation(sender, &allocation);
1681 const int height = allocation.height;
1683 cairo_t* cr = gdk_cairo_create(gtk_widget_get_window(sender));
1684 gdk_cairo_rectangle(cr, &event->area);
1687 cairo_pattern_t* pattern = cairo_pattern_create_linear(0, 0, 0, height);
1689 const GdkColor top_color = GetGradientTopColor();
1690 const GdkColor bottom_color = GetGradientBottomColor();
1691 cairo_pattern_add_color_stop_rgb(
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(
1698 bottom_color.red/255.0,
1699 bottom_color.blue/255.0,
1700 bottom_color.green/255.0);
1702 cairo_set_source(cr, pattern);
1704 cairo_pattern_destroy(pattern);
1710 ////////////////////////////////////////////////////////////////////////////////
1711 // LocationBarViewGtk::PageActionViewGtk
1713 LocationBarViewGtk::PageActionViewGtk::PageActionViewGtk(
1714 LocationBarViewGtk* owner,
1715 ExtensionAction* page_action)
1717 page_action_(page_action),
1718 current_tab_id_(-1),
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);
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);
1736 image_.Own(gtk_image_new());
1737 gtk_container_add(GTK_CONTAINER(event_box_.get()), image_.get());
1739 const Extension* extension =
1740 owner->profile()->GetExtensionService()->GetExtensionById(
1741 page_action->extension_id(), false);
1744 icon_factory_.reset(new ExtensionActionIconFactory(
1745 owner->profile(), extension, page_action, this));
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.
1752 LocationBarViewGtk::PageActionViewGtk::~PageActionViewGtk() {
1753 DisconnectPageActionAccelerator();
1756 event_box_.Destroy();
1759 bool LocationBarViewGtk::PageActionViewGtk::IsVisible() {
1760 return gtk_widget_get_visible(widget());
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.
1768 contents ? extensions::ExtensionTabUtil::GetTabId(contents) : -1;
1771 bool visible = contents &&
1772 (preview_enabled_ || page_action_->GetIsVisible(current_tab_id_));
1775 gtk_widget_set_tooltip_text(event_box_.get(),
1776 page_action_->GetTitle(current_tab_id_).c_str());
1779 gfx::Image icon = icon_factory_->GetIcon(current_tab_id_);
1780 if (!icon.IsEmpty()) {
1781 GdkPixbuf* pixbuf = icon.ToGdkPixbuf();
1783 gtk_image_set_from_pixbuf(GTK_IMAGE(image_.get()), pixbuf);
1787 bool old_visible = IsVisible();
1789 gtk_widget_show_all(event_box_.get());
1791 gtk_widget_hide_all(event_box_.get());
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));
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;
1805 UpdateVisibility(web_contents, current_url_);
1808 void LocationBarViewGtk::PageActionViewGtk::TestActivatePageAction() {
1809 GdkEventButton event = {};
1810 event.type = GDK_BUTTON_PRESS;
1812 OnButtonPressed(widget(), &event);
1815 void LocationBarViewGtk::PageActionViewGtk::Observe(
1817 const content::NotificationSource& source,
1818 const content::NotificationDetails& details) {
1819 DCHECK_EQ(type, chrome::NOTIFICATION_WINDOW_CLOSED);
1820 DisconnectPageActionAccelerator();
1823 void LocationBarViewGtk::PageActionViewGtk::InspectPopup(
1824 ExtensionAction* action) {
1825 ExtensionPopupGtk::Show(
1826 action->GetPopupUrl(current_tab_id_),
1829 ExtensionPopupGtk::SHOW_AND_INSPECT);
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();
1839 extensions::CommandService* command_service =
1840 extensions::CommandService::Get(owner_->profile());
1842 extensions::Command command_page_action;
1843 if (command_service->GetPageActionCommand(
1845 extensions::CommandService::ACTIVE_ONLY,
1846 &command_page_action,
1848 // Found the page action shortcut command, register it.
1849 page_action_keybinding_.reset(
1850 new ui::Accelerator(command_page_action.accelerator()));
1853 if (page_action_keybinding_.get()) {
1854 accel_group_ = gtk_accel_group_new();
1855 gtk_window_add_accel_group(window_, accel_group_);
1857 gtk_accel_group_connect(
1859 ui::GetGdkKeyCodeForAccelerator(*page_action_keybinding_),
1860 ui::GetGdkModifierForAccelerator(*page_action_keybinding_),
1862 g_cclosure_new(G_CALLBACK(OnGtkAccelerator), this, NULL));
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_));
1872 void LocationBarViewGtk::PageActionViewGtk::DisconnectPageActionAccelerator() {
1874 if (page_action_keybinding_.get()) {
1875 gtk_accel_group_disconnect_key(
1877 ui::GetGdkKeyCodeForAccelerator(*page_action_keybinding_),
1878 ui::GetGdkModifierForAccelerator(*page_action_keybinding_));
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);
1887 gboolean LocationBarViewGtk::PageActionViewGtk::OnButtonPressed(
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
1893 if (event->type != GDK_BUTTON_PRESS)
1896 WebContents* web_contents = owner_->GetWebContents();
1900 ExtensionService* extension_service =
1901 owner_->profile()->GetExtensionService();
1902 if (!extension_service)
1905 const Extension* extension =
1906 extension_service->extensions()->GetByID(page_action()->extension_id());
1910 LocationBarController* controller =
1911 extensions::TabHelper::FromWebContents(web_contents)->
1912 location_bar_controller();
1914 switch (controller->OnClicked(extension->id(), event->button)) {
1915 case LocationBarController::ACTION_NONE:
1918 case LocationBarController::ACTION_SHOW_POPUP:
1919 ExtensionPopupGtk::Show(
1920 page_action_->GetPopupUrl(current_tab_id_),
1923 ExtensionPopupGtk::SHOW);
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);
1938 gboolean LocationBarViewGtk::PageActionViewGtk::OnExposeEvent(
1940 GdkEventExpose* event) {
1941 TRACE_EVENT0("ui::gtk", "LocationBarViewGtk::PageActionViewGtk::OnExpose");
1942 WebContents* contents = owner_->GetWebContents();
1946 int tab_id = extensions::ExtensionTabUtil::GetTabId(contents);
1950 std::string badge_text = page_action_->GetBadgeText(tab_id);
1951 if (badge_text.empty())
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);
1961 void LocationBarViewGtk::PageActionViewGtk::OnRealize(GtkWidget* widget) {
1962 ConnectPageActionAccelerator();
1966 gboolean LocationBarViewGtk::PageActionViewGtk::OnGtkAccelerator(
1967 GtkAccelGroup* accel_group,
1968 GObject* acceleratable,
1970 GdkModifierType modifier,
1972 PageActionViewGtk* view = static_cast<PageActionViewGtk*>(user_data);
1973 if (!gtk_widget_get_visible(view->widget()))
1976 GdkEventButton event = {};
1977 event.type = GDK_BUTTON_PRESS;
1979 return view->OnButtonPressed(view->widget(), &event);