| Index: chrome/browser/gtk/extension_installed_bubble_gtk.cc | 
| =================================================================== | 
| --- chrome/browser/gtk/extension_installed_bubble_gtk.cc	(revision 71352) | 
| +++ chrome/browser/gtk/extension_installed_bubble_gtk.cc	(working copy) | 
| @@ -1,314 +0,0 @@ | 
| -// 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 <string> | 
| - | 
| -#include "app/l10n_util.h" | 
| -#include "app/resource_bundle.h" | 
| -#include "base/i18n/rtl.h" | 
| -#include "base/message_loop.h" | 
| -#include "base/utf_string_conversions.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/browser/ui/browser.h" | 
| -#include "chrome/common/extensions/extension.h" | 
| -#include "chrome/common/extensions/extension_action.h" | 
| -#include "chrome/common/notification_details.h" | 
| -#include "chrome/common/notification_source.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; | 
| - | 
| -// When showing the bubble for a new browser action, we may have to wait for | 
| -// the toolbar to finish animating to know where the item's final position | 
| -// will be. | 
| -const int kAnimationWaitRetries = 10; | 
| -const int kAnimationWaitMS = 50; | 
| - | 
| -// Padding between content and edge of info bubble. | 
| -const int kContentBorder = 7; | 
| - | 
| -}  // namespace | 
| - | 
| -void ExtensionInstalledBubbleGtk::Show(const Extension* extension, | 
| -                                       Browser* browser, | 
| -                                       SkBitmap icon) { | 
| -  new ExtensionInstalledBubbleGtk(extension, browser, icon); | 
| -} | 
| - | 
| -ExtensionInstalledBubbleGtk::ExtensionInstalledBubbleGtk( | 
| -    const Extension* extension, Browser *browser, SkBitmap icon) | 
| -    : extension_(extension), | 
| -      browser_(browser), | 
| -      icon_(icon), | 
| -      animation_wait_retries_(kAnimationWaitRetries) { | 
| -  AddRef();  // Balanced in Close(). | 
| - | 
| -  if (!extension_->omnibox_keyword().empty()) { | 
| -    type_ = OMNIBOX_KEYWORD; | 
| -  } else 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, | 
| -      Source<Profile>(browser->profile())); | 
| -  registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, | 
| -      Source<Profile>(browser->profile())); | 
| -} | 
| - | 
| -ExtensionInstalledBubbleGtk::~ExtensionInstalledBubbleGtk() {} | 
| - | 
| -void ExtensionInstalledBubbleGtk::Observe(NotificationType type, | 
| -                                          const NotificationSource& source, | 
| -                                          const NotificationDetails& details) { | 
| -  if (type == NotificationType::EXTENSION_LOADED) { | 
| -    const Extension* extension = Details<const 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 if (type == NotificationType::EXTENSION_UNLOADED) { | 
| -    const Extension* extension = | 
| -        Details<UnloadedExtensionInfo>(details)->extension; | 
| -    if (extension == extension_) | 
| -      extension_ = NULL; | 
| -  } 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) { | 
| -    BrowserActionsToolbarGtk* toolbar = | 
| -        browser_window->GetToolbar()->GetBrowserActionsToolbar(); | 
| - | 
| -    if (toolbar->animating() && animation_wait_retries_-- > 0) { | 
| -      MessageLoopForUI::current()->PostDelayedTask( | 
| -          FROM_HERE, | 
| -          NewRunnableMethod(this, &ExtensionInstalledBubbleGtk::ShowInternal), | 
| -          kAnimationWaitMS); | 
| -      return; | 
| -    } | 
| - | 
| -    reference_widget = toolbar->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. Try showing it on the chevron. | 
| -    // If that fails, fall back to default position. | 
| -    if (reference_widget && !GTK_WIDGET_VISIBLE(reference_widget)) { | 
| -      reference_widget = GTK_WIDGET_VISIBLE(toolbar->chevron()) ? | 
| -          toolbar->chevron() : 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); | 
| -  } else if (type_ == OMNIBOX_KEYWORD) { | 
| -    LocationBarViewGtk* location_bar_view = | 
| -        browser_window->GetToolbar()->GetLocationBarView(); | 
| -    reference_widget = location_bar_view->location_entry_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); | 
| - | 
| -  if (!icon_.isNull()) { | 
| -    // 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); | 
| -  string16 extension_name = UTF8ToUTF16(extension_->name()); | 
| -  base::i18n::AdjustStringForLocaleDirection(&extension_name); | 
| -  std::string heading_text = l10n_util::GetStringFUTF8( | 
| -      IDS_EXTENSION_INSTALLED_HEADING, 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_ == PAGE_ACTION) { | 
| -    GtkWidget* info_label = gtk_label_new(l10n_util::GetStringUTF8( | 
| -        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); | 
| -  } | 
| - | 
| -  // Omnibox keyword label | 
| -  if (type_ == OMNIBOX_KEYWORD) { | 
| -    GtkWidget* info_label = gtk_label_new(l10n_util::GetStringFUTF8( | 
| -        IDS_EXTENSION_INSTALLED_OMNIBOX_KEYWORD_INFO, | 
| -        UTF8ToUTF16(extension_->omnibox_keyword())).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( | 
| -      l10n_util::GetStringUTF8(IDS_EXTENSION_INSTALLED_MANAGE_INFO).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); | 
| -  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; | 
| - | 
| -  gfx::Rect bounds = gtk_util::WidgetBounds(reference_widget); | 
| -  if (type_ == OMNIBOX_KEYWORD) { | 
| -    // Reverse the arrow for omnibox keywords, since the bubble will be on the | 
| -    // other side of the window. We also clear the width to avoid centering | 
| -    // the popup on the URL bar. | 
| -    arrow_location = | 
| -        !base::i18n::IsRTL() ? | 
| -        InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT : | 
| -        InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT; | 
| -    if (base::i18n::IsRTL()) | 
| -      bounds.Offset(bounds.width(), 0); | 
| -    bounds.set_width(0); | 
| -  } | 
| - | 
| -  info_bubble_ = InfoBubbleGtk::Show(reference_widget, | 
| -      &bounds, | 
| -      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_ && type_ == 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; | 
| -} | 
|  |