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_view_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_constants.h"
18 #include "chrome/common/extensions/extension_icon_set.h"
19 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
20 #include "content/public/browser/render_view_host.h"
21 #include "content/public/browser/render_widget_host_view.h"
22 #include "extensions/common/extension.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 ---------------------------------------------------
35 scoped_ptr
<InfoBar
> ExtensionInfoBarDelegate::CreateInfoBar(
36 scoped_ptr
<ExtensionInfoBarDelegate
> delegate
) {
37 return scoped_ptr
<InfoBar
>(new ExtensionInfoBarGtk(delegate
.Pass()));
41 // ExtensionInfoBarGtk --------------------------------------------------------
43 ExtensionInfoBarGtk::ExtensionInfoBarGtk(
44 scoped_ptr
<ExtensionInfoBarDelegate
> delegate
)
45 : InfoBarGtk(delegate
.PassAs
<InfoBarDelegate
>()),
50 weak_ptr_factory_(this) {
51 int height
= GetDelegate()->height();
52 SetBarTargetHeight((height
> 0) ? (height
+ kSeparatorLineHeight
) : 0);
55 ExtensionInfoBarGtk::~ExtensionInfoBarGtk() {
58 void ExtensionInfoBarGtk::PlatformSpecificSetOwner() {
59 InfoBarGtk::PlatformSpecificSetOwner();
61 // Always render the close button as if we were doing chrome style widget
62 // rendering. For extension infobars, we force chrome style rendering because
63 // extension authors are going to expect to match the declared gradient in
64 // extensions_infobar.css, and the close button provided by some GTK+ themes
65 // won't look good on this background.
66 ForceCloseButtonToUseChromeTheme();
68 icon_
= gtk_image_new();
69 gtk_misc_set_alignment(GTK_MISC(icon_
), 0.5, 0.5);
71 extensions::ExtensionViewHost
* extension_view_host
=
72 GetDelegate()->extension_view_host();
73 const extensions::Extension
* extension
= extension_view_host
->extension();
75 if (extension
->ShowConfigureContextMenus()) {
76 button_
= gtk_chrome_button_new();
77 gtk_chrome_button_set_use_gtk_rendering(GTK_CHROME_BUTTON(button_
), FALSE
);
78 g_object_set_data(G_OBJECT(button_
), "left-align-popup",
79 reinterpret_cast<void*>(true));
81 gtk_button_set_image(GTK_BUTTON(button_
), icon_
);
82 gtk_util::CenterWidgetInHBox(hbox(), button_
, false, 0);
84 gtk_util::CenterWidgetInHBox(hbox(), icon_
, false, 0);
87 // Start loading the image for the menu button.
88 extensions::ExtensionResource icon_resource
=
89 extensions::IconsInfo::GetIconResource(
91 extension_misc::EXTENSION_ICON_BITTY
,
92 ExtensionIconSet::MATCH_EXACTLY
);
93 // Load image asynchronously, calling back OnImageLoaded.
94 extensions::ImageLoader
* loader
=
95 extensions::ImageLoader::Get(extension_view_host
->browser_context());
96 loader
->LoadImageAsync(extension
, icon_resource
,
97 gfx::Size(extension_misc::EXTENSION_ICON_BITTY
,
98 extension_misc::EXTENSION_ICON_BITTY
),
99 base::Bind(&ExtensionInfoBarGtk::OnImageLoaded
,
100 weak_ptr_factory_
.GetWeakPtr()));
102 // Pad the bottom of the infobar by one pixel for the border.
103 alignment_
= gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
104 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment_
), 0, 1, 0, 0);
105 gtk_box_pack_start(GTK_BOX(hbox()), alignment_
, TRUE
, TRUE
, 0);
107 view_
= extension_view_host
->view();
109 if (gtk_widget_get_parent(view_
->native_view())) {
110 gtk_widget_reparent(view_
->native_view(), alignment_
);
112 gtk_container_add(GTK_CONTAINER(alignment_
), view_
->native_view());
116 signals()->Connect(button_
, "button-press-event",
117 G_CALLBACK(&OnButtonPressThunk
), this);
119 signals()->Connect(view_
->native_view(), "expose-event",
120 G_CALLBACK(&OnExposeThunk
), this);
121 signals()->Connect(view_
->native_view(), "size_allocate",
122 G_CALLBACK(&OnSizeAllocateThunk
), this);
125 void ExtensionInfoBarGtk::PlatformSpecificHide(bool animate
) {
128 gtk_util::RemoveAllChildren(alignment_
);
131 void ExtensionInfoBarGtk::GetTopColor(InfoBarDelegate::Type type
,
132 double* r
, double* g
, double* b
) {
133 // Extension infobars are always drawn with chrome-theme colors.
134 *r
= *g
= *b
= 233.0 / 255.0;
137 void ExtensionInfoBarGtk::GetBottomColor(InfoBarDelegate::Type type
,
138 double* r
, double* g
, double* b
) {
139 *r
= *g
= *b
= 218.0 / 255.0;
142 void ExtensionInfoBarGtk::StoppedShowing() {
144 gtk_chrome_button_unset_paint_state(GTK_CHROME_BUTTON(button_
));
147 void ExtensionInfoBarGtk::OnImageLoaded(const gfx::Image
& image
) {
150 // TODO(erg): IDR_EXTENSIONS_SECTION should have an IDR_INFOBAR_EXTENSIONS
151 // icon of the correct size with real subpixel shading and such.
152 const gfx::ImageSkia
* icon
= NULL
;
153 ui::ResourceBundle
& rb
= ui::ResourceBundle::GetSharedInstance();
155 icon
= rb
.GetImageSkiaNamed(IDR_EXTENSIONS_SECTION
);
157 icon
= image
.ToImageSkia();
161 gfx::ImageSkia
* drop_image
= rb
.GetImageSkiaNamed(IDR_APP_DROPARROW
);
163 int image_size
= extension_misc::EXTENSION_ICON_BITTY
;
164 // The margin between the extension icon and the drop-down arrow bitmap.
165 static const int kDropArrowLeftMargin
= 3;
166 scoped_ptr
<gfx::Canvas
> canvas(new gfx::Canvas(
167 gfx::Size(image_size
+ kDropArrowLeftMargin
+ drop_image
->width(),
168 image_size
), 1.0f
, false));
169 canvas
->DrawImageInt(*icon
, 0, 0, icon
->width(), icon
->height(), 0, 0,
170 image_size
, image_size
, false);
171 canvas
->DrawImageInt(*drop_image
, image_size
+ kDropArrowLeftMargin
,
173 bitmap
= canvas
->ExtractImageRep().sk_bitmap();
175 bitmap
= *icon
->bitmap();
178 GdkPixbuf
* pixbuf
= gfx::GdkPixbufFromSkBitmap(bitmap
);
179 gtk_image_set_from_pixbuf(GTK_IMAGE(icon_
), pixbuf
);
180 g_object_unref(pixbuf
);
183 ExtensionInfoBarDelegate
* ExtensionInfoBarGtk::GetDelegate() {
184 return delegate()->AsExtensionInfoBarDelegate();
187 Browser
* ExtensionInfoBarGtk::GetBrowser() {
189 // Get the Browser object this infobar is attached to.
190 GtkWindow
* parent
= platform_util::GetTopLevel(icon_
);
192 BrowserWindowGtk::GetBrowserWindowForNativeWindow(parent
)->browser() :
196 ExtensionContextMenuModel
* ExtensionInfoBarGtk::BuildMenuModel() {
197 const extensions::Extension
* extension
= GetDelegate()->extension();
198 if (!extension
->ShowConfigureContextMenus())
201 Browser
* browser
= GetBrowser();
205 return new ExtensionContextMenuModel(extension
, browser
);
208 void ExtensionInfoBarGtk::OnSizeAllocate(GtkWidget
* widget
,
209 GtkAllocation
* allocation
) {
210 gfx::Size
new_size(allocation
->width
, allocation
->height
);
212 GetDelegate()->extension_view_host()->view()->render_view_host()->GetView()->
216 gboolean
ExtensionInfoBarGtk::OnButtonPress(GtkWidget
* widget
,
217 GdkEventButton
* event
) {
218 if (event
->button
!= 1)
223 context_menu_model_
= BuildMenuModel();
224 if (!context_menu_model_
.get())
227 gtk_chrome_button_set_paint_state(GTK_CHROME_BUTTON(widget
),
229 ShowMenuWithModel(widget
, this, context_menu_model_
.get());
234 gboolean
ExtensionInfoBarGtk::OnExpose(GtkWidget
* sender
,
235 GdkEventExpose
* event
) {
236 TRACE_EVENT0("ui::gtk", "ExtensionInfoBarGtk::OnExpose");
238 // We also need to draw our infobar arrows over the renderer.
239 static_cast<InfoBarContainerGtk
*>(container())->
240 PaintInfobarBitsOn(sender
, event
, this);