summaryrefslogtreecommitdiffstats
path: root/chrome/browser/gtk/extension_installed_bubble_gtk.cc
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2010-07-29 17:14:53 +0100
committerBen Murdoch <benm@google.com>2010-08-04 14:29:45 +0100
commitc407dc5cd9bdc5668497f21b26b09d988ab439de (patch)
tree7eaf8707c0309516bdb042ad976feedaf72b0bb1 /chrome/browser/gtk/extension_installed_bubble_gtk.cc
parent0998b1cdac5733f299c12d88bc31ef9c8035b8fa (diff)
downloadexternal_chromium-c407dc5cd9bdc5668497f21b26b09d988ab439de.zip
external_chromium-c407dc5cd9bdc5668497f21b26b09d988ab439de.tar.gz
external_chromium-c407dc5cd9bdc5668497f21b26b09d988ab439de.tar.bz2
Merge Chromium src@r53293
Change-Id: Ia79acf8670f385cee48c45b0a75371d8e950af34
Diffstat (limited to 'chrome/browser/gtk/extension_installed_bubble_gtk.cc')
-rw-r--r--chrome/browser/gtk/extension_installed_bubble_gtk.cc252
1 files changed, 252 insertions, 0 deletions
diff --git a/chrome/browser/gtk/extension_installed_bubble_gtk.cc b/chrome/browser/gtk/extension_installed_bubble_gtk.cc
new file mode 100644
index 0000000..37a3c02
--- /dev/null
+++ b/chrome/browser/gtk/extension_installed_bubble_gtk.cc
@@ -0,0 +1,252 @@
+// Copyright (c) 2010 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/extension_installed_bubble_gtk.h"
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/i18n/rtl.h"
+#include "base/message_loop.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/gtk/browser_actions_toolbar_gtk.h"
+#include "chrome/browser/gtk/browser_toolbar_gtk.h"
+#include "chrome/browser/gtk/browser_window_gtk.h"
+#include "chrome/browser/gtk/gtk_theme_provider.h"
+#include "chrome/browser/gtk/gtk_util.h"
+#include "chrome/browser/gtk/location_bar_view_gtk.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_action.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+#include "gfx/gtk_util.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+
+namespace {
+
+const int kHorizontalColumnSpacing = 10;
+const int kIconPadding = 3;
+const int kIconSize = 43;
+const int kTextColumnVerticalSpacing = 7;
+const int kTextColumnWidth = 350;
+
+// Padding between content and edge of info bubble.
+const int kContentBorder = 7;
+
+} // namespace
+
+void ExtensionInstalledBubbleGtk::Show(Extension* extension, Browser* browser,
+ SkBitmap icon) {
+ new ExtensionInstalledBubbleGtk(extension, browser, icon);
+}
+
+ExtensionInstalledBubbleGtk::ExtensionInstalledBubbleGtk(Extension *extension,
+ Browser *browser,
+ SkBitmap icon)
+ : extension_(extension),
+ browser_(browser),
+ icon_(icon) {
+ AddRef(); // Balanced in Close().
+
+ if (extension_->browser_action()) {
+ type_ = BROWSER_ACTION;
+ } else if (extension->page_action() &&
+ !extension->page_action()->default_icon_path().empty()) {
+ type_ = PAGE_ACTION;
+ } else {
+ type_ = GENERIC;
+ }
+
+ // |extension| has been initialized but not loaded at this point. We need
+ // to wait on showing the Bubble until not only the EXTENSION_LOADED gets
+ // fired, but all of the EXTENSION_LOADED Observers have run. Only then can we
+ // be sure that a browser action or page action has had views created which we
+ // can inspect for the purpose of pointing to them.
+ registrar_.Add(this, NotificationType::EXTENSION_LOADED,
+ NotificationService::AllSources());
+}
+
+void ExtensionInstalledBubbleGtk::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NotificationType::EXTENSION_LOADED) {
+ Extension* extension = Details<Extension>(details).ptr();
+ if (extension == extension_) {
+ // PostTask to ourself to allow all EXTENSION_LOADED Observers to run.
+ MessageLoopForUI::current()->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &ExtensionInstalledBubbleGtk::ShowInternal));
+ }
+ } else {
+ NOTREACHED() << L"Received unexpected notification";
+ }
+}
+
+void ExtensionInstalledBubbleGtk::ShowInternal() {
+ BrowserWindowGtk* browser_window =
+ BrowserWindowGtk::GetBrowserWindowForNativeWindow(
+ browser_->window()->GetNativeHandle());
+
+ GtkWidget* reference_widget = NULL;
+
+ if (type_ == BROWSER_ACTION) {
+ reference_widget = browser_window->GetToolbar()->GetBrowserActionsToolbar()
+ ->GetBrowserActionWidget(extension_);
+ // glib delays recalculating layout, but we need reference_widget to know
+ // its coordinates, so we force a check_resize here.
+ gtk_container_check_resize(GTK_CONTAINER(
+ browser_window->GetToolbar()->widget()));
+ // If the widget is not visible then browser_window could be incognito
+ // with this extension disabled. Fall back to default position.
+ if (reference_widget && !GTK_WIDGET_VISIBLE(reference_widget))
+ reference_widget = NULL;
+ } else if (type_ == PAGE_ACTION) {
+ LocationBarViewGtk* location_bar_view =
+ browser_window->GetToolbar()->GetLocationBarView();
+ location_bar_view->SetPreviewEnabledPageAction(extension_->page_action(),
+ true); // preview_enabled
+ reference_widget = location_bar_view->GetPageActionWidget(
+ extension_->page_action());
+ // glib delays recalculating layout, but we need reference_widget to know
+ // it's coordinates, so we force a check_resize here.
+ gtk_container_check_resize(GTK_CONTAINER(
+ browser_window->GetToolbar()->widget()));
+ DCHECK(reference_widget);
+ }
+ // Default case.
+ if (reference_widget == NULL)
+ reference_widget = browser_window->GetToolbar()->GetAppMenuButton();
+
+ GtkThemeProvider* theme_provider = GtkThemeProvider::GetFrom(
+ browser_->profile());
+
+ // Setup the InfoBubble content.
+ GtkWidget* bubble_content = gtk_hbox_new(FALSE, kHorizontalColumnSpacing);
+ gtk_container_set_border_width(GTK_CONTAINER(bubble_content), kContentBorder);
+
+ // Scale icon down to 43x43, but allow smaller icons (don't scale up).
+ GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&icon_);
+ gfx::Size size(icon_.width(), icon_.height());
+ if (size.width() > kIconSize || size.height() > kIconSize) {
+ if (size.width() > size.height()) {
+ size.set_height(size.height() * kIconSize / size.width());
+ size.set_width(kIconSize);
+ } else {
+ size.set_width(size.width() * kIconSize / size.height());
+ size.set_height(kIconSize);
+ }
+
+ GdkPixbuf* old = pixbuf;
+ pixbuf = gdk_pixbuf_scale_simple(pixbuf, size.width(), size.height(),
+ GDK_INTERP_BILINEAR);
+ g_object_unref(old);
+ }
+
+ // Put Icon in top of the left column.
+ GtkWidget* icon_column = gtk_vbox_new(FALSE, 0);
+ // Use 3 pixel padding to get visual balance with InfoBubble border on the
+ // left.
+ gtk_box_pack_start(GTK_BOX(bubble_content), icon_column, FALSE, FALSE,
+ kIconPadding);
+ GtkWidget* image = gtk_image_new_from_pixbuf(pixbuf);
+ g_object_unref(pixbuf);
+ gtk_box_pack_start(GTK_BOX(icon_column), image, FALSE, FALSE, 0);
+
+ // Center text column.
+ GtkWidget* text_column = gtk_vbox_new(FALSE, kTextColumnVerticalSpacing);
+ gtk_box_pack_start(GTK_BOX(bubble_content), text_column, FALSE, FALSE, 0);
+
+ // Heading label
+ GtkWidget* heading_label = gtk_label_new(NULL);
+ std::string heading_text = WideToUTF8(l10n_util::GetStringF(
+ IDS_EXTENSION_INSTALLED_HEADING,
+ UTF8ToWide(extension_->name())));
+ char* markup = g_markup_printf_escaped("<span size=\"larger\">%s</span>",
+ heading_text.c_str());
+ gtk_label_set_markup(GTK_LABEL(heading_label), markup);
+ g_free(markup);
+
+ gtk_label_set_line_wrap(GTK_LABEL(heading_label), TRUE);
+ gtk_widget_set_size_request(heading_label, kTextColumnWidth, -1);
+ gtk_box_pack_start(GTK_BOX(text_column), heading_label, FALSE, FALSE, 0);
+
+ // Page action label
+ if (type_ == ExtensionInstalledBubbleGtk::PAGE_ACTION) {
+ GtkWidget* info_label = gtk_label_new(
+ WideToUTF8(l10n_util::GetString(
+ IDS_EXTENSION_INSTALLED_PAGE_ACTION_INFO)).c_str());
+ gtk_label_set_line_wrap(GTK_LABEL(info_label), TRUE);
+ gtk_widget_set_size_request(info_label, kTextColumnWidth, -1);
+ gtk_box_pack_start(GTK_BOX(text_column), info_label, FALSE, FALSE, 0);
+ }
+
+ // Manage label
+ GtkWidget* manage_label = gtk_label_new(
+ WideToUTF8(l10n_util::GetStringF(IDS_EXTENSION_INSTALLED_MANAGE_INFO,
+ UTF8ToWide(extension_->name()))).c_str());
+ gtk_label_set_line_wrap(GTK_LABEL(manage_label), TRUE);
+ gtk_widget_set_size_request(manage_label, kTextColumnWidth, -1);
+ gtk_box_pack_start(GTK_BOX(text_column), manage_label, FALSE, FALSE, 0);
+
+ // Create and pack the close button.
+ GtkWidget* close_column = gtk_vbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(bubble_content), close_column, FALSE, FALSE, 0);
+ close_button_.reset(CustomDrawButton::CloseButton(theme_provider));
+ g_signal_connect(close_button_->widget(), "clicked",
+ G_CALLBACK(OnButtonClick), this);
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ close_button_->SetBackground(
+ theme_provider->GetColor(BrowserThemeProvider::COLOR_TAB_TEXT),
+ rb.GetBitmapNamed(IDR_CLOSE_BAR),
+ rb.GetBitmapNamed(IDR_CLOSE_BAR_MASK));
+ gtk_box_pack_start(GTK_BOX(close_column), close_button_->widget(),
+ FALSE, FALSE, 0);
+
+ InfoBubbleGtk::ArrowLocationGtk arrow_location =
+ !base::i18n::IsRTL() ?
+ InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT :
+ InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT;
+ info_bubble_ = InfoBubbleGtk::Show(reference_widget,
+ NULL,
+ bubble_content,
+ arrow_location,
+ true, // match_system_theme
+ true, // grab_input
+ theme_provider,
+ this);
+}
+
+// static
+void ExtensionInstalledBubbleGtk::OnButtonClick(GtkWidget* button,
+ ExtensionInstalledBubbleGtk* bubble) {
+ if (button == bubble->close_button_->widget()) {
+ bubble->info_bubble_->Close();
+ } else {
+ NOTREACHED();
+ }
+}
+// InfoBubbleDelegate
+void ExtensionInstalledBubbleGtk::InfoBubbleClosing(InfoBubbleGtk* info_bubble,
+ bool closed_by_escape) {
+ if (extension_->page_action()) {
+ // Turn the page action preview off.
+ BrowserWindowGtk* browser_window =
+ BrowserWindowGtk::GetBrowserWindowForNativeWindow(
+ browser_->window()->GetNativeHandle());
+ LocationBarViewGtk* location_bar_view =
+ browser_window->GetToolbar()->GetLocationBarView();
+ location_bar_view->SetPreviewEnabledPageAction(extension_->page_action(),
+ false); // preview_enabled
+ }
+
+ // We need to allow the info bubble to close and remove the widgets from
+ // the window before we call Release() because close_button_ depends
+ // on all references being cleared before it is destroyed.
+ MessageLoopForUI::current()->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &ExtensionInstalledBubbleGtk::Close));
+}
+
+void ExtensionInstalledBubbleGtk::Close() {
+ Release(); // Balanced in ctor.
+ info_bubble_ = NULL;
+}