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/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"
96 using content::NavigationEntry;
97 using content::OpenURLParams;
98 using content::WebContents;
99 using extensions::LocationBarController;
100 using extensions::Extension;
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;
110 const int kPopupEdgeThickness = 1;
111 const int kNormalEdgeThickness = 2;
113 // Spacing needed to align the bubble with the left side of the omnibox.
114 const int kFirstRunBubbleLeftSpacing = 4;
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;
122 // Padding between the elements in the bar.
123 const int kInnerPadding = 2;
124 const int kScriptBadgeInnerPadding = 9;
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);
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);
135 // Use weak gray for showing search and keyword hint text.
136 const GdkColor kHintTextColor = GDK_COLOR_RGB(0x75, 0x75, 0x75);
138 // Size of the rounding of the "Search site for:" box.
139 const int kCornerSize = 3;
141 // Default page tool animation time (open and close). In ms.
142 const int kPageToolAnimationTime = 150;
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;
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);
156 inline int InnerPadding() {
157 return extensions::FeatureSwitch::script_badges()->IsEnabled() ?
158 kScriptBadgeInnerPadding : kInnerPadding;
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;
168 class ContentSettingImageViewGtk : public LocationBarViewGtk::PageToolViewGtk,
169 public BubbleDelegateGtk {
171 ContentSettingImageViewGtk(ContentSettingsType content_type,
172 LocationBarViewGtk* parent);
173 virtual ~ContentSettingImageViewGtk();
176 virtual void UpdatePreLayout(WebContents* web_contents) OVERRIDE;
177 virtual void UpdatePostLayout(WebContents* web_contents) OVERRIDE;
179 // gfx::AnimationDelegate
180 virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE;
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;
190 virtual void BubbleClosing(BubbleGtk* bubble,
191 bool closed_by_escape) OVERRIDE;
193 void CreateBubble(WebContents* web_contents);
195 // The owning LocationBarViewGtk.
196 LocationBarViewGtk* parent_;
198 scoped_ptr<ContentSettingImageModel> content_setting_image_model_;
200 // The currently shown bubble if any.
201 ContentSettingBubbleGtk* content_setting_bubble_;
203 DISALLOW_COPY_AND_ASSIGN(ContentSettingImageViewGtk);
206 ContentSettingImageViewGtk::ContentSettingImageViewGtk(
207 ContentSettingsType content_type,
208 LocationBarViewGtk* parent)
211 content_setting_image_model_(
212 ContentSettingImageModel::CreateContentSettingImageModel(
214 content_setting_bubble_(NULL) {
215 animation_.SetSlideDuration(kContentSettingImageAnimationTime);
218 ContentSettingImageViewGtk::~ContentSettingImageViewGtk() {
219 if (content_setting_bubble_)
220 content_setting_bubble_->Close();
223 void ContentSettingImageViewGtk::UpdatePreLayout(WebContents* web_contents) {
225 content_setting_image_model_->UpdateFromWebContents(web_contents);
227 if (!content_setting_image_model_->is_visible()) {
228 gtk_widget_hide(widget());
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());
236 gtk_widget_set_tooltip_text(widget(),
237 content_setting_image_model_->get_tooltip().c_str());
238 gtk_widget_show_all(widget());
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()))
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)
255 gtk_label_set_text(GTK_LABEL(label_.get()),
256 l10n_util::GetStringUTF8(label_string_id).c_str());
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.
265 void ContentSettingImageViewGtk::UpdatePostLayout(WebContents* web_contents) {
266 if (!content_setting_image_model_->is_visible())
269 TabSpecificContentSettings* content_settings = web_contents ?
270 TabSpecificContentSettings::FromWebContents(web_contents) : NULL;
271 if (!content_settings)
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());
283 void ContentSettingImageViewGtk::AnimationEnded(
284 const gfx::Animation* animation) {
285 if (animation_.IsShowing()) {
286 base::MessageLoop::current()->PostDelayedTask(
288 base::Bind(&ContentSettingImageViewGtk::CloseAnimation,
289 weak_factory_.GetWeakPtr()),
290 base::TimeDelta::FromMilliseconds(kContentSettingImageDisplayTime));
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);
298 GdkColor ContentSettingImageViewGtk::GetButtonBorderColor() const {
299 return kContentSettingBorderColor;
302 GdkColor ContentSettingImageViewGtk::GetGradientTopColor() const {
303 return kContentSettingTopColor;
306 GdkColor ContentSettingImageViewGtk::GetGradientBottomColor() const {
307 return kContentSettingBottomColor;
310 void ContentSettingImageViewGtk::OnClick(
312 WebContents* web_contents = parent_->GetWebContents();
315 Profile* profile = parent_->browser()->profile();
316 content_setting_bubble_ = new ContentSettingBubbleGtk(
318 ContentSettingBubbleModel::CreateContentSettingBubbleModel(
319 parent_->browser()->content_setting_bubble_model_delegate(),
322 content_setting_image_model_->get_content_settings_type()),
327 void ContentSettingImageViewGtk::BubbleClosing(
329 bool closed_by_escape) {
330 content_setting_bubble_ = NULL;
333 void ContentSettingImageViewGtk::CreateBubble(
334 content::WebContents* web_contents) {
335 content_setting_bubble_ = new ContentSettingBubbleGtk(
337 ContentSettingBubbleModel::CreateContentSettingBubbleModel(
338 parent_->browser()->content_setting_bubble_model_delegate(),
340 parent_->browser()->profile(),
341 content_setting_image_model_->get_content_settings_type()),
342 parent_->browser()->profile());
346 gfx::Rect AllocationToRect(const GtkAllocation& allocation) {
347 return gfx::Rect(allocation.x, allocation.y,
348 allocation.width, allocation.height);
353 ////////////////////////////////////////////////////////////////////////////////
354 // LocationBarViewGtk
357 const GdkColor LocationBarViewGtk::kBackgroundColor =
358 GDK_COLOR_RGB(255, 255, 255);
360 LocationBarViewGtk::LocationBarViewGtk(Browser* browser)
361 : OmniboxEditController(browser->command_controller()->command_updater()),
363 script_bubble_button_image_(NULL),
364 num_running_scripts_(0u),
368 site_type_alignment_(NULL),
369 site_type_event_box_(NULL),
370 location_icon_image_(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),
383 popup_window_mode_(false),
384 theme_service_(NULL),
387 show_selected_keyword_(false),
388 show_keyword_hint_(false),
389 weak_ptr_factory_(this) {
392 LocationBarViewGtk::~LocationBarViewGtk() {
393 // All of our widgets should be children of / owned by the alignment.
395 script_bubble_button_.Destroy();
398 content_setting_hbox_.Destroy();
399 page_action_hbox_.Destroy();
402 void LocationBarViewGtk::Init(bool popup_window_mode) {
403 popup_window_mode_ = popup_window_mode;
405 Profile* profile = browser_->profile();
406 theme_service_ = GtkThemeService::GetFrom(profile);
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);
417 // Now initialize the OmniboxViewGtk.
418 location_entry_.reset(new OmniboxViewGtk(this, browser_, browser_->profile(),
420 popup_window_mode_, hbox_.get()));
421 location_entry_->Init();
423 g_signal_connect(hbox_.get(), "expose-event",
424 G_CALLBACK(&HandleExposeThunk), this);
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);
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);
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_,
457 gtk_util::CenterWidgetInHBox(tab_to_search_hbox, tab_to_search_label_hbox,
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,
467 gtk_util::ROUNDED_ALL, gtk_util::BORDER_ALL);
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_),
473 gtk_box_pack_start(GTK_BOX(entry_box_), tab_to_search_alignment_,
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_);
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_,
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_,
501 gtk_box_pack_start(GTK_BOX(tab_to_search_hint_),
502 tab_to_search_hint_icon_,
504 gtk_box_pack_start(GTK_BOX(tab_to_search_hint_),
505 tab_to_search_hint_trailing_label_,
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);
514 if (browser_defaults::bookmarks_enabled && !ShouldOnlyShowLocation()) {
515 // Hide the star icon in popups, app windows, etc.
517 gtk_box_pack_end(GTK_BOX(hbox_.get()), star_.get(), FALSE, FALSE, 0);
520 CreateScriptBubbleButton();
521 gtk_box_pack_end(GTK_BOX(hbox_.get()), script_bubble_button_.get(), FALSE,
525 gtk_box_pack_end(GTK_BOX(hbox_.get()), zoom_.get(), FALSE, FALSE, 0);
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(),
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);
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(),
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);
555 chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
556 content::Source<ThemeService>(theme_service_));
558 chrome::NOTIFICATION_EXTENSION_LOCATION_BAR_UPDATED,
559 content::Source<Profile>(browser()->profile()));
560 edit_bookmarks_enabled_.Init(prefs::kEditBookmarksEnabled,
562 base::Bind(&LocationBarViewGtk::UpdateStarIcon,
563 base::Unretained(this)));
565 theme_service_->InitThemesFor(this);
568 void LocationBarViewGtk::SetPreviewEnabledPageAction(
569 ExtensionAction* page_action,
570 bool preview_enabled) {
572 for (ScopedVector<PageActionViewGtk>::iterator iter =
573 page_action_views_.begin(); iter != page_action_views_.end();
575 if ((*iter)->page_action() == page_action) {
576 (*iter)->set_preview_enabled(preview_enabled);
583 GtkWidget* LocationBarViewGtk::GetPageActionWidget(
584 ExtensionAction* page_action) {
586 for (ScopedVector<PageActionViewGtk>::iterator iter =
587 page_action_views_.begin();
588 iter != page_action_views_.end();
590 if ((*iter)->page_action() == page_action)
591 return (*iter)->widget();
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());
605 void LocationBarViewGtk::ShowStarBubble(const GURL& url,
606 bool newly_bookmarked) {
611 BookmarkBubbleGtk::Show(star_.get(), browser_->profile(), url,
614 on_star_sized_ = base::Bind(&BookmarkBubbleGtk::Show,
615 star_.get(), browser_->profile(),
616 url, newly_bookmarked);
620 void LocationBarViewGtk::ZoomChangedForActiveTab(bool can_show_bubble) {
623 if (can_show_bubble && gtk_widget_get_visible(zoom_.get()))
627 void LocationBarViewGtk::SetStarred(bool starred) {
628 if (starred == starred_)
635 void LocationBarViewGtk::Update(const WebContents* contents) {
637 UpdateScriptBubbleIcon();
639 UpdateSiteTypeArea();
640 UpdateContentSettingsIcons();
643 location_entry_->OnTabChanged(contents);
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
650 gtk_widget_queue_draw(gtk_widget_get_parent(widget()));
652 gtk_widget_queue_draw(widget());
654 ZoomBubbleGtk::CloseBubble();
658 void LocationBarViewGtk::OnChanged() {
659 UpdateSiteTypeArea();
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;
666 if (show_selected_keyword_)
667 SetKeywordLabel(keyword);
669 if (show_keyword_hint_)
670 SetKeywordHintLabel(keyword);
672 AdjustChildrenVisibility();
675 void LocationBarViewGtk::OnSetFocus() {
676 Profile* profile = browser_->profile();
677 AccessibilityTextBoxInfo info(
679 l10n_util::GetStringUTF8(IDS_ACCNAME_LOCATION),
682 ExtensionAccessibilityEventRouter::GetInstance()->HandleControlEvent(
683 ui::AccessibilityTypes::EVENT_FOCUS,
686 // Update the keyword and search hint states.
690 InstantController* LocationBarViewGtk::GetInstant() {
691 return browser_->instant_controller() ?
692 browser_->instant_controller()->instant() : NULL;
695 WebContents* LocationBarViewGtk::GetWebContents() {
696 return browser_->tab_strip_model()->GetActiveWebContents();
699 ToolbarModel* LocationBarViewGtk::GetToolbarModel() {
700 return browser_->toolbar_model();
703 const ToolbarModel* LocationBarViewGtk::GetToolbarModel() const {
704 return browser_->toolbar_model();
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(
712 base::Bind(&LocationBarViewGtk::ShowFirstRunBubbleInternal,
713 weak_ptr_factory_.GetWeakPtr()));
716 GURL LocationBarViewGtk::GetDestinationURL() const {
717 return destination_url();
720 WindowOpenDisposition LocationBarViewGtk::GetWindowOpenDisposition() const {
721 return disposition();
724 content::PageTransition LocationBarViewGtk::GetPageTransition() const {
728 void LocationBarViewGtk::AcceptInput() {
729 location_entry_->model()->AcceptInput(CURRENT_TAB, false);
732 void LocationBarViewGtk::FocusLocation(bool select_all) {
733 location_entry_->SetFocus();
735 location_entry_->SelectAll(true);
738 void LocationBarViewGtk::FocusSearch() {
739 location_entry_->SetFocus();
740 location_entry_->SetForcedQuery();
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;
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);
758 void LocationBarViewGtk::UpdatePageActions() {
759 UpdateScriptBubbleIcon();
761 std::vector<ExtensionAction*> new_page_actions;
763 WebContents* contents = GetWebContents();
765 LocationBarController* location_bar_controller =
766 extensions::TabHelper::FromWebContents(contents)->
767 location_bar_controller();
768 new_page_actions = location_bar_controller->GetCurrentActions();
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();
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);
783 content::NotificationService::current()->Notify(
784 chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_COUNT_CHANGED,
785 content::Source<LocationBar>(this),
786 content::NotificationService::NoDetails());
789 if (!page_action_views_.empty() && contents) {
790 GURL url = GetWebContents()->GetURL();
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);
796 gtk_widget_queue_draw(hbox_.get());
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());
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());
816 void LocationBarViewGtk::UpdateOpenPDFInReaderPrompt() {
817 // Not implemented on Gtk.
820 void LocationBarViewGtk::UpdateGeneratedCreditCardView() {
824 void LocationBarViewGtk::SaveStateToContents(WebContents* contents) {
825 location_entry_->SaveStateToTab(contents);
828 void LocationBarViewGtk::Revert() {
829 location_entry_->RevertAll();
832 const OmniboxView* LocationBarViewGtk::GetLocationEntry() const {
833 return location_entry_.get();
836 OmniboxView* LocationBarViewGtk::GetLocationEntry() {
837 return location_entry_.get();
840 LocationBarTesting* LocationBarViewGtk::GetLocationBarForTesting() {
844 int LocationBarViewGtk::PageActionCount() {
845 return page_action_views_.size();
848 int LocationBarViewGtk::PageActionVisibleCount() {
850 gtk_container_foreach(GTK_CONTAINER(page_action_hbox_.get()),
851 CountVisibleWidgets, &count);
855 ExtensionAction* LocationBarViewGtk::GetPageAction(size_t index) {
856 if (index >= page_action_views_.size()) {
861 return page_action_views_[index]->page_action();
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();
877 void LocationBarViewGtk::TestPageActionPressed(size_t index) {
878 if (index >= page_action_views_.size()) {
883 page_action_views_[index]->TestActivatePageAction();
886 bool LocationBarViewGtk::GetBookmarkStarVisibility() {
890 void LocationBarViewGtk::Observe(int type,
891 const content::NotificationSource& source,
892 const content::NotificationDetails& details) {
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())
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);
906 GdkColor border_color = theme_service_->GetGdkColor(
907 ThemeProperties::COLOR_FRAME);
908 gtk_util::SetRoundedWindowBorderColor(tab_to_search_box_, border_color);
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_);
916 gtk_alignment_set_padding(GTK_ALIGNMENT(location_entry_alignment_),
918 gtk_alignment_set_padding(GTK_ALIGNMENT(tab_to_search_alignment_),
920 gtk_alignment_set_padding(GTK_ALIGNMENT(site_type_alignment_),
923 gtk_widget_modify_bg(tab_to_search_box_, GTK_STATE_NORMAL,
924 &kKeywordBackgroundColor);
925 gtk_util::SetRoundedWindowBorderColor(tab_to_search_box_,
926 kKeywordBorderColor);
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);
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_),
947 gtk_alignment_set_padding(GTK_ALIGNMENT(site_type_alignment_),
952 UpdateScriptBubbleIcon();
954 UpdateSiteTypeArea();
955 UpdateContentSettingsIcons();
965 void LocationBarViewGtk::BuildSiteTypeArea() {
966 location_icon_image_ = gtk_image_new();
967 gtk_widget_set_name(location_icon_image_, "chrome-location-icon");
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);
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");
982 GtkWidget* site_type_hbox = gtk_hbox_new(FALSE, 1);
983 gtk_box_pack_start(GTK_BOX(site_type_hbox), icon_alignment,
985 gtk_box_pack_start(GTK_BOX(site_type_hbox), security_info_label_,
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);
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_),
1001 gtk_widget_set_name(site_type_event_box_,
1002 "chrome-location-icon-eventbox");
1003 gtk_container_add(GTK_CONTAINER(site_type_event_box_),
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_,
1013 gtk_widget_set_tooltip_text(location_icon_image_,
1014 l10n_util::GetStringUTF8(IDS_TOOLTIP_LOCATION_ICON).c_str());
1016 g_signal_connect(site_type_event_box_, "button-release-event",
1017 G_CALLBACK(&OnIconReleasedThunk), this);
1020 void LocationBarViewGtk::SetSiteTypeDragSource() {
1021 bool enable = !GetLocationEntry()->IsEditingOrEmpty();
1022 if (enable_location_drag_ == enable)
1024 enable_location_drag_ = enable;
1027 gtk_drag_source_unset(site_type_event_box_);
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_,
1036 ui::CHROME_NAMED_URL);
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.
1048 gfx::CanvasSkiaPaint canvas(event, /*opaque=*/false);
1050 GtkAllocation allocation;
1051 gtk_widget_get_allocation(widget, &allocation);
1053 int thickness = popup_window_mode_ ?
1054 kPopupEdgeThickness : kNormalEdgeThickness;
1055 gfx::Rect bounds(allocation);
1056 bounds.Inset(thickness, thickness);
1058 const SkColor color = SK_ColorWHITE;
1059 if (popup_window_mode_) {
1060 canvas.FillRect(bounds, color);
1063 paint.setStyle(SkPaint::kFill_Style);
1064 paint.setColor(color);
1065 const int kBorderCornerRadius = 2;
1066 canvas.DrawRoundRect(bounds, kBorderCornerRadius, paint);
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);
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);
1093 // Draw ExtensionAction backgrounds and borders, if necessary. The borders
1094 // appear exactly between the elements, so they can't draw the borders
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.
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
1115 bounds.Inset(-(InnerPadding() + 1) / 2,
1116 theme_service_->UsingNativeTheme() ? -1 : 0);
1117 location_bar_util::PaintExtensionActionBackground(
1118 *action, SessionID::IdForTab(GetWebContents()),
1120 theme_service_->get_location_bar_text_color(),
1121 theme_service_->get_location_bar_bg_color());
1124 // Destroying |canvas| draws the background.
1126 return FALSE; // Continue propagating the expose.
1129 gboolean LocationBarViewGtk::OnIconReleased(GtkWidget* sender,
1130 GdkEventButton* event) {
1131 WebContents* tab = GetWebContents();
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())
1139 // (0,0) event coordinates indicates that the release came at the end of
1141 if (event->x == 0 && event->y == 0)
1144 // Important to use GetVisibleEntry to match what's showing in the omnibox.
1145 NavigationEntry* nav_entry = tab->GetController().GetVisibleEntry();
1150 chrome::ShowWebsiteSettings(browser_, tab, nav_entry->GetURL(),
1151 nav_entry->GetSSL());
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))) {
1163 if (!gtk_util::URLFromPrimarySelection(browser_->profile(), &url))
1166 tab->OpenURL(OpenURLParams(
1167 url, content::Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED,
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);
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())
1189 drag_url_ = web_contents->GetURL();
1190 drag_title_ = web_contents->GetTitle();
1191 drag_icon_ = GetDragRepresentation(favicon.ToGdkPixbuf(), drag_title_,
1193 gtk_drag_set_icon_widget(context, drag_icon_, 0, 0);
1196 void LocationBarViewGtk::OnIconDragEnd(GtkWidget* sender,
1197 GdkDragContext* context) {
1199 gtk_widget_destroy(drag_icon_);
1201 drag_url_ = GURL::EmptyGURL();
1202 drag_title_.clear();
1205 void LocationBarViewGtk::OnHboxSizeAllocate(GtkWidget* sender,
1206 GtkAllocation* allocation) {
1207 if (hbox_width_ != allocation->width) {
1208 hbox_width_ = allocation->width;
1209 UpdateEVCertificateLabelSize();
1211 if (browser_ && browser_->instant_controller()) {
1212 browser_->instant_controller()->
1213 SetOmniboxBounds(AllocationToRect(*allocation));
1217 void LocationBarViewGtk::OnEntryBoxSizeAllocate(GtkWidget* sender,
1218 GtkAllocation* allocation) {
1219 if (entry_box_width_ != allocation->width) {
1220 entry_box_width_ = allocation->width;
1221 AdjustChildrenVisibility();
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
1230 ZoomBubbleGtk::ShowBubble(GetWebContents(), false);
1236 gboolean LocationBarViewGtk::OnScriptBubbleButtonPress(GtkWidget* widget,
1237 GdkEventButton* event) {
1238 if (event->button == 1 && GetWebContents()) {
1239 ScriptBubbleGtk::Show(script_bubble_button_image_, GetWebContents());
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();
1254 gboolean LocationBarViewGtk::OnStarButtonPress(GtkWidget* widget,
1255 GdkEventButton* event) {
1256 if (event->button == 1) {
1257 chrome::ExecuteCommand(browser_, IDC_BOOKMARK_PAGE);
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_),
1272 SkColorSetRGB(0, 170, 0),
1274 extensions::ActionInfo::TYPE_PAGE);
1278 void LocationBarViewGtk::UpdateSiteTypeArea() {
1279 // The icon is always visible except when the |tab_to_search_alignment_| is
1281 if (!location_entry_->model()->keyword().empty() &&
1282 !location_entry_->model()->is_keyword_hint()) {
1283 gtk_widget_hide(site_type_area());
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());
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
1298 gtk_event_box_set_visible_window(GTK_EVENT_BOX(site_type_event_box_),
1301 gtk_util::ActAsRoundedWindow(site_type_event_box_,
1302 kEvSecureBorderColor,
1304 gtk_util::ROUNDED_ALL,
1305 gtk_util::BORDER_ALL);
1308 string16 info_text = GetToolbarModel()->GetEVCertName();
1309 gtk_label_set_text(GTK_LABEL(security_info_label_),
1310 UTF16ToUTF8(info_text).c_str());
1312 UpdateEVCertificateLabelSize();
1314 gtk_widget_show(GTK_WIDGET(security_info_label_));
1316 if (gtk_util::IsActingAsRoundedWindow(site_type_event_box_)) {
1317 gtk_util::StopActingAsRoundedWindow(site_type_event_box_);
1319 gtk_event_box_set_visible_window(GTK_EVENT_BOX(site_type_event_box_),
1323 gtk_widget_hide(GTK_WIDGET(security_info_label_));
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_, "");
1331 gtk_widget_set_tooltip_text(location_icon_image_,
1332 l10n_util::GetStringUTF8(IDS_TOOLTIP_LOCATION_ICON).c_str());
1335 gtk_widget_show(site_type_area());
1337 SetSiteTypeDragSource();
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(
1346 gtk_widget_get_style(security_info_label_)->font_desc,
1347 pango_context_get_language(context));
1349 pango_font_metrics_get_approximate_char_width(metrics) / PANGO_SCALE;
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));
1367 pango_font_metrics_unref(metrics);
1370 void LocationBarViewGtk::SetKeywordLabel(const string16& keyword) {
1371 if (keyword.empty())
1374 Profile* profile = browser_->profile();
1375 TemplateURLService* template_url_service =
1376 TemplateURLServiceFactory::GetForProfile(profile);
1377 if (!template_url_service)
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 ?
1386 l10n_util::GetStringFUTF16(IDS_OMNIBOX_KEYWORD_TEXT, short_name);
1387 const string16 partial_name = is_extension_keyword ?
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());
1395 if (last_keyword_ != keyword) {
1396 last_keyword_ = keyword;
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());
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());
1413 void LocationBarViewGtk::SetKeywordHintLabel(const string16& keyword) {
1414 if (keyword.empty())
1417 TemplateURLService* template_url_service =
1418 TemplateURLServiceFactory::GetForProfile(browser_->profile());
1419 if (!template_url_service)
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(
1432 &content_param_offsets);
1433 if (content_param_offsets.size() != 2) {
1434 // See comments on an identical NOTREACHED() in search_provider.cc.
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_),
1445 gtk_label_set_text(GTK_LABEL(tab_to_search_hint_trailing_label_),
1449 void LocationBarViewGtk::ShowFirstRunBubbleInternal() {
1450 if (!location_entry_.get() || !gtk_widget_get_window(widget()))
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);
1458 void LocationBarViewGtk::ShowZoomBubble() {
1459 if (GetToolbarModel()->input_in_progress() || !GetWebContents())
1462 ZoomBubbleGtk::ShowBubble(GetWebContents(), true);
1465 void LocationBarViewGtk::AdjustChildrenVisibility() {
1466 int text_width = location_entry_->TextWidth();
1467 int available_width = entry_box_width_ - text_width - InnerPadding();
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_);
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;
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;
1491 partial_box_width = box.width;
1492 full_box_width = partial_box_width + full_partial_width_diff;
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_);
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;
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_);
1527 GtkWidget* LocationBarViewGtk::CreateIconButton(
1532 gboolean (click_callback)(GtkWidget*, GdkEventButton*, gpointer)) {
1534 gtk_image_new_from_pixbuf(
1535 theme_service_->GetImageNamed(image_id).ToGdkPixbuf()) :
1538 GtkWidget* alignment = gtk_alignment_new(0, 0, 1, 1);
1539 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0,
1541 gtk_container_add(GTK_CONTAINER(alignment), *image);
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);
1548 if (debug_id != VIEW_ID_NONE)
1549 ViewIDUtil::SetID(result, debug_id);
1552 gtk_widget_set_tooltip_text(result,
1553 l10n_util::GetStringUTF8(tooltip_id).c_str());
1556 g_signal_connect(result, "button-press-event",
1557 G_CALLBACK(click_callback), this);
1562 void LocationBarViewGtk::CreateZoomButton() {
1563 zoom_.Own(CreateIconButton(&zoom_image_,
1565 VIEW_ID_ZOOM_BUTTON,
1567 OnZoomButtonPressThunk));
1570 void LocationBarViewGtk::CreateScriptBubbleButton() {
1571 script_bubble_button_.Own(CreateIconButton(&script_bubble_button_image_,
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);
1584 void LocationBarViewGtk::CreateStarButton() {
1585 star_.Own(CreateIconButton(&star_image_,
1587 VIEW_ID_STAR_BUTTON,
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);
1596 void LocationBarViewGtk::UpdateZoomIcon() {
1597 WebContents* web_contents = GetWebContents();
1598 if (!zoom_.get() || !web_contents)
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();
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());
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());
1618 gtk_widget_show(zoom_.get());
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();
1632 if (num_running_scripts_ == 0u)
1633 gtk_widget_hide(script_bubble_button_.get());
1635 gtk_widget_show(script_bubble_button_.get());
1638 void LocationBarViewGtk::UpdateStarIcon() {
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,
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());
1657 gtk_widget_hide_all(star_.get());
1661 bool LocationBarViewGtk::ShouldOnlyShowLocation() {
1662 return !browser_->is_type_tabbed();
1665 ////////////////////////////////////////////////////////////////////////////////
1666 // LocationBarViewGtk::PageToolViewGtk
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)),
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());
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);
1686 gtk_widget_set_no_show_all(label_.get(), TRUE);
1687 gtk_label_set_line_wrap(GTK_LABEL(label_.get()), FALSE);
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);
1692 gtk_container_set_border_width(GTK_CONTAINER(hbox_), kHboxBorder);
1694 gtk_container_add(GTK_CONTAINER(event_box_.get()), hbox_);
1695 gtk_widget_hide(widget());
1697 animation_.SetSlideDuration(kPageToolAnimationTime);
1700 LocationBarViewGtk::PageToolViewGtk::~PageToolViewGtk() {
1703 event_box_.Destroy();
1704 alignment_.Destroy();
1707 bool LocationBarViewGtk::PageToolViewGtk::IsVisible() {
1708 return gtk_widget_get_visible(widget());
1711 void LocationBarViewGtk::PageToolViewGtk::AnimationProgressed(
1712 const gfx::Animation* animation) {
1713 gtk_widget_set_size_request(
1715 animation->GetCurrentValue() * label_req_.width,
1719 void LocationBarViewGtk::PageToolViewGtk::AnimationEnded(
1720 const gfx::Animation* animation) {
1723 void LocationBarViewGtk::PageToolViewGtk::AnimationCanceled(
1724 const gfx::Animation* animation) {
1727 void LocationBarViewGtk::PageToolViewGtk::StartAnimating() {
1728 if (animation_.IsShowing() || animation_.IsClosing())
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,
1735 gtk_util::ROUNDED_ALL, gtk_util::BORDER_ALL);
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());
1745 void LocationBarViewGtk::PageToolViewGtk::CloseAnimation() {
1749 gboolean LocationBarViewGtk::PageToolViewGtk::OnButtonPressed(
1750 GtkWidget* sender, GdkEvent* event) {
1755 gboolean LocationBarViewGtk::PageToolViewGtk::OnExpose(
1756 GtkWidget* sender, GdkEventExpose* event) {
1757 TRACE_EVENT0("ui::gtk", "LocationBarViewGtk::PageToolViewGtk::OnExpose");
1759 if (!(animation_.IsShowing() || animation_.IsClosing()))
1762 GtkAllocation allocation;
1763 gtk_widget_get_allocation(sender, &allocation);
1764 const int height = allocation.height;
1766 cairo_t* cr = gdk_cairo_create(gtk_widget_get_window(sender));
1767 gdk_cairo_rectangle(cr, &event->area);
1770 cairo_pattern_t* pattern = cairo_pattern_create_linear(0, 0, 0, height);
1772 const GdkColor top_color = GetGradientTopColor();
1773 const GdkColor bottom_color = GetGradientBottomColor();
1774 cairo_pattern_add_color_stop_rgb(
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(
1781 bottom_color.red/255.0,
1782 bottom_color.blue/255.0,
1783 bottom_color.green/255.0);
1785 cairo_set_source(cr, pattern);
1787 cairo_pattern_destroy(pattern);
1793 ////////////////////////////////////////////////////////////////////////////////
1794 // LocationBarViewGtk::PageActionViewGtk
1796 LocationBarViewGtk::PageActionViewGtk::PageActionViewGtk(
1797 LocationBarViewGtk* owner,
1798 ExtensionAction* page_action)
1800 page_action_(page_action),
1801 current_tab_id_(-1),
1804 preview_enabled_(false),
1805 scoped_icon_animation_observer_(
1806 page_action->GetIconAnimation(
1807 SessionID::IdForTab(owner->GetWebContents())),
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);
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);
1823 image_.Own(gtk_image_new());
1824 gtk_container_add(GTK_CONTAINER(event_box_.get()), image_.get());
1826 const Extension* extension = owner->browser()->profile()->
1827 GetExtensionService()->GetExtensionById(page_action->extension_id(),
1831 icon_factory_.reset(
1832 new ExtensionActionIconFactory(
1833 owner->browser()->profile(), extension, page_action, this));
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.
1840 LocationBarViewGtk::PageActionViewGtk::~PageActionViewGtk() {
1841 DisconnectPageActionAccelerator();
1844 event_box_.Destroy();
1847 bool LocationBarViewGtk::PageActionViewGtk::IsVisible() {
1848 return gtk_widget_get_visible(widget());
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;
1858 bool visible = contents &&
1859 (preview_enabled_ || page_action_->GetIsVisible(current_tab_id_));
1862 gtk_widget_set_tooltip_text(event_box_.get(),
1863 page_action_->GetTitle(current_tab_id_).c_str());
1866 gfx::Image icon = icon_factory_->GetIcon(current_tab_id_);
1867 if (!icon.IsEmpty()) {
1868 GdkPixbuf* pixbuf = icon.ToGdkPixbuf();
1870 gtk_image_set_from_pixbuf(GTK_IMAGE(image_.get()), pixbuf);
1874 bool old_visible = IsVisible();
1876 gtk_widget_show_all(event_box_.get());
1878 gtk_widget_hide_all(event_box_.get());
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));
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;
1892 UpdateVisibility(web_contents, current_url_);
1895 void LocationBarViewGtk::PageActionViewGtk::TestActivatePageAction() {
1896 GdkEventButton event = {};
1897 event.type = GDK_BUTTON_PRESS;
1899 OnButtonPressed(widget(), &event);
1902 void LocationBarViewGtk::PageActionViewGtk::Observe(
1904 const content::NotificationSource& source,
1905 const content::NotificationDetails& details) {
1906 DCHECK_EQ(type, chrome::NOTIFICATION_WINDOW_CLOSED);
1907 DisconnectPageActionAccelerator();
1910 void LocationBarViewGtk::PageActionViewGtk::InspectPopup(
1911 ExtensionAction* action) {
1912 ExtensionPopupGtk::Show(
1913 action->GetPopupUrl(current_tab_id_),
1916 ExtensionPopupGtk::SHOW_AND_INSPECT);
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();
1926 extensions::CommandService* command_service =
1927 extensions::CommandService::Get(owner_->browser()->profile());
1929 extensions::Command command_page_action;
1930 if (command_service->GetPageActionCommand(
1932 extensions::CommandService::ACTIVE_ONLY,
1933 &command_page_action,
1935 // Found the page action shortcut command, register it.
1936 page_action_keybinding_.reset(
1937 new ui::Accelerator(command_page_action.accelerator()));
1940 extensions::Command command_script_badge;
1941 if (command_service->GetScriptBadgeCommand(
1943 extensions::CommandService::ACTIVE_ONLY,
1944 &command_script_badge,
1946 // Found the script badge shortcut command, register it.
1947 script_badge_keybinding_.reset(
1948 new ui::Accelerator(command_script_badge.accelerator()));
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_);
1955 if (page_action_keybinding_.get()) {
1956 gtk_accel_group_connect(
1958 ui::GetGdkKeyCodeForAccelerator(*page_action_keybinding_),
1959 ui::GetGdkModifierForAccelerator(*page_action_keybinding_),
1961 g_cclosure_new(G_CALLBACK(OnGtkAccelerator), this, NULL));
1963 if (script_badge_keybinding_.get()) {
1964 gtk_accel_group_connect(
1966 ui::GetGdkKeyCodeForAccelerator(*script_badge_keybinding_),
1967 ui::GetGdkModifierForAccelerator(*script_badge_keybinding_),
1969 g_cclosure_new(G_CALLBACK(OnGtkAccelerator), this, NULL));
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_));
1980 void LocationBarViewGtk::PageActionViewGtk::DisconnectPageActionAccelerator() {
1982 if (page_action_keybinding_.get()) {
1983 gtk_accel_group_disconnect_key(
1985 ui::GetGdkKeyCodeForAccelerator(*page_action_keybinding_),
1986 ui::GetGdkModifierForAccelerator(*page_action_keybinding_));
1988 if (script_badge_keybinding_.get()) {
1989 gtk_accel_group_disconnect_key(
1991 ui::GetGdkKeyCodeForAccelerator(*script_badge_keybinding_),
1992 ui::GetGdkModifierForAccelerator(*script_badge_keybinding_));
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);
2002 gboolean LocationBarViewGtk::PageActionViewGtk::OnButtonPressed(
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
2008 if (event->type != GDK_BUTTON_PRESS)
2011 WebContents* web_contents = owner_->GetWebContents();
2015 ExtensionService* extension_service =
2016 owner_->browser()->profile()->GetExtensionService();
2017 if (!extension_service)
2020 const Extension* extension =
2021 extension_service->extensions()->GetByID(page_action()->extension_id());
2025 LocationBarController* controller =
2026 extensions::TabHelper::FromWebContents(web_contents)->
2027 location_bar_controller();
2029 switch (controller->OnClicked(extension->id(), event->button)) {
2030 case LocationBarController::ACTION_NONE:
2033 case LocationBarController::ACTION_SHOW_POPUP:
2034 ExtensionPopupGtk::Show(
2035 page_action_->GetPopupUrl(current_tab_id_),
2038 ExtensionPopupGtk::SHOW);
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);
2049 case LocationBarController::ACTION_SHOW_SCRIPT_POPUP:
2050 ExtensionPopupGtk::Show(
2051 extensions::ExtensionInfoUI::GetURL(extension->id()),
2054 ExtensionPopupGtk::SHOW);
2061 gboolean LocationBarViewGtk::PageActionViewGtk::OnExposeEvent(
2063 GdkEventExpose* event) {
2064 TRACE_EVENT0("ui::gtk", "LocationBarViewGtk::PageActionViewGtk::OnExpose");
2065 WebContents* contents = owner_->GetWebContents();
2069 int tab_id = ExtensionTabUtil::GetTabId(contents);
2073 std::string badge_text = page_action_->GetBadgeText(tab_id);
2074 if (badge_text.empty())
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);
2084 void LocationBarViewGtk::PageActionViewGtk::OnRealize(GtkWidget* widget) {
2085 ConnectPageActionAccelerator();
2089 gboolean LocationBarViewGtk::PageActionViewGtk::OnGtkAccelerator(
2090 GtkAccelGroup* accel_group,
2091 GObject* acceleratable,
2093 GdkModifierType modifier,
2095 PageActionViewGtk* view = static_cast<PageActionViewGtk*>(user_data);
2096 if (!gtk_widget_get_visible(view->widget()))
2099 GdkEventButton event = {};
2100 event.type = GDK_BUTTON_PRESS;
2102 return view->OnButtonPressed(view->widget(), &event);
2105 void LocationBarViewGtk::PageActionViewGtk::OnIconChanged() {
2106 UpdateVisibility(owner_->GetWebContents(), current_url_);