Home | History | Annotate | Download | only in gtk
      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
     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
     53 void ScriptBubbleGtk::OnItemLinkClickedThunk(GtkWidget* sender,
     54                                              void* user_data) {
     55   g_bubble->OnItemLinkClicked(sender);
     56 }
     57 
     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 
     66 ScriptBubbleGtk::~ScriptBubbleGtk() {
     67 }
     68 
     69 void ScriptBubbleGtk::Close() {
     70   if (bubble_)
     71     bubble_->Close();
     72 }
     73 
     74 void ScriptBubbleGtk::BubbleClosing(BubbleGtk* bubble,
     75                                     bool closed_by_escape) {
     76   g_bubble = NULL;
     77   delete this;
     78 }
     79 
     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 
    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 
    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