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