From 67274c96843e6ecc7e299f6165c1ea2bb02f3361 Mon Sep 17 00:00:00 2001 From: "estade@chromium.org" Date: Tue, 13 Oct 2009 20:06:23 +0000 Subject: 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 --- chrome/browser/gtk/browser_actions_toolbar_gtk.cc | 197 ++++++++++++++++++++++ chrome/browser/gtk/browser_actions_toolbar_gtk.h | 71 ++++++++ chrome/browser/gtk/browser_toolbar_gtk.cc | 10 ++ chrome/browser/gtk/browser_toolbar_gtk.h | 2 + 4 files changed, 280 insertions(+) create mode 100644 chrome/browser/gtk/browser_actions_toolbar_gtk.cc create mode 100644 chrome/browser/gtk/browser_actions_toolbar_gtk.h (limited to 'chrome/browser/gtk') 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 +#include + +#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(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 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(extension_service)); + registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, + Source(extension_service)); + registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED, + Source(extension_service)); + + CreateAllButtons(); +} + +BrowserActionsToolbarGtk::~BrowserActionsToolbarGtk() { + hbox_.Destroy(); +} + +void BrowserActionsToolbarGtk::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + Extension* extension = Details(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 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 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 +#include + +#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 > 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 home_; scoped_ptr star_; scoped_ptr go_; + scoped_ptr actions_toolbar_; OwnedWidgetGtk page_menu_button_, app_menu_button_; // Keep a pointer to the menu button images because we change them when -- cgit v1.1