diff options
author | Ben Murdoch <benm@google.com> | 2010-07-29 17:14:53 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2010-08-04 14:29:45 +0100 |
commit | c407dc5cd9bdc5668497f21b26b09d988ab439de (patch) | |
tree | 7eaf8707c0309516bdb042ad976feedaf72b0bb1 /chrome/browser/gtk/extension_installed_bubble_gtk.cc | |
parent | 0998b1cdac5733f299c12d88bc31ef9c8035b8fa (diff) | |
download | external_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.cc | 252 |
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; +} |