summaryrefslogtreecommitdiffstats
path: root/chrome/browser/gtk
diff options
context:
space:
mode:
authorestade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-13 20:06:23 +0000
committerestade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-13 20:06:23 +0000
commit67274c96843e6ecc7e299f6165c1ea2bb02f3361 (patch)
treec467e2bc8a9ca8ffbe6b7d1c26e2b3a11db729a7 /chrome/browser/gtk
parentb5d079536bcbf33c657fd96079bb7b2bd9644c0e (diff)
downloadchromium_src-67274c96843e6ecc7e299f6165c1ea2bb02f3361.zip
chromium_src-67274c96843e6ecc7e299f6165c1ea2bb02f3361.tar.gz
chromium_src-67274c96843e6ecc7e299f6165c1ea2bb02f3361.tar.bz2
GTK: Browser actions toolbar.
We don't have html popups yet but clicking should work (e.g. print button works). TODO: port browser_action in proc browser test. TODO: badges BUG=23882 TEST=loaded gmail browser action extension, loaded print bookmark bar extension, loaded them both, unloaded, disabled, enabled, etc. Review URL: http://codereview.chromium.org/273025 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28869 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/gtk')
-rw-r--r--chrome/browser/gtk/browser_actions_toolbar_gtk.cc197
-rw-r--r--chrome/browser/gtk/browser_actions_toolbar_gtk.h71
-rw-r--r--chrome/browser/gtk/browser_toolbar_gtk.cc10
-rw-r--r--chrome/browser/gtk/browser_toolbar_gtk.h2
4 files changed, 280 insertions, 0 deletions
diff --git a/chrome/browser/gtk/browser_actions_toolbar_gtk.cc b/chrome/browser/gtk/browser_actions_toolbar_gtk.cc
new file mode 100644
index 0000000..cf90faa
--- /dev/null
+++ b/chrome/browser/gtk/browser_actions_toolbar_gtk.cc
@@ -0,0 +1,197 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/gtk/browser_actions_toolbar_gtk.h"
+
+#include <gtk/gtk.h>
+#include <vector>
+
+#include "app/gfx/gtk_util.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/image_loading_tracker.h"
+#include "chrome/browser/gtk/gtk_chrome_button.h"
+#include "chrome/browser/profile.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+
+// The size of each button on the toolbar.
+static const int kButtonSize = 29;
+
+class BrowserActionButton : public NotificationObserver,
+ public ImageLoadingTracker::Observer {
+ public:
+ BrowserActionButton(Browser* browser, Extension* extension)
+ : browser_(browser),
+ extension_(extension),
+ button_(gtk_chrome_button_new()) {
+ DCHECK(extension_->browser_action());
+
+ gtk_widget_set_size_request(button_.get(), kButtonSize, kButtonSize);
+
+ browser_action_icons_.resize(
+ extension->browser_action()->icon_paths().size(), NULL);
+ tracker_ = new ImageLoadingTracker(this, browser_action_icons_.size());
+ for (size_t i = 0; i < extension->browser_action()->icon_paths().size();
+ ++i) {
+ tracker_->PostLoadImageTask(extension->GetResource(
+ extension->browser_action()->icon_paths()[i]));
+ }
+
+ OnStateUpdated();
+
+ // We need to hook up extension popups here. http://crbug.com/23897
+ g_signal_connect(button_.get(), "clicked",
+ G_CALLBACK(OnButtonClicked), this);
+
+ registrar_.Add(this, NotificationType::EXTENSION_BROWSER_ACTION_UPDATED,
+ Source<ExtensionAction>(extension->browser_action()));
+ }
+
+ ~BrowserActionButton() {
+ for (size_t i = 0; i < browser_action_icons_.size(); ++i) {
+ if (browser_action_icons_[i])
+ g_object_unref(browser_action_icons_[i]);
+ }
+
+ button_.Destroy();
+ tracker_->StopTrackingImageLoad();
+ }
+
+ GtkWidget* widget() { return button_.get(); }
+
+ static void OnButtonClicked(GtkWidget* widget, BrowserActionButton* action) {
+ action->browser_->ExecuteCommand(
+ action->extension_->browser_action()->command_id());
+ }
+
+ // Called when the tooltip has changed or an image has loaded.
+ void OnStateUpdated() {
+ gtk_widget_set_tooltip_text(button_.get(),
+ extension_->browser_action_state()->title().c_str());
+
+ if (browser_action_icons_.empty())
+ return;
+
+ GdkPixbuf* image =
+ browser_action_icons_[extension_->browser_action_state()->icon_index()];
+ if (image) {
+ gtk_button_set_image(GTK_BUTTON(button_.get()),
+ gtk_image_new_from_pixbuf(image));
+ }
+ }
+
+ // NotificationObserver implementation.
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ OnStateUpdated();
+ }
+
+ // ImageLoadingTracker::Observer implementation.
+ void OnImageLoaded(SkBitmap* image, size_t index) {
+ browser_action_icons_[index] = gfx::GdkPixbufFromSkBitmap(image);
+ OnStateUpdated();
+ }
+
+ private:
+ // The Browser that executes a command when the button is pressed.
+ Browser* browser_;
+
+ // The extension that contains this browser action.
+ Extension* extension_;
+
+ // The gtk widget for this browser action.
+ OwnedWidgetGtk button_;
+
+ // Loads the button's icons for us on the file thread.
+ ImageLoadingTracker* tracker_;
+
+ // Icons for all the different states the button can be in. These will be NULL
+ // while they are loading.
+ std::vector<GdkPixbuf*> browser_action_icons_;
+
+ NotificationRegistrar registrar_;
+};
+
+BrowserActionsToolbarGtk::BrowserActionsToolbarGtk(Browser* browser)
+ : browser_(browser),
+ profile_(browser->profile()),
+ hbox_(gtk_hbox_new(0, FALSE)) {
+ ExtensionsService* extension_service = profile_->GetExtensionsService();
+ registrar_.Add(this, NotificationType::EXTENSION_LOADED,
+ Source<ExtensionsService>(extension_service));
+ registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
+ Source<ExtensionsService>(extension_service));
+ registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED,
+ Source<ExtensionsService>(extension_service));
+
+ CreateAllButtons();
+}
+
+BrowserActionsToolbarGtk::~BrowserActionsToolbarGtk() {
+ hbox_.Destroy();
+}
+
+void BrowserActionsToolbarGtk::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ Extension* extension = Details<Extension>(details).ptr();
+
+ if (type == NotificationType::EXTENSION_LOADED) {
+ CreateButtonForExtension(extension);
+ } else if (type == NotificationType::EXTENSION_UNLOADED ||
+ type == NotificationType::EXTENSION_UNLOADED_DISABLED) {
+ RemoveButtonForExtension(extension);
+ } else {
+ NOTREACHED() << "Received unexpected notification";
+ }
+}
+
+void BrowserActionsToolbarGtk::CreateAllButtons() {
+ ExtensionsService* extension_service = profile_->GetExtensionsService();
+ if (!extension_service) // The |extension_service| can be NULL in Incognito.
+ return;
+
+ // Get all browser actions, including those with popups.
+ std::vector<ExtensionAction*> browser_actions =
+ extension_service->GetBrowserActions(true);
+
+ for (size_t i = 0; i < browser_actions.size(); ++i) {
+ Extension* extension = extension_service->GetExtensionById(
+ browser_actions[i]->id());
+ CreateButtonForExtension(extension);
+ }
+}
+
+void BrowserActionsToolbarGtk::CreateButtonForExtension(Extension* extension) {
+ // Only show extensions with browser actions and that have an icon.
+ if (!extension->browser_action() ||
+ extension->browser_action()->icon_paths().empty()) {
+ return;
+ }
+
+ RemoveButtonForExtension(extension);
+ linked_ptr<BrowserActionButton> button(
+ new BrowserActionButton(browser_, extension));
+ gtk_box_pack_end(GTK_BOX(hbox_.get()), button->widget(), FALSE, FALSE, 0);
+ gtk_widget_show(button->widget());
+ extension_button_map_[extension->id()] = button;
+
+ UpdateVisibility();
+}
+
+void BrowserActionsToolbarGtk::RemoveButtonForExtension(Extension* extension) {
+ if (extension_button_map_.erase(extension->id()))
+ UpdateVisibility();
+}
+
+void BrowserActionsToolbarGtk::UpdateVisibility() {
+ if (button_count() == 0)
+ gtk_widget_hide(widget());
+ else
+ gtk_widget_show(widget());
+}
diff --git a/chrome/browser/gtk/browser_actions_toolbar_gtk.h b/chrome/browser/gtk/browser_actions_toolbar_gtk.h
new file mode 100644
index 0000000..4210889
--- /dev/null
+++ b/chrome/browser/gtk/browser_actions_toolbar_gtk.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_GTK_BROWSER_ACTIONS_TOOLBAR_GTK_H_
+#define CHROME_BROWSER_GTK_BROWSER_ACTIONS_TOOLBAR_GTK_H_
+
+#include <map>
+#include <string>
+
+#include "base/linked_ptr.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/owned_widget_gtk.h"
+
+class Browser;
+class BrowserActionButton;
+class Extension;
+class Profile;
+
+typedef struct _GtkWidget GtkWidget;
+
+class BrowserActionsToolbarGtk : public NotificationObserver {
+ public:
+ explicit BrowserActionsToolbarGtk(Browser* browser);
+ ~BrowserActionsToolbarGtk();
+
+ GtkWidget* widget() { return hbox_.get(); }
+
+ int button_count() { return extension_button_map_.size(); }
+
+ // NotificationObserver implementation.
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ private:
+ // Query the extensions service for all extensions with browser actions,
+ // and create the UI for them.
+ void CreateAllButtons();
+
+ // Create the UI for a single browser action. This will stick the button
+ // at the end of the toolbar.
+ // TODO(estade): is this OK, or does it need to place it in a specific
+ // location on the toolbar?
+ void CreateButtonForExtension(Extension* extension);
+
+ // Delete resources associated with UI for a browser action.
+ void RemoveButtonForExtension(Extension* extension);
+
+ // Change the visibility of widget() based on whether we have any buttons
+ // to show.
+ void UpdateVisibility();
+
+ Browser* browser_;
+
+ Profile* profile_;
+
+ OwnedWidgetGtk hbox_;
+
+ NotificationRegistrar registrar_;
+
+ // Map from extension ID to BrowserActionButton, which is a wrapper for
+ // a chrome button and related functionality. There should be one entry
+ // for every extension that has a browser action.
+ std::map<std::string, linked_ptr<BrowserActionButton> > extension_button_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserActionsToolbarGtk);
+};
+
+#endif // CHROME_BROWSER_GTK_BROWSER_ACTIONS_TOOLBAR_GTK_H_
diff --git a/chrome/browser/gtk/browser_toolbar_gtk.cc b/chrome/browser/gtk/browser_toolbar_gtk.cc
index c598070..4908773 100644
--- a/chrome/browser/gtk/browser_toolbar_gtk.cc
+++ b/chrome/browser/gtk/browser_toolbar_gtk.cc
@@ -19,6 +19,7 @@
#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/encoding_menu_controller.h"
#include "chrome/browser/gtk/back_forward_button_gtk.h"
+#include "chrome/browser/gtk/browser_actions_toolbar_gtk.h"
#include "chrome/browser/gtk/browser_window_gtk.h"
#include "chrome/browser/gtk/cairo_cached_surface.h"
#include "chrome/browser/gtk/custom_button.h"
@@ -183,6 +184,12 @@ void BrowserToolbarGtk::Init(Profile* profile,
gtk_box_pack_start(GTK_BOX(toolbar_), location_hbox, TRUE, TRUE,
ShouldOnlyShowLocation() ? 1 : 0);
+ if (!ShouldOnlyShowLocation()) {
+ actions_toolbar_.reset(new BrowserActionsToolbarGtk(browser_));
+ gtk_box_pack_start(GTK_BOX(toolbar_), actions_toolbar_->widget(),
+ FALSE, FALSE, 0);
+ }
+
// Group the menu buttons together in an hbox.
GtkWidget* menus_hbox_ = gtk_hbox_new(FALSE, 0);
GtkWidget* page_menu = BuildToolbarMenuButton(
@@ -239,6 +246,9 @@ void BrowserToolbarGtk::Init(Profile* profile,
} else {
gtk_widget_hide(home_->widget());
}
+
+ if (actions_toolbar_->button_count() == 0)
+ gtk_widget_hide(actions_toolbar_->widget());
}
SetViewIDs();
diff --git a/chrome/browser/gtk/browser_toolbar_gtk.h b/chrome/browser/gtk/browser_toolbar_gtk.h
index 995c5d8..cf726b1 100644
--- a/chrome/browser/gtk/browser_toolbar_gtk.h
+++ b/chrome/browser/gtk/browser_toolbar_gtk.h
@@ -19,6 +19,7 @@
class BackForwardButtonGtk;
class Browser;
+class BrowserActionsToolbarGtk;
class BrowserWindowGtk;
class CustomDrawButton;
class GtkThemeProvider;
@@ -182,6 +183,7 @@ class BrowserToolbarGtk : public CommandUpdater::CommandObserver,
scoped_ptr<CustomDrawButton> home_;
scoped_ptr<ToolbarStarToggleGtk> star_;
scoped_ptr<GoButtonGtk> go_;
+ scoped_ptr<BrowserActionsToolbarGtk> actions_toolbar_;
OwnedWidgetGtk page_menu_button_, app_menu_button_;
// Keep a pointer to the menu button images because we change them when