root/chrome/browser/ui/gtk/infobars/extension_infobar_gtk.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. CreateInfoBar
  2. weak_ptr_factory_
  3. PlatformSpecificSetOwner
  4. PlatformSpecificHide
  5. GetTopColor
  6. GetBottomColor
  7. StoppedShowing
  8. OnImageLoaded
  9. GetDelegate
  10. GetBrowser
  11. BuildMenuModel
  12. OnSizeAllocate
  13. OnButtonPress
  14. OnExpose

// Copyright (c) 2012 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/ui/gtk/infobars/extension_infobar_gtk.h"

#include "base/debug/trace_event.h"
#include "chrome/browser/extensions/extension_context_menu_model.h"
#include "chrome/browser/extensions/extension_view_host.h"
#include "chrome/browser/extensions/image_loader.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/ui/gtk/browser_window_gtk.h"
#include "chrome/browser/ui/gtk/custom_button.h"
#include "chrome/browser/ui/gtk/gtk_chrome_button.h"
#include "chrome/browser/ui/gtk/gtk_util.h"
#include "chrome/browser/ui/gtk/infobars/infobar_container_gtk.h"
#include "chrome/common/extensions/extension_icon_set.h"
#include "chrome/common/extensions/manifest_handlers/icons_handler.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_resource.h"
#include "grit/theme_resources.h"
#include "ui/base/gtk/gtk_signal_registrar.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/gtk_util.h"
#include "ui/gfx/image/image.h"


// ExtensionInfoBarDelegate ---------------------------------------------------

// static
scoped_ptr<InfoBar> ExtensionInfoBarDelegate::CreateInfoBar(
    scoped_ptr<ExtensionInfoBarDelegate> delegate) {
  return scoped_ptr<InfoBar>(new ExtensionInfoBarGtk(delegate.Pass()));
}


// ExtensionInfoBarGtk --------------------------------------------------------

ExtensionInfoBarGtk::ExtensionInfoBarGtk(
    scoped_ptr<ExtensionInfoBarDelegate> delegate)
    : InfoBarGtk(delegate.PassAs<InfoBarDelegate>()),
      view_(NULL),
      button_(NULL),
      icon_(NULL),
      alignment_(NULL),
      weak_ptr_factory_(this) {
  int height = GetDelegate()->height();
  SetBarTargetHeight((height > 0) ? (height + kSeparatorLineHeight) : 0);
}

ExtensionInfoBarGtk::~ExtensionInfoBarGtk() {
}

void ExtensionInfoBarGtk::PlatformSpecificSetOwner() {
  InfoBarGtk::PlatformSpecificSetOwner();

  // Always render the close button as if we were doing chrome style widget
  // rendering. For extension infobars, we force chrome style rendering because
  // extension authors are going to expect to match the declared gradient in
  // extensions_infobar.css, and the close button provided by some GTK+ themes
  // won't look good on this background.
  ForceCloseButtonToUseChromeTheme();

  icon_ = gtk_image_new();
  gtk_misc_set_alignment(GTK_MISC(icon_), 0.5, 0.5);

  extensions::ExtensionViewHost* extension_view_host =
      GetDelegate()->extension_view_host();
  const extensions::Extension* extension = extension_view_host->extension();

  if (extension->ShowConfigureContextMenus()) {
    button_ = gtk_chrome_button_new();
    gtk_chrome_button_set_use_gtk_rendering(GTK_CHROME_BUTTON(button_), FALSE);
    g_object_set_data(G_OBJECT(button_), "left-align-popup",
                      reinterpret_cast<void*>(true));

    gtk_button_set_image(GTK_BUTTON(button_), icon_);
    gtk_util::CenterWidgetInHBox(hbox(), button_, false, 0);
  } else {
    gtk_util::CenterWidgetInHBox(hbox(), icon_, false, 0);
  }

  // Start loading the image for the menu button.
  extensions::ExtensionResource icon_resource =
      extensions::IconsInfo::GetIconResource(
          extension,
          extension_misc::EXTENSION_ICON_BITTY,
          ExtensionIconSet::MATCH_EXACTLY);
  // Load image asynchronously, calling back OnImageLoaded.
  extensions::ImageLoader* loader =
      extensions::ImageLoader::Get(extension_view_host->browser_context());
  loader->LoadImageAsync(extension, icon_resource,
                         gfx::Size(extension_misc::EXTENSION_ICON_BITTY,
                                   extension_misc::EXTENSION_ICON_BITTY),
                         base::Bind(&ExtensionInfoBarGtk::OnImageLoaded,
                                    weak_ptr_factory_.GetWeakPtr()));

  // Pad the bottom of the infobar by one pixel for the border.
  alignment_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
  gtk_alignment_set_padding(GTK_ALIGNMENT(alignment_), 0, 1, 0, 0);
  gtk_box_pack_start(GTK_BOX(hbox()), alignment_, TRUE, TRUE, 0);

  view_ = extension_view_host->view();

  if (gtk_widget_get_parent(view_->native_view())) {
    gtk_widget_reparent(view_->native_view(), alignment_);
  } else {
    gtk_container_add(GTK_CONTAINER(alignment_), view_->native_view());
  }

  if (button_) {
    signals()->Connect(button_, "button-press-event",
                       G_CALLBACK(&OnButtonPressThunk), this);
  }
  signals()->Connect(view_->native_view(), "expose-event",
                     G_CALLBACK(&OnExposeThunk), this);
  signals()->Connect(view_->native_view(), "size_allocate",
                     G_CALLBACK(&OnSizeAllocateThunk), this);
}

