- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / gtk / infobars / extension_infobar_gtk.cc
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.
4
5 #include "chrome/browser/ui/gtk/infobars/extension_infobar_gtk.h"
6
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"
30
31
32 // ExtensionInfoBarDelegate ---------------------------------------------------
33
34 InfoBar* ExtensionInfoBarDelegate::CreateInfoBar(InfoBarService* owner) {
35   return new ExtensionInfoBarGtk(owner, this);
36 }
37
38
39 // ExtensionInfoBarGtk --------------------------------------------------------
40
41 ExtensionInfoBarGtk::ExtensionInfoBarGtk(InfoBarService* owner,
42                                          ExtensionInfoBarDelegate* delegate)
43     : InfoBarGtk(owner, delegate),
44       delegate_(delegate),
45       view_(NULL),
46       button_(NULL),
47       icon_(NULL),
48       alignment_(NULL),
49       weak_ptr_factory_(this) {
50   GetDelegate()->set_observer(this);
51
52   int height = GetDelegate()->height();
53   SetBarTargetHeight((height > 0) ? (height + kSeparatorLineHeight) : 0);
54 }
55
56 ExtensionInfoBarGtk::~ExtensionInfoBarGtk() {
57   if (GetDelegate())
58     GetDelegate()->set_observer(NULL);
59 }
60
61 void ExtensionInfoBarGtk::PlatformSpecificHide(bool animate) {
62   DCHECK(view_);
63   DCHECK(alignment_);
64   gtk_util::RemoveAllChildren(alignment_);
65 }
66
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;
71 }
72
73 void ExtensionInfoBarGtk::GetBottomColor(InfoBarDelegate::Type type,
74                                          double* r, double* g, double* b) {
75   *r = *g = *b = 218.0 / 255.0;
76 }
77
78 void ExtensionInfoBarGtk::InitWidgets() {
79   InfoBarGtk::InitWidgets();
80
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();
87
88   icon_ = gtk_image_new();
89   gtk_misc_set_alignment(GTK_MISC(icon_), 0.5, 0.5);
90
91   extensions::ExtensionHost* extension_host = GetDelegate()->extension_host();
92   const extensions::Extension* extension = extension_host->extension();
93
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));
99
100     gtk_button_set_image(GTK_BUTTON(button_), icon_);
101     gtk_util::CenterWidgetInHBox(hbox(), button_, false, 0);
102   } else {
103     gtk_util::CenterWidgetInHBox(hbox(), icon_, false, 0);
104   }
105
106   // Start loading the image for the menu button.
107   extensions::ExtensionResource icon_resource =
108       extensions::IconsInfo::GetIconResource(
109           extension,
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()));
120
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);
125
126   view_ = extension_host->view();
127
128   if (gtk_widget_get_parent(view_->native_view())) {
129     gtk_widget_reparent(view_->native_view(), alignment_);
130   } else {
131     gtk_container_add(GTK_CONTAINER(alignment_), view_->native_view());
132   }
133
134   if (button_) {
135     signals()->Connect(button_, "button-press-event",
136                        G_CALLBACK(&OnButtonPressThunk), this);
137   }
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);
142 }
143
144 void ExtensionInfoBarGtk::StoppedShowing() {
145   if (button_)
146     gtk_chrome_button_unset_paint_state(GTK_CHROME_BUTTON(button_));
147 }
148
149 void ExtensionInfoBarGtk::OnDelegateDeleted() {
150   delegate_ = NULL;
151 }
152
153 void ExtensionInfoBarGtk::OnImageLoaded(const gfx::Image& image) {
154
155   DCHECK(icon_);
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();
160   if (image.IsEmpty())
161     icon = rb.GetImageSkiaNamed(IDR_EXTENSIONS_SECTION);
162   else
163     icon = image.ToImageSkia();
164
165   SkBitmap bitmap;
166   if (button_) {
167     gfx::ImageSkia* drop_image = rb.GetImageSkiaNamed(IDR_APP_DROPARROW);
168
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,
178                          image_size / 2);
179     bitmap = canvas->ExtractImageRep().sk_bitmap();
180   } else {
181     bitmap = *icon->bitmap();
182   }
183
184   GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(bitmap);
185   gtk_image_set_from_pixbuf(GTK_IMAGE(icon_), pixbuf);
186   g_object_unref(pixbuf);
187 }
188
189 ExtensionInfoBarDelegate* ExtensionInfoBarGtk::GetDelegate() {
190   return delegate_ ? delegate_->AsExtensionInfoBarDelegate() : NULL;
191 }
192
193 Browser* ExtensionInfoBarGtk::GetBrowser() {
194   DCHECK(icon_);
195   // Get the Browser object this infobar is attached to.
196   GtkWindow* parent = platform_util::GetTopLevel(icon_);
197   return parent ?
198       BrowserWindowGtk::GetBrowserWindowForNativeWindow(parent)->browser() :
199       NULL;
200 }
201
202 ExtensionContextMenuModel* ExtensionInfoBarGtk::BuildMenuModel() {
203   const extensions::Extension* extension = GetDelegate()->extension();
204   if (!extension->ShowConfigureContextMenus())
205     return NULL;
206
207   Browser* browser = GetBrowser();
208   if (!browser)
209     return NULL;
210
211   return new ExtensionContextMenuModel(extension, browser);
212 }
213
214 void ExtensionInfoBarGtk::OnSizeAllocate(GtkWidget* widget,
215                                          GtkAllocation* allocation) {
216   gfx::Size new_size(allocation->width, allocation->height);
217
218   GetDelegate()->extension_host()->view()->render_view_host()->GetView()->
219       SetSize(new_size);
220 }
221
222 gboolean ExtensionInfoBarGtk::OnButtonPress(GtkWidget* widget,
223                                             GdkEventButton* event) {
224   if (event->button != 1)
225     return FALSE;
226
227   DCHECK(button_);
228
229   context_menu_model_ = BuildMenuModel();
230   if (!context_menu_model_.get())
231     return FALSE;
232
233   gtk_chrome_button_set_paint_state(GTK_CHROME_BUTTON(widget),
234                                     GTK_STATE_ACTIVE);
235   ShowMenuWithModel(widget, this, context_menu_model_.get());
236
237   return TRUE;
238 }
239
240 gboolean ExtensionInfoBarGtk::OnExpose(GtkWidget* sender,
241                                        GdkEventExpose* event) {
242   TRACE_EVENT0("ui::gtk", "ExtensionInfoBarGtk::OnExpose");
243
244   // We also need to draw our infobar arrows over the renderer.
245   static_cast<InfoBarContainerGtk*>(container())->
246       PaintInfobarBitsOn(sender, event, this);
247
248   return FALSE;
249 }