diff options
author | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-13 20:06:23 +0000 |
---|---|---|
committer | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-13 20:06:23 +0000 |
commit | 67274c96843e6ecc7e299f6165c1ea2bb02f3361 (patch) | |
tree | c467e2bc8a9ca8ffbe6b7d1c26e2b3a11db729a7 /chrome/browser/gtk | |
parent | b5d079536bcbf33c657fd96079bb7b2bd9644c0e (diff) | |
download | chromium_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.cc | 197 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_actions_toolbar_gtk.h | 71 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_toolbar_gtk.cc | 10 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_toolbar_gtk.h | 2 |
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 |