1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/gtk/infobars/extension_infobar_gtk.h"
7 #include "base/debug/trace_event.h"
8 #include "chrome/browser/extensions/extension_context_menu_model.h"
9 #include "chrome/browser/extensions/extension_host.h"
10 #include "chrome/browser/extensions/image_loader.h"
11 #include "chrome/browser/platform_util.h"
12 #include "chrome/browser/ui/gtk/browser_window_gtk.h"
13 #include "chrome/browser/ui/gtk/custom_button.h"
14 #include "chrome/browser/ui/gtk/gtk_chrome_button.h"
15 #include "chrome/browser/ui/gtk/gtk_util.h"
16 #include "chrome/browser/ui/gtk/infobars/infobar_container_gtk.h"
17 #include "chrome/common/extensions/extension.h"
18 #include "chrome/common/extensions/extension_constants.h"
19 #include "chrome/common/extensions/extension_icon_set.h"
20 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
21 #include "content/public/browser/render_view_host.h"
22 #include "content/public/browser/render_widget_host_view.h"
23 #include "extensions/common/extension_resource.h"
24 #include "grit/theme_resources.h"
25 #include "ui/base/gtk/gtk_signal_registrar.h"
26 #include "ui/base/resource/resource_bundle.h"
27 #include "ui/gfx/canvas.h"
28 #include "ui/gfx/gtk_util.h"
29 #include "ui/gfx/image/image.h"
32 // ExtensionInfoBarDelegate ---------------------------------------------------
34 InfoBar* ExtensionInfoBarDelegate::CreateInfoBar(InfoBarService* owner) {
35 return new ExtensionInfoBarGtk(owner, this);
39 // ExtensionInfoBarGtk --------------------------------------------------------
41 ExtensionInfoBarGtk::ExtensionInfoBarGtk(InfoBarService* owner,
42 ExtensionInfoBarDelegate* delegate)
43 : InfoBarGtk(owner, delegate),
49 weak_ptr_factory_(this) {
50 GetDelegate()->set_observer(this);
52 int height = GetDelegate()->height();
53 SetBarTargetHeight((height > 0) ? (height + kSeparatorLineHeight) : 0);
56 ExtensionInfoBarGtk::~ExtensionInfoBarGtk() {
58 GetDelegate()->set_observer(NULL);
61 void ExtensionInfoBarGtk::PlatformSpecificHide(bool animate) {
64 gtk_util::RemoveAllChildren(alignment_);
67 void ExtensionInfoBarGtk::GetTopColor(InfoBarDelegate::Type type,
68 double* r, double* g, double* b) {
69 // Extension infobars are always drawn with chrome-theme colors.
70 *r = *g = *b = 233.0 / 255.0;
73 void ExtensionInfoBarGtk::GetBottomColor(InfoBarDelegate::Type type,
74 double* r, double* g, double* b) {
75 *r = *g = *b = 218.0 / 255.0;
78 void ExtensionInfoBarGtk::InitWidgets() {
79 InfoBarGtk::InitWidgets();
81 // Always render the close button as if we were doing chrome style widget
82 // rendering. For extension infobars, we force chrome style rendering because
83 // extension authors are going to expect to match the declared gradient in
84 // extensions_infobar.css, and the close button provided by some GTK+ themes
85 // won't look good on this background.
86 ForceCloseButtonToUseChromeTheme();
88 icon_ = gtk_image_new();
89 gtk_misc_set_alignment(GTK_MISC(icon_), 0.5, 0.5);
91 extensions::ExtensionHost* extension_host = GetDelegate()->extension_host();
92 const extensions::Extension* extension = extension_host->extension();
94 if (extension->ShowConfigureContextMenus()) {
95 button_ = gtk_chrome_button_new();
96 gtk_chrome_button_set_use_gtk_rendering(GTK_CHROME_BUTTON(button_), FALSE);
97 g_object_set_data(G_OBJECT(button_), "left-align-popup",
98 reinterpret_cast<void*>(true));
100 gtk_button_set_image(GTK_BUTTON(button_), icon_);
101 gtk_util::CenterWidgetInHBox(hbox(), button_, false, 0);
103 gtk_util::CenterWidgetInHBox(hbox(), icon_, false, 0);
106 // Start loading the image for the menu button.
107 extensions::ExtensionResource icon_resource =
108 extensions::IconsInfo::GetIconResource(
110 extension_misc::EXTENSION_ICON_BITTY,
111 ExtensionIconSet::MATCH_EXACTLY);
112 // Load image asynchronously, calling back OnImageLoaded.
113 extensions::ImageLoader* loader =
114 extensions::ImageLoader::Get(extension_host->profile());
115 loader->LoadImageAsync(extension, icon_resource,
116 gfx::Size(extension_misc::EXTENSION_ICON_BITTY,
117 extension_misc::EXTENSION_ICON_BITTY),
118 base::Bind(&ExtensionInfoBarGtk::OnImageLoaded,
119 weak_ptr_factory_.GetWeakPtr()));
121 // Pad the bottom of the infobar by one pixel for the border.
122 alignment_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
123 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment_), 0, 1, 0, 0);
124 gtk_box_pack_start(GTK_BOX(hbox()), alignment_, TRUE, TRUE, 0);
126 view_ = extension_host->view();
128 if (gtk_widget_get_parent(view_->native_view())) {
129 gtk_widget_reparent(view_->native_view(), alignment_);
131 gtk_container_add(GTK_CONTAINER(alignment_), view_->native_view());
135 signals()->Connect(button_, "button-press-event",
136 G_CALLBACK(&OnButtonPressThunk), this);
138 signals()->Connect(view_->native_view(), "expose-event",
139 G_CALLBACK(&OnExposeThunk), this);
140 signals()->Connect(view_->native_view(), "size_allocate",
141 G_CALLBACK(&OnSizeAllocateThunk), this);
144 void ExtensionInfoBarGtk::StoppedShowing() {
146 gtk_chrome_button_unset_paint_state(GTK_CHROME_BUTTON(button_));
149 void ExtensionInfoBarGtk::OnDelegateDeleted() {
153 void ExtensionInfoBarGtk::OnImageLoaded(const gfx::Image& image) {
156 // TODO(erg): IDR_EXTENSIONS_SECTION should have an IDR_INFOBAR_EXTENSIONS
157 // icon of the correct size with real subpixel shading and such.
158 const gfx::ImageSkia* icon = NULL;
159 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
161 icon = rb.GetImageSkiaNamed(IDR_EXTENSIONS_SECTION);
163 icon = image.ToImageSkia();
167 gfx::ImageSkia* drop_image = rb.GetImageSkiaNamed(IDR_APP_DROPARROW);
169 int image_size = extension_misc::EXTENSION_ICON_BITTY;
170 // The margin between the extension icon and the drop-down arrow bitmap.
171 static const int kDropArrowLeftMargin = 3;
172 scoped_ptr<gfx::Canvas> canvas(new gfx::Canvas(
173 gfx::Size(image_size + kDropArrowLeftMargin + drop_image->width(),
174 image_size), 1.0f, false));
175 canvas->DrawImageInt(*icon, 0, 0, icon->width(), icon->height(), 0, 0,
176 image_size, image_size, false);
177 canvas->DrawImageInt(*drop_image, image_size + kDropArrowLeftMargin,
179 bitmap = canvas->ExtractImageRep().sk_bitmap();
181 bitmap = *icon->bitmap();
184 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(bitmap);
185 gtk_image_set_from_pixbuf(GTK_IMAGE(icon_), pixbuf);
186 g_object_unref(pixbuf);
189 ExtensionInfoBarDelegate* ExtensionInfoBarGtk::GetDelegate() {
190 return delegate_ ? delegate_->AsExtensionInfoBarDelegate() : NULL;
193 Browser* ExtensionInfoBarGtk::GetBrowser() {
195 // Get the Browser object this infobar is attached to.
196 GtkWindow* parent = platform_util::GetTopLevel(icon_);
198 BrowserWindowGtk::GetBrowserWindowForNativeWindow(parent)->browser() :
202 ExtensionContextMenuModel* ExtensionInfoBarGtk::BuildMenuModel() {
203 const extensions::Extension* extension = GetDelegate()->extension();
204 if (!extension->ShowConfigureContextMenus())
207 Browser* browser = GetBrowser();
211 return new ExtensionContextMenuModel(extension, browser);
214 void ExtensionInfoBarGtk::OnSizeAllocate(GtkWidget* widget,
215 GtkAllocation* allocation) {
216 gfx::Size new_size(allocation->width, allocation->height);
218 GetDelegate()->extension_host()->view()->render_view_host()->GetView()->
222 gboolean ExtensionInfoBarGtk::OnButtonPress(GtkWidget* widget,
223 GdkEventButton* event) {
224 if (event->button != 1)
229 context_menu_model_ = BuildMenuModel();
230 if (!context_menu_model_.get())
233 gtk_chrome_button_set_paint_state(GTK_CHROME_BUTTON(widget),
235 ShowMenuWithModel(widget, this, context_menu_model_.get());
240 gboolean ExtensionInfoBarGtk::OnExpose(GtkWidget* sender,
241 GdkEventExpose* event) {
242 TRACE_EVENT0("ui::gtk", "ExtensionInfoBarGtk::OnExpose");
244 // We also need to draw our infobar arrows over the renderer.
245 static_cast<InfoBarContainerGtk*>(container())->
246 PaintInfobarBitsOn(sender, event, this);