| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/gtk/browser_actions_toolbar_gtk.h" | 5 #include "chrome/browser/ui/gtk/browser_actions_toolbar_gtk.h" |
| 6 | 6 |
| 7 #include <gtk/gtk.h> | 7 #include <gtk/gtk.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <vector> | 10 #include <vector> |
| 11 | 11 |
| 12 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/i18n/rtl.h" | 13 #include "base/i18n/rtl.h" |
| 14 #include "base/message_loop.h" | 14 #include "base/message_loop.h" |
| 15 #include "base/utf_string_conversions.h" | 15 #include "base/utf_string_conversions.h" |
| 16 #include "chrome/browser/extensions/api/commands/command_service.h" | 16 #include "chrome/browser/extensions/api/commands/command_service.h" |
| 17 #include "chrome/browser/extensions/api/commands/command_service_factory.h" | 17 #include "chrome/browser/extensions/api/commands/command_service_factory.h" |
| 18 #include "chrome/browser/extensions/extension_action_icon_factory.h" |
| 18 #include "chrome/browser/extensions/extension_context_menu_model.h" | 19 #include "chrome/browser/extensions/extension_context_menu_model.h" |
| 19 #include "chrome/browser/extensions/extension_service.h" | 20 #include "chrome/browser/extensions/extension_service.h" |
| 20 #include "chrome/browser/extensions/image_loading_tracker.h" | |
| 21 #include "chrome/browser/profiles/profile.h" | 21 #include "chrome/browser/profiles/profile.h" |
| 22 #include "chrome/browser/sessions/restore_tab_helper.h" | 22 #include "chrome/browser/sessions/restore_tab_helper.h" |
| 23 #include "chrome/browser/ui/browser.h" | 23 #include "chrome/browser/ui/browser.h" |
| 24 #include "chrome/browser/ui/browser_tabstrip.h" | 24 #include "chrome/browser/ui/browser_tabstrip.h" |
| 25 #include "chrome/browser/ui/gtk/browser_window_gtk.h" | 25 #include "chrome/browser/ui/gtk/browser_window_gtk.h" |
| 26 #include "chrome/browser/ui/gtk/extensions/extension_popup_gtk.h" | 26 #include "chrome/browser/ui/gtk/extensions/extension_popup_gtk.h" |
| 27 #include "chrome/browser/ui/gtk/gtk_chrome_button.h" | 27 #include "chrome/browser/ui/gtk/gtk_chrome_button.h" |
| 28 #include "chrome/browser/ui/gtk/gtk_chrome_shrinkable_hbox.h" | 28 #include "chrome/browser/ui/gtk/gtk_chrome_shrinkable_hbox.h" |
| 29 #include "chrome/browser/ui/gtk/gtk_theme_service.h" | 29 #include "chrome/browser/ui/gtk/gtk_theme_service.h" |
| 30 #include "chrome/browser/ui/gtk/gtk_util.h" | 30 #include "chrome/browser/ui/gtk/gtk_util.h" |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 84 gint WidthForIconCount(gint icon_count) { | 84 gint WidthForIconCount(gint icon_count) { |
| 85 return std::max((kButtonWidth + kButtonPadding) * icon_count - kButtonPadding, | 85 return std::max((kButtonWidth + kButtonPadding) * icon_count - kButtonPadding, |
| 86 0); | 86 0); |
| 87 } | 87 } |
| 88 | 88 |
| 89 } // namespace | 89 } // namespace |
| 90 | 90 |
| 91 using ui::SimpleMenuModel; | 91 using ui::SimpleMenuModel; |
| 92 | 92 |
| 93 class BrowserActionButton : public content::NotificationObserver, | 93 class BrowserActionButton : public content::NotificationObserver, |
| 94 public ImageLoadingTracker::Observer, | 94 public ExtensionActionIconFactory::Observer, |
| 95 public ExtensionContextMenuModel::PopupDelegate, | 95 public ExtensionContextMenuModel::PopupDelegate, |
| 96 public MenuGtk::Delegate { | 96 public MenuGtk::Delegate { |
| 97 public: | 97 public: |
| 98 BrowserActionButton(BrowserActionsToolbarGtk* toolbar, | 98 BrowserActionButton(BrowserActionsToolbarGtk* toolbar, |
| 99 const Extension* extension, | 99 const Extension* extension, |
| 100 GtkThemeService* theme_provider) | 100 GtkThemeService* theme_provider) |
| 101 : toolbar_(toolbar), | 101 : toolbar_(toolbar), |
| 102 extension_(extension), | 102 extension_(extension), |
| 103 image_(NULL), | 103 image_(NULL), |
| 104 tracker_(this), | 104 ALLOW_THIS_IN_INITIALIZER_LIST(icon_factory_(extension, this)), |
| 105 tab_specific_icon_(NULL), | |
| 106 default_icon_(NULL), | |
| 107 accel_group_(NULL) { | 105 accel_group_(NULL) { |
| 108 button_.reset(new CustomDrawButton( | 106 button_.reset(new CustomDrawButton( |
| 109 theme_provider, | 107 theme_provider, |
| 110 IDR_BROWSER_ACTION, | 108 IDR_BROWSER_ACTION, |
| 111 IDR_BROWSER_ACTION_P, | 109 IDR_BROWSER_ACTION_P, |
| 112 IDR_BROWSER_ACTION_H, | 110 IDR_BROWSER_ACTION_H, |
| 113 0, | 111 0, |
| 114 NULL)); | 112 NULL)); |
| 115 gtk_widget_set_size_request(button(), kButtonWidth, kButtonWidth); | 113 gtk_widget_set_size_request(button(), kButtonWidth, kButtonWidth); |
| 116 alignment_.Own(gtk_alignment_new(0, 0, 1, 1)); | 114 alignment_.Own(gtk_alignment_new(0, 0, 1, 1)); |
| 117 gtk_container_add(GTK_CONTAINER(alignment_.get()), button()); | 115 gtk_container_add(GTK_CONTAINER(alignment_.get()), button()); |
| 118 gtk_widget_show(button()); | 116 gtk_widget_show(button()); |
| 119 | 117 |
| 120 DCHECK(extension_->browser_action()); | 118 DCHECK(extension_->browser_action()); |
| 121 | 119 |
| 122 // The Browser Action API does not allow the default icon path to be | |
| 123 // changed at runtime, so we can load this now and cache it. | |
| 124 std::string path = extension_->browser_action()->default_icon_path(); | |
| 125 if (!path.empty()) { | |
| 126 tracker_.LoadImage(extension_, extension_->GetResource(path), | |
| 127 gfx::Size(Extension::kBrowserActionIconMaxSize, | |
| 128 Extension::kBrowserActionIconMaxSize), | |
| 129 ImageLoadingTracker::DONT_CACHE); | |
| 130 } | |
| 131 | |
| 132 UpdateState(); | 120 UpdateState(); |
| 133 | 121 |
| 134 signals_.Connect(button(), "button-press-event", | 122 signals_.Connect(button(), "button-press-event", |
| 135 G_CALLBACK(OnButtonPress), this); | 123 G_CALLBACK(OnButtonPress), this); |
| 136 signals_.Connect(button(), "clicked", | 124 signals_.Connect(button(), "clicked", |
| 137 G_CALLBACK(OnClicked), this); | 125 G_CALLBACK(OnClicked), this); |
| 138 signals_.Connect(button(), "drag-begin", | 126 signals_.Connect(button(), "drag-begin", |
| 139 G_CALLBACK(&OnDragBegin), this); | 127 G_CALLBACK(&OnDragBegin), this); |
| 140 signals_.ConnectAfter(widget(), "expose-event", | 128 signals_.ConnectAfter(widget(), "expose-event", |
| 141 G_CALLBACK(OnExposeEvent), this); | 129 G_CALLBACK(OnExposeEvent), this); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 163 toolbar->browser()->profile()->GetOriginalProfile())); | 151 toolbar->browser()->profile()->GetOriginalProfile())); |
| 164 registrar_.Add( | 152 registrar_.Add( |
| 165 this, chrome::NOTIFICATION_EXTENSION_COMMAND_REMOVED, | 153 this, chrome::NOTIFICATION_EXTENSION_COMMAND_REMOVED, |
| 166 content::Source<Profile>( | 154 content::Source<Profile>( |
| 167 toolbar->browser()->profile()->GetOriginalProfile())); | 155 toolbar->browser()->profile()->GetOriginalProfile())); |
| 168 } | 156 } |
| 169 | 157 |
| 170 ~BrowserActionButton() { | 158 ~BrowserActionButton() { |
| 171 DisconnectBrowserActionPopupAccelerator(); | 159 DisconnectBrowserActionPopupAccelerator(); |
| 172 | 160 |
| 173 if (tab_specific_icon_) | |
| 174 g_object_unref(tab_specific_icon_); | |
| 175 | |
| 176 if (default_icon_) | |
| 177 g_object_unref(default_icon_); | |
| 178 | |
| 179 alignment_.Destroy(); | 161 alignment_.Destroy(); |
| 180 } | 162 } |
| 181 | 163 |
| 182 GtkWidget* button() { return button_->widget(); } | 164 GtkWidget* button() { return button_->widget(); } |
| 183 | 165 |
| 184 GtkWidget* widget() { return alignment_.get(); } | 166 GtkWidget* widget() { return alignment_.get(); } |
| 185 | 167 |
| 186 const Extension* extension() { return extension_; } | 168 const Extension* extension() { return extension_; } |
| 187 | 169 |
| 188 // NotificationObserver implementation. | 170 // NotificationObserver implementation. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 211 DisconnectBrowserActionPopupAccelerator(); | 193 DisconnectBrowserActionPopupAccelerator(); |
| 212 } | 194 } |
| 213 break; | 195 break; |
| 214 } | 196 } |
| 215 default: | 197 default: |
| 216 NOTREACHED(); | 198 NOTREACHED(); |
| 217 break; | 199 break; |
| 218 } | 200 } |
| 219 } | 201 } |
| 220 | 202 |
| 221 // ImageLoadingTracker::Observer implementation. | 203 // ExtensionActionIconFactory::Observer implementation. |
| 222 void OnImageLoaded(const gfx::Image& image, | 204 void OnIconUpdated() OVERRIDE { |
| 223 const std::string& extension_id, | |
| 224 int index) OVERRIDE { | |
| 225 extension_->browser_action()->CacheIcon( | |
| 226 extension_->browser_action()->default_icon_path(), image); | |
| 227 UpdateState(); | 205 UpdateState(); |
| 228 } | 206 } |
| 229 | 207 |
| 230 // Updates the button based on the latest state from the associated | 208 // Updates the button based on the latest state from the associated |
| 231 // browser action. | 209 // browser action. |
| 232 void UpdateState() { | 210 void UpdateState() { |
| 233 int tab_id = toolbar_->GetCurrentTabId(); | 211 int tab_id = toolbar_->GetCurrentTabId(); |
| 234 if (tab_id < 0) | 212 if (tab_id < 0) |
| 235 return; | 213 return; |
| 236 | 214 |
| 237 std::string tooltip = extension_->browser_action()->GetTitle(tab_id); | 215 std::string tooltip = extension_->browser_action()->GetTitle(tab_id); |
| 238 if (tooltip.empty()) | 216 if (tooltip.empty()) |
| 239 gtk_widget_set_has_tooltip(button(), FALSE); | 217 gtk_widget_set_has_tooltip(button(), FALSE); |
| 240 else | 218 else |
| 241 gtk_widget_set_tooltip_text(button(), tooltip.c_str()); | 219 gtk_widget_set_tooltip_text(button(), tooltip.c_str()); |
| 242 | 220 |
| 243 gfx::Image image = extension_->browser_action()->GetIcon(tab_id); | 221 gfx::Image image = |
| 222 extension_->browser_action()->GetIcon(tab_id, &icon_factory_); |
| 244 if (!image.IsEmpty()) | 223 if (!image.IsEmpty()) |
| 245 SetImage(image.ToGdkPixbuf()); | 224 SetImage(image.ToGdkPixbuf()); |
| 246 bool enabled = extension_->browser_action()->GetIsVisible(tab_id); | 225 bool enabled = extension_->browser_action()->GetIsVisible(tab_id); |
| 247 gtk_widget_set_sensitive(button(), enabled); | 226 gtk_widget_set_sensitive(button(), enabled); |
| 248 | 227 |
| 249 gtk_widget_queue_draw(button()); | 228 gtk_widget_queue_draw(button()); |
| 250 } | 229 } |
| 251 | 230 |
| 252 gfx::Image GetIcon() { | 231 gfx::Image GetIcon() { |
| 253 return extension_->browser_action()->GetIcon( | 232 return extension_->browser_action()->GetIcon( |
| 254 toolbar_->GetCurrentTabId()); | 233 toolbar_->GetCurrentTabId(), &icon_factory_); |
| 255 } | 234 } |
| 256 | 235 |
| 257 MenuGtk* GetContextMenu() { | 236 MenuGtk* GetContextMenu() { |
| 258 if (!extension_->ShowConfigureContextMenus()) | 237 if (!extension_->ShowConfigureContextMenus()) |
| 259 return NULL; | 238 return NULL; |
| 260 | 239 |
| 261 context_menu_model_ = | 240 context_menu_model_ = |
| 262 new ExtensionContextMenuModel(extension_, toolbar_->browser(), this); | 241 new ExtensionContextMenuModel(extension_, toolbar_->browser(), this); |
| 263 context_menu_.reset( | 242 context_menu_.reset( |
| 264 new MenuGtk(this, context_menu_model_.get())); | 243 new MenuGtk(this, context_menu_model_.get())); |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 455 | 434 |
| 456 // The top level widget (parent of |button_|). | 435 // The top level widget (parent of |button_|). |
| 457 ui::OwnedWidgetGtk alignment_; | 436 ui::OwnedWidgetGtk alignment_; |
| 458 | 437 |
| 459 // The one image subwidget in |button_|. We keep this out so we don't alter | 438 // The one image subwidget in |button_|. We keep this out so we don't alter |
| 460 // the widget hierarchy while changing the button image because changing the | 439 // the widget hierarchy while changing the button image because changing the |
| 461 // GTK widget hierarchy invalidates all tooltips and several popular | 440 // GTK widget hierarchy invalidates all tooltips and several popular |
| 462 // extensions change browser action icon in a loop. | 441 // extensions change browser action icon in a loop. |
| 463 GtkWidget* image_; | 442 GtkWidget* image_; |
| 464 | 443 |
| 465 // Loads the button's icons for us on the file thread. | 444 // The object that browser action will use to create icon for us. |
| 466 ImageLoadingTracker tracker_; | 445 // It may load icon asynchronously (in which case initial icon returned by |
| 467 | 446 // the action will be blank), so we have to observe it for icon's updates. |
| 468 // If we are displaying a tab-specific icon, it will be here. | 447 ExtensionActionIconFactory icon_factory_; |
| 469 GdkPixbuf* tab_specific_icon_; | |
| 470 | |
| 471 // If the browser action has a default icon, it will be here. | |
| 472 GdkPixbuf* default_icon_; | |
| 473 | 448 |
| 474 // Same as |default_icon_|, but stored as SkBitmap. | 449 // Same as |default_icon_|, but stored as SkBitmap. |
| 475 SkBitmap default_skbitmap_; | 450 SkBitmap default_skbitmap_; |
| 476 | 451 |
| 477 ui::GtkSignalRegistrar signals_; | 452 ui::GtkSignalRegistrar signals_; |
| 478 content::NotificationRegistrar registrar_; | 453 content::NotificationRegistrar registrar_; |
| 479 | 454 |
| 480 // The accelerator group used to handle accelerators, owned by this object. | 455 // The accelerator group used to handle accelerators, owned by this object. |
| 481 GtkAccelGroup* accel_group_; | 456 GtkAccelGroup* accel_group_; |
| 482 | 457 |
| (...skipping 611 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1094 | 1069 |
| 1095 menu->PopupAsContext(gfx::Point(event->x_root, event->y_root), | 1070 menu->PopupAsContext(gfx::Point(event->x_root, event->y_root), |
| 1096 event->time); | 1071 event->time); |
| 1097 return TRUE; | 1072 return TRUE; |
| 1098 } | 1073 } |
| 1099 | 1074 |
| 1100 void BrowserActionsToolbarGtk::OnButtonShowOrHide(GtkWidget* sender) { | 1075 void BrowserActionsToolbarGtk::OnButtonShowOrHide(GtkWidget* sender) { |
| 1101 if (!resize_animation_.is_animating()) | 1076 if (!resize_animation_.is_animating()) |
| 1102 UpdateChevronVisibility(); | 1077 UpdateChevronVisibility(); |
| 1103 } | 1078 } |
| OLD | NEW |