Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(149)

Side by Side Diff: chrome/browser/gtk/browser_actions_toolbar_gtk.cc

Issue 306044: Refactor implementation of BrowserActions, and add support for (Closed)
Patch Set: Make it work on linux too Created 11 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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/gtk/browser_actions_toolbar_gtk.h" 5 #include "chrome/browser/gtk/browser_actions_toolbar_gtk.h"
6 6
7 #include <gtk/gtk.h> 7 #include <gtk/gtk.h>
8 #include <vector> 8 #include <vector>
9 9
10 #include "app/gfx/canvas_paint.h" 10 #include "app/gfx/canvas_paint.h"
11 #include "app/gfx/gtk_util.h" 11 #include "app/gfx/gtk_util.h"
12 #include "chrome/browser/browser.h" 12 #include "chrome/browser/browser.h"
13 #include "chrome/browser/extensions/extension_browser_event_router.h" 13 #include "chrome/browser/extensions/extension_browser_event_router.h"
14 #include "chrome/browser/extensions/extensions_service.h" 14 #include "chrome/browser/extensions/extensions_service.h"
15 #include "chrome/browser/extensions/image_loading_tracker.h" 15 #include "chrome/browser/extensions/image_loading_tracker.h"
16 #include "chrome/browser/gtk/extension_popup_gtk.h" 16 #include "chrome/browser/gtk/extension_popup_gtk.h"
17 #include "chrome/browser/gtk/gtk_chrome_button.h" 17 #include "chrome/browser/gtk/gtk_chrome_button.h"
18 #include "chrome/browser/gtk/gtk_theme_provider.h" 18 #include "chrome/browser/gtk/gtk_theme_provider.h"
19 #include "chrome/browser/profile.h" 19 #include "chrome/browser/profile.h"
20 #include "chrome/browser/tab_contents/tab_contents.h"
20 #include "chrome/common/extensions/extension.h" 21 #include "chrome/common/extensions/extension.h"
22 #include "chrome/common/extensions/extension_action2.h"
21 #include "chrome/common/notification_details.h" 23 #include "chrome/common/notification_details.h"
22 #include "chrome/common/notification_service.h" 24 #include "chrome/common/notification_service.h"
23 #include "chrome/common/notification_source.h" 25 #include "chrome/common/notification_source.h"
24 #include "chrome/common/notification_type.h" 26 #include "chrome/common/notification_type.h"
25 27
26 // The size of each button on the toolbar. 28 // The size of each button on the toolbar.
27 static const int kButtonSize = 29; 29 static const int kButtonSize = 29;
28 30
29 class BrowserActionButton : public NotificationObserver, 31 class BrowserActionButton : public NotificationObserver,
30 public ImageLoadingTracker::Observer { 32 public ImageLoadingTracker::Observer {
31 public: 33 public:
32 BrowserActionButton(Browser* browser, Extension* extension) 34 BrowserActionButton(BrowserActionsToolbarGtk* toolbar,
33 : browser_(browser), 35 Extension* extension)
36 : toolbar_(toolbar),
34 extension_(extension), 37 extension_(extension),
35 button_(gtk_chrome_button_new()), 38 button_(gtk_chrome_button_new()),
36 gdk_icon_(NULL) { 39 tracker_(NULL),
40 tab_specific_icon_(NULL),
41 default_icon_(NULL) {
37 DCHECK(extension_->browser_action()); 42 DCHECK(extension_->browser_action());
38 43
39 gtk_widget_set_size_request(button_.get(), kButtonSize, kButtonSize); 44 gtk_widget_set_size_request(button_.get(), kButtonSize, kButtonSize);
40 45
41 browser_action_icons_.resize( 46 UpdateState();
42 extension->browser_action()->icon_paths().size()); 47
43 tracker_ = new ImageLoadingTracker(this, browser_action_icons_.size()); 48 // The Browser Action API does not allow the default icon path to be
44 for (size_t i = 0; i < extension->browser_action()->icon_paths().size(); 49 // changed at runtime, so we can load this now and cache it.
45 ++i) { 50 std::string path = extension_->browser_action()->GetDefaultIconPath();
46 tracker_->PostLoadImageTask( 51 if (!path.empty()) {
47 extension->GetResource(extension->browser_action()->icon_paths()[i]), 52 tracker_ = new ImageLoadingTracker(this, 1);
53 tracker_->PostLoadImageTask(extension_->GetResource(path),
48 gfx::Size(Extension::kBrowserActionIconMaxSize, 54 gfx::Size(Extension::kBrowserActionIconMaxSize,
49 Extension::kBrowserActionIconMaxSize)); 55 Extension::kBrowserActionIconMaxSize));
50 } 56 }
51 57
52 OnStateUpdated();
53
54 // We need to hook up extension popups here. http://crbug.com/23897 58 // We need to hook up extension popups here. http://crbug.com/23897
55 g_signal_connect(button_.get(), "clicked", 59 g_signal_connect(button_.get(), "clicked",
56 G_CALLBACK(OnButtonClicked), this); 60 G_CALLBACK(OnButtonClicked), this);
57 g_signal_connect_after(button_.get(), "expose-event", 61 g_signal_connect_after(button_.get(), "expose-event",
58 G_CALLBACK(OnExposeEvent), this); 62 G_CALLBACK(OnExposeEvent), this);
59 63
60 registrar_.Add(this, NotificationType::EXTENSION_BROWSER_ACTION_UPDATED, 64 registrar_.Add(this, NotificationType::EXTENSION_BROWSER_ACTION_UPDATED,
61 Source<ExtensionAction>(extension->browser_action())); 65 Source<ExtensionAction2>(extension->browser_action()));
62 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, 66 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
63 NotificationService::AllSources()); 67 NotificationService::AllSources());
64 68
65 OnThemeChanged(); 69 OnThemeChanged();
66 } 70 }
67 71
68 ~BrowserActionButton() { 72 ~BrowserActionButton() {
69 if (gdk_icon_) 73 if (tab_specific_icon_)
70 g_object_unref(gdk_icon_); 74 g_object_unref(tab_specific_icon_);
75
76 if (default_icon_)
77 g_object_unref(default_icon_);
71 78
72 button_.Destroy(); 79 button_.Destroy();
73 tracker_->StopTrackingImageLoad(); 80
81 if (tracker_)
82 tracker_->StopTrackingImageLoad();
74 } 83 }
75 84
76 GtkWidget* widget() { return button_.get(); } 85 GtkWidget* widget() { return button_.get(); }
77 86
78 void Observe(NotificationType type, 87 void Observe(NotificationType type,
79 const NotificationSource& source, 88 const NotificationSource& source,
80 const NotificationDetails& details) { 89 const NotificationDetails& details) {
81 if (type == NotificationType::EXTENSION_BROWSER_ACTION_UPDATED) 90 if (type == NotificationType::EXTENSION_BROWSER_ACTION_UPDATED)
82 OnStateUpdated(); 91 UpdateState();
83 else if (type == NotificationType::BROWSER_THEME_CHANGED) 92 else if (type == NotificationType::BROWSER_THEME_CHANGED)
84 OnThemeChanged(); 93 OnThemeChanged();
85 else 94 else
86 NOTREACHED(); 95 NOTREACHED();
87 } 96 }
88 97
89 // ImageLoadingTracker::Observer implementation. 98 // ImageLoadingTracker::Observer implementation.
90 void OnImageLoaded(SkBitmap* image, size_t index) { 99 void OnImageLoaded(SkBitmap* image, size_t index) {
91 DCHECK(index < browser_action_icons_.size()); 100 default_icon_ = gfx::GdkPixbufFromSkBitmap(image);
92 browser_action_icons_[index] = image ? *image : SkBitmap(); 101 UpdateState();
102 }
93 103
94 OnStateUpdated(); 104 // Updates the button based on the latest state from the associated
105 // browser action.
106 void UpdateState() {
107 int tab_id = toolbar_->GetCurrentTabId();
108 if (tab_id < 0)
109 return;
110
111 gtk_widget_set_tooltip_text(button_.get(),
112 extension_->browser_action()->GetTitle(tab_id).c_str());
113
114 SkBitmap image = extension_->browser_action()->GetIcon(tab_id);
115 if (!image.isNull()) {
116 GdkPixbuf* previous_gdk_icon = tab_specific_icon_;
117 tab_specific_icon_ = gfx::GdkPixbufFromSkBitmap(&image);
118 SetImage(tab_specific_icon_);
119 if (previous_gdk_icon)
120 g_object_unref(previous_gdk_icon);
121 } else if (default_icon_) {
122 SetImage(default_icon_);
123 }
95 } 124 }
96 125
97 private: 126 private:
98 // Called when the tooltip has changed or an image has loaded. 127 void SetImage(GdkPixbuf* image) {
99 void OnStateUpdated() { 128 gtk_button_set_image(GTK_BUTTON(button_.get()),
100 gtk_widget_set_tooltip_text(button_.get(), 129 gtk_image_new_from_pixbuf(image));
101 extension_->browser_action_state()->title().c_str());
102
103 SkBitmap* image = extension_->browser_action_state()->icon();
104 if (!image) {
105 if (static_cast<size_t>(
106 extension_->browser_action_state()->icon_index()) <
107 browser_action_icons_.size()) {
108 image = &browser_action_icons_[
109 extension_->browser_action_state()->icon_index()];
110 }
111 }
112
113 if (image && !image->empty()) {
114 GdkPixbuf* current_gdk_icon = gdk_icon_;
115 gdk_icon_ = gfx::GdkPixbufFromSkBitmap(image);
116 gtk_button_set_image(GTK_BUTTON(button_.get()),
117 gtk_image_new_from_pixbuf(gdk_icon_));
118 if (current_gdk_icon)
119 g_object_unref(current_gdk_icon);
120 }
121 } 130 }
122 131
123 void OnThemeChanged() { 132 void OnThemeChanged() {
124 gtk_chrome_button_set_use_gtk_rendering(GTK_CHROME_BUTTON(button_.get()), 133 gtk_chrome_button_set_use_gtk_rendering(GTK_CHROME_BUTTON(button_.get()),
125 GtkThemeProvider::GetFrom(browser_->profile())->UseGtkTheme()); 134 GtkThemeProvider::GetFrom(
135 toolbar_->browser()->profile())->UseGtkTheme());
126 } 136 }
127 137
128 static void OnButtonClicked(GtkWidget* widget, BrowserActionButton* action) { 138 static void OnButtonClicked(GtkWidget* widget, BrowserActionButton* action) {
129 if (action->extension_->browser_action()->is_popup()) { 139 if (action->extension_->browser_action()->has_popup()) {
130 ExtensionPopupGtk::Show(action->extension_->browser_action()->popup_url(), 140 ExtensionPopupGtk::Show(action->extension_->browser_action()->popup_url(),
131 action->browser_, gfx::Rect(widget->allocation)); 141 action->toolbar_->browser(),
132 142 gfx::Rect(widget->allocation));
133 } else { 143 } else {
134 ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted( 144 ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted(
135 action->browser_->profile(), action->extension_->id(), 145 action->toolbar_->browser()->profile(), action->extension_->id(),
136 action->browser_); 146 action->toolbar_->browser());
137 } 147 }
138 } 148 }
139 149
140 static gboolean OnExposeEvent(GtkWidget* widget, 150 static gboolean OnExposeEvent(GtkWidget* widget,
141 GdkEventExpose* event, 151 GdkEventExpose* event,
142 BrowserActionButton* action) { 152 BrowserActionButton* button) {
143 if (action->extension_->browser_action_state()->badge_text().empty()) 153 int tab_id = button->toolbar_->GetCurrentTabId();
154 if (tab_id < 0)
155 return FALSE;
156
157 ExtensionAction2* action = button->extension_->browser_action();
158 if (action->GetBadgeText(tab_id).empty())
144 return FALSE; 159 return FALSE;
145 160
146 gfx::CanvasPaint canvas(event, false); 161 gfx::CanvasPaint canvas(event, false);
147 gfx::Rect bounding_rect(widget->allocation); 162 gfx::Rect bounding_rect(widget->allocation);
148 action->extension_->browser_action_state()->PaintBadge(&canvas, 163 ExtensionActionState::PaintBadge(&canvas, bounding_rect,
149 bounding_rect); 164 action->GetBadgeText(tab_id),
165 action->GetBadgeTextColor(tab_id),
166 action->GetBadgeBackgroundColor(tab_id));
150 return FALSE; 167 return FALSE;
151 } 168 }
152 169
153 // The Browser that executes a command when the button is pressed. 170 // The toolbar containing this button.
154 Browser* browser_; 171 BrowserActionsToolbarGtk* toolbar_;
155 172
156 // The extension that contains this browser action. 173 // The extension that contains this browser action.
157 Extension* extension_; 174 Extension* extension_;
158 175
159 // The gtk widget for this browser action. 176 // The gtk widget for this browser action.
160 OwnedWidgetGtk button_; 177 OwnedWidgetGtk button_;
161 178
162 // Loads the button's icons for us on the file thread. 179 // Loads the button's icons for us on the file thread.
163 ImageLoadingTracker* tracker_; 180 ImageLoadingTracker* tracker_;
164 181
165 // Icons for all the different states the button can be in. These will be 182 // If we are displaying a tab-specific icon, it will be here.
166 // empty while they are loading. 183 GdkPixbuf* tab_specific_icon_;
167 std::vector<SkBitmap> browser_action_icons_;
168 184
169 // SkBitmap must be converted to GdkPixbuf before assignment to the button. 185 // If the browser action has a default icon, it will be here.
170 // This stores the current icon while it is in use. 186 GdkPixbuf* default_icon_;
171 GdkPixbuf* gdk_icon_;
172 187
173 NotificationRegistrar registrar_; 188 NotificationRegistrar registrar_;
174 }; 189 };
175 190
176 BrowserActionsToolbarGtk::BrowserActionsToolbarGtk(Browser* browser) 191 BrowserActionsToolbarGtk::BrowserActionsToolbarGtk(Browser* browser)
177 : browser_(browser), 192 : browser_(browser),
178 profile_(browser->profile()), 193 profile_(browser->profile()),
179 hbox_(gtk_hbox_new(0, FALSE)) { 194 hbox_(gtk_hbox_new(0, FALSE)) {
180 ExtensionsService* extension_service = profile_->GetExtensionsService(); 195 ExtensionsService* extension_service = profile_->GetExtensionsService();
181 registrar_.Add(this, NotificationType::EXTENSION_LOADED, 196 registrar_.Add(this, NotificationType::EXTENSION_LOADED,
182 Source<ExtensionsService>(extension_service)); 197 Source<ExtensionsService>(extension_service));
183 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, 198 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
184 Source<ExtensionsService>(extension_service)); 199 Source<ExtensionsService>(extension_service));
185 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED, 200 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED,
186 Source<ExtensionsService>(extension_service)); 201 Source<ExtensionsService>(extension_service));
187 202
188 CreateAllButtons(); 203 CreateAllButtons();
189 } 204 }
190 205
191 BrowserActionsToolbarGtk::~BrowserActionsToolbarGtk() { 206 BrowserActionsToolbarGtk::~BrowserActionsToolbarGtk() {
192 hbox_.Destroy(); 207 hbox_.Destroy();
193 } 208 }
194 209
210 int BrowserActionsToolbarGtk::GetCurrentTabId() {
211 TabContents* selected_tab = browser_->GetSelectedTabContents();
212 if (!selected_tab)
213 return -1;
214
215 return selected_tab->controller().session_id().id();
216 }
217
218 void BrowserActionsToolbarGtk::Update() {
219 for (ExtensionButtonMap::iterator iter = extension_button_map_.begin();
220 iter != extension_button_map_.end(); ++iter) {
221 iter->second->UpdateState();
222 }
223 }
224
195 void BrowserActionsToolbarGtk::Observe(NotificationType type, 225 void BrowserActionsToolbarGtk::Observe(NotificationType type,
196 const NotificationSource& source, 226 const NotificationSource& source,
197 const NotificationDetails& details) { 227 const NotificationDetails& details) {
198 Extension* extension = Details<Extension>(details).ptr(); 228 Extension* extension = Details<Extension>(details).ptr();
199 229
200 if (type == NotificationType::EXTENSION_LOADED) { 230 if (type == NotificationType::EXTENSION_LOADED) {
201 CreateButtonForExtension(extension); 231 CreateButtonForExtension(extension);
202 } else if (type == NotificationType::EXTENSION_UNLOADED || 232 } else if (type == NotificationType::EXTENSION_UNLOADED ||
203 type == NotificationType::EXTENSION_UNLOADED_DISABLED) { 233 type == NotificationType::EXTENSION_UNLOADED_DISABLED) {
204 RemoveButtonForExtension(extension); 234 RemoveButtonForExtension(extension);
205 } else { 235 } else {
206 NOTREACHED() << "Received unexpected notification"; 236 NOTREACHED() << "Received unexpected notification";
207 } 237 }
208 } 238 }
209 239
210 void BrowserActionsToolbarGtk::CreateAllButtons() { 240 void BrowserActionsToolbarGtk::CreateAllButtons() {
211 ExtensionsService* extension_service = profile_->GetExtensionsService(); 241 ExtensionsService* extension_service = profile_->GetExtensionsService();
212 if (!extension_service) // The |extension_service| can be NULL in Incognito. 242 if (!extension_service) // The |extension_service| can be NULL in Incognito.
213 return; 243 return;
214 244
215 // Get all browser actions, including those with popups. 245 for (size_t i = 0; i < extension_service->extensions()->size(); ++i) {
216 std::vector<ExtensionAction*> browser_actions =
217 extension_service->GetBrowserActions(true);
218
219 for (size_t i = 0; i < browser_actions.size(); ++i) {
220 Extension* extension = extension_service->GetExtensionById( 246 Extension* extension = extension_service->GetExtensionById(
221 browser_actions[i]->extension_id()); 247 extension_service->extensions()->at(i)->id());
222 CreateButtonForExtension(extension); 248 CreateButtonForExtension(extension);
223 } 249 }
224 } 250 }
225 251
226 void BrowserActionsToolbarGtk::CreateButtonForExtension(Extension* extension) { 252 void BrowserActionsToolbarGtk::CreateButtonForExtension(Extension* extension) {
227 // Only show extensions with browser actions and that have an icon. 253 // Only show extensions with browser actions.
228 if (!extension->browser_action() || 254 if (!extension->browser_action())
229 extension->browser_action()->icon_paths().empty()) {
230 return; 255 return;
231 }
232 256
233 RemoveButtonForExtension(extension); 257 RemoveButtonForExtension(extension);
234 linked_ptr<BrowserActionButton> button( 258 linked_ptr<BrowserActionButton> button(
235 new BrowserActionButton(browser_, extension)); 259 new BrowserActionButton(this, extension));
236 gtk_box_pack_end(GTK_BOX(hbox_.get()), button->widget(), FALSE, FALSE, 0); 260 gtk_box_pack_end(GTK_BOX(hbox_.get()), button->widget(), FALSE, FALSE, 0);
237 gtk_widget_show(button->widget()); 261 gtk_widget_show(button->widget());
238 extension_button_map_[extension->id()] = button; 262 extension_button_map_[extension->id()] = button;
239 263
240 UpdateVisibility(); 264 UpdateVisibility();
241 } 265 }
242 266
243 void BrowserActionsToolbarGtk::RemoveButtonForExtension(Extension* extension) { 267 void BrowserActionsToolbarGtk::RemoveButtonForExtension(Extension* extension) {
244 if (extension_button_map_.erase(extension->id())) 268 if (extension_button_map_.erase(extension->id()))
245 UpdateVisibility(); 269 UpdateVisibility();
246 } 270 }
247 271
248 void BrowserActionsToolbarGtk::UpdateVisibility() { 272 void BrowserActionsToolbarGtk::UpdateVisibility() {
249 if (button_count() == 0) 273 if (button_count() == 0)
250 gtk_widget_hide(widget()); 274 gtk_widget_hide(widget());
251 else 275 else
252 gtk_widget_show(widget()); 276 gtk_widget_show(widget());
253 } 277 }
OLDNEW
« no previous file with comments | « chrome/browser/gtk/browser_actions_toolbar_gtk.h ('k') | chrome/browser/gtk/browser_toolbar_gtk.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698