void ExtensionInfoBarGtk::PlatformSpecificHide(bool animate) {
  DCHECK(view_);
  DCHECK(alignment_);
  gtk_util::RemoveAllChildren(alignment_);
}

void ExtensionInfoBarGtk::GetTopColor(InfoBarDelegate::Type type,
                                      double* r, double* g, double* b) {
  // Extension infobars are always drawn with chrome-theme colors.
  *r = *g = *b = 233.0 / 255.0;
}

void ExtensionInfoBarGtk::GetBottomColor(InfoBarDelegate::Type type,
                                         double* r, double* g, double* b) {
  *r = *g = *b = 218.0 / 255.0;
}

void ExtensionInfoBarGtk::StoppedShowing() {
  if (button_)
    gtk_chrome_button_unset_paint_state(GTK_CHROME_BUTTON(button_));
}

void ExtensionInfoBarGtk::OnImageLoaded(const gfx::Image& image) {

  DCHECK(icon_);
  // TODO(erg): IDR_EXTENSIONS_SECTION should have an IDR_INFOBAR_EXTENSIONS
  // icon of the correct size with real subpixel shading and such.
  const gfx::ImageSkia* icon = NULL;
  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
  if (image.IsEmpty())
    icon = rb.GetImageSkiaNamed(IDR_EXTENSIONS_SECTION);
  else
    icon = image.ToImageSkia();

  SkBitmap bitmap;
  if (button_) {
    gfx::ImageSkia* drop_image = rb.GetImageSkiaNamed(IDR_APP_DROPARROW);

    int image_size = extension_misc::EXTENSION_ICON_BITTY;
    // The margin between the extension icon and the drop-down arrow bitmap.
    static const int kDropArrowLeftMargin = 3;
    scoped_ptr<gfx::Canvas> canvas(new gfx::Canvas(
        gfx::Size(image_size + kDropArrowLeftMargin + drop_image->width(),
                  image_size), 1.0f, false));
    canvas->DrawImageInt(*icon, 0, 0, icon->width(), icon->height(), 0, 0,
                         image_size, image_size, false);
    canvas->DrawImageInt(*drop_image, image_size + kDropArrowLeftMargin,
                         image_size / 2);
    bitmap = canvas->ExtractImageRep().sk_bitmap();
  } else {
    bitmap = *icon->bitmap();
  }

  GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(bitmap);
  gtk_image_set_from_pixbuf(GTK_IMAGE(icon_), pixbuf);
  g_object_unref(pixbuf);
}

ExtensionInfoBarDelegate* ExtensionInfoBarGtk::GetDelegate() {
  return delegate()->AsExtensionInfoBarDelegate();
}

Browser* ExtensionInfoBarGtk::GetBrowser() {
  DCHECK(icon_);
  // Get the Browser object this infobar is attached to.
  GtkWindow* parent = platform_util::GetTopLevel(icon_);
  return parent ?
      BrowserWindowGtk::GetBrowserWindowForNativeWindow(parent)->browser() :
      NULL;
}

ExtensionContextMenuModel* ExtensionInfoBarGtk::BuildMenuModel() {
  const extensions::Extension* extension = GetDelegate()->extension();
  if (!extension->ShowConfigureContextMenus())
    return NULL;

  Browser* browser = GetBrowser();
  if (!browser)
    return NULL;

  return new ExtensionContextMenuModel(extension, browser);
}

void ExtensionInfoBarGtk::OnSizeAllocate(GtkWidget* widget,
                                         GtkAllocation* allocation) {
  gfx::Size new_size(allocation->width, allocation->height);

  GetDelegate()->extension_view_host()->view()->render_view_host()->GetView()->
      SetSize(new_size);
}

gboolean ExtensionInfoBarGtk::OnButtonPress(GtkWidget* widget,
                                            GdkEventButton* event) {
  if (event->button != 1)
    return FALSE;

  DCHECK(button_);

  context_menu_model_ = BuildMenuModel();
  if (!context_menu_model_.get())
    return FALSE;

  gtk_chrome_button_set_paint_state(GTK_CHROME_BUTTON(widget),
                                    GTK_STATE_ACTIVE);
  ShowMenuWithModel(widget, this, context_menu_model_.get());

  return TRUE;
}

gboolean ExtensionInfoBarGtk::OnExpose(GtkWidget* sender,
                                       GdkEventExpose* event) {
  TRACE_EVENT0("ui::gtk", "ExtensionInfoBarGtk::OnExpose");

  // We also need to draw our infobar arrows over the renderer.
  static_cast<InfoBarContainerGtk*>(container())->
      PaintInfobarBitsOn(sender, event, this);

  return FALSE;
}

/* [<][>][^][v][top][bottom][index][help] */