• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/script_bubble_gtk.h"
6 
7 #include <string>
8 #include <vector>
9 
10 #include "base/i18n/rtl.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "chrome/browser/extensions/extension_service.h"
13 #include "chrome/browser/extensions/extension_system.h"
14 #include "chrome/browser/extensions/image_loader.h"
15 #include "chrome/browser/extensions/script_bubble_controller.h"
16 #include "chrome/browser/extensions/tab_helper.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
19 #include "chrome/common/extensions/extension_set.h"
20 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
21 #include "chrome/common/url_constants.h"
22 #include "content/public/browser/web_contents.h"
23 #include "extensions/common/extension.h"
24 #include "grit/generated_resources.h"
25 #include "grit/theme_resources.h"
26 #include "grit/ui_resources.h"
27 #include "ui/base/gtk/gtk_hig_constants.h"
28 #include "ui/base/l10n/l10n_util.h"
29 
30 using content::WebContents;
31 using content::OpenURLParams;
32 using content::Referrer;
33 using extensions::Extension;
34 using extensions::ExtensionSystem;
35 using extensions::TabHelper;
36 using extensions::ImageLoader;
37 
38 namespace {
39 
40 // The currently open app-modal bubble singleton, or NULL if none is open.
41 ScriptBubbleGtk* g_bubble = NULL;
42 
43 }  // namespace
44 
45 
46 // static
Show(GtkWidget * anchor,WebContents * web_contents)47 void ScriptBubbleGtk::Show(GtkWidget* anchor, WebContents* web_contents) {
48   if (!g_bubble)
49     g_bubble = new ScriptBubbleGtk(anchor, web_contents);
50 }
51 
52 // static
OnItemLinkClickedThunk(GtkWidget * sender,void * user_data)53 void ScriptBubbleGtk::OnItemLinkClickedThunk(GtkWidget* sender,
54                                              void* user_data) {
55   g_bubble->OnItemLinkClicked(sender);
56 }
57 
ScriptBubbleGtk(GtkWidget * anchor,WebContents * web_contents)58 ScriptBubbleGtk::ScriptBubbleGtk(GtkWidget* anchor, WebContents* web_contents)
59     : anchor_(anchor),
60       web_contents_(web_contents),
61       profile_(Profile::FromBrowserContext(web_contents_->GetBrowserContext())),
62       weak_ptr_factory_(this) {
63   BuildBubble();
64 }
65 
~ScriptBubbleGtk()66 ScriptBubbleGtk::~ScriptBubbleGtk() {
67 }
68 
Close()69 void ScriptBubbleGtk::Close() {
70   if (bubble_)
71     bubble_->Close();
72 }
73 
BubbleClosing(BubbleGtk * bubble,bool closed_by_escape)74 void ScriptBubbleGtk::BubbleClosing(BubbleGtk* bubble,
75                                     bool closed_by_escape) {
76   g_bubble = NULL;
77   delete this;
78 }
79 
BuildBubble()80 void ScriptBubbleGtk::BuildBubble() {
81   GtkThemeService* theme_provider = GtkThemeService::GetFrom(profile_);
82 
83   GtkWidget* bubble_content = gtk_vbox_new(FALSE, ui::kControlSpacing);
84   gtk_container_set_border_width(GTK_CONTAINER(bubble_content),
85                                  ui::kContentAreaBorder);
86 
87   extensions::TabHelper* tab_helper =
88       extensions::TabHelper::FromWebContents(web_contents_);
89   const std::set<std::string>& extensions_running_scripts =
90       tab_helper->script_bubble_controller()->extensions_running_scripts();
91   const ExtensionSet* loaded_extensions =
92       ExtensionSystem::Get(profile_)->extension_service()->extensions();
93 
94   std::string heading_string =
95       l10n_util::GetStringUTF8(IDS_SCRIPT_BUBBLE_HEADLINE);
96   GtkWidget* heading = gtk_label_new(heading_string.c_str());
97   gtk_misc_set_alignment(GTK_MISC(heading), 0, 0);
98   gtk_box_pack_start(GTK_BOX(bubble_content), heading, FALSE, FALSE, 0);
99 
100   for (std::set<std::string>::const_iterator iter =
101            extensions_running_scripts.begin();
102        iter != extensions_running_scripts.end(); ++iter) {
103     const Extension* extension = loaded_extensions->GetByID(*iter);
104     if (!extension)
105       continue;
106 
107     GtkWidget* item = gtk_hbox_new(FALSE, ui::kControlSpacing);
108     gtk_box_pack_start(GTK_BOX(bubble_content), item, FALSE, FALSE, 0);
109 
110     GtkWidget* image = gtk_image_new();
111     gtk_widget_set_usize(image, 16, 16);
112     gtk_box_pack_start(GTK_BOX(item), image, FALSE, FALSE, 0);
113 
114     // Load the image asynchronously.
115     icon_controls_[extension->id()] = GTK_IMAGE(image);
116     ImageLoader::Get(profile_)->LoadImageAsync(
117         extension,
118         extensions::IconsInfo::GetIconResource(
119             extension,
120             extension_misc::EXTENSION_ICON_BITTY,
121             ExtensionIconSet::MATCH_EXACTLY),
122         gfx::Size(extension_misc::EXTENSION_ICON_BITTY,
123                   extension_misc::EXTENSION_ICON_BITTY),
124         base::Bind(&ScriptBubbleGtk::OnIconLoaded,
125                    weak_ptr_factory_.GetWeakPtr(),
126                    extension->id()));
127 
128     GtkWidget* link = theme_provider->BuildChromeLinkButton(
129         extension->name().c_str());
130     gtk_box_pack_start(GTK_BOX(item), link, FALSE, FALSE, 0);
131     link_controls_[GTK_WIDGET(link)] = extension->id();
132     g_signal_connect(link, "button-press-event",
133                      G_CALLBACK(&OnItemLinkClickedThunk), this);
134   }
135 
136   bubble_ = BubbleGtk::Show(anchor_,
137                             NULL,
138                             bubble_content,
139                             BubbleGtk::ANCHOR_TOP_RIGHT,
140                             BubbleGtk::MATCH_SYSTEM_THEME |
141                                 BubbleGtk::POPUP_WINDOW |
142                                 BubbleGtk::GRAB_INPUT,
143                             theme_provider,
144                             this);
145 }
146 
OnIconLoaded(const std::string & extension_id,const gfx::Image & icon)147 void ScriptBubbleGtk::OnIconLoaded(const std::string& extension_id,
148                                    const gfx::Image& icon) {
149   gtk_image_set_from_pixbuf(
150       icon_controls_[extension_id],
151       (!icon.IsEmpty() ? icon :
152        GtkThemeService::GetFrom(profile_)->GetImageNamed(
153            IDR_EXTENSIONS_FAVICON)).ToGdkPixbuf());
154 }
155 
OnItemLinkClicked(GtkWidget * button)156 void ScriptBubbleGtk::OnItemLinkClicked(GtkWidget* button) {
157   std::string link(chrome::kChromeUIExtensionsURL);
158   link += "?id=" + link_controls_[button];
159   web_contents_->OpenURL(OpenURLParams(GURL(link),
160                                        Referrer(),
161                                        NEW_FOREGROUND_TAB,
162                                        content::PAGE_TRANSITION_LINK,
163                                        false));
164   Close();
165 }
166