Home | History | Annotate | Download | only in website_settings
      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/website_settings/website_settings_popup_gtk.h"
      6 
      7 #include "base/i18n/rtl.h"
      8 #include "base/strings/string_number_conversions.h"
      9 #include "base/strings/utf_string_conversions.h"
     10 #include "chrome/browser/certificate_viewer.h"
     11 #include "chrome/browser/chrome_notification_types.h"
     12 #include "chrome/browser/infobars/infobar_service.h"
     13 #include "chrome/browser/ui/browser.h"
     14 #include "chrome/browser/ui/browser_list.h"
     15 #include "chrome/browser/ui/gtk/browser_toolbar_gtk.h"
     16 #include "chrome/browser/ui/gtk/browser_window_gtk.h"
     17 #include "chrome/browser/ui/gtk/collected_cookies_gtk.h"
     18 #include "chrome/browser/ui/gtk/gtk_chrome_link_button.h"
     19 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
     20 #include "chrome/browser/ui/gtk/gtk_util.h"
     21 #include "chrome/browser/ui/gtk/location_bar_view_gtk.h"
     22 #include "chrome/browser/ui/gtk/nine_box.h"
     23 #include "chrome/browser/ui/gtk/website_settings/permission_selector.h"
     24 #include "chrome/browser/ui/website_settings/website_settings.h"
     25 #include "chrome/browser/ui/website_settings/website_settings_utils.h"
     26 #include "chrome/common/url_constants.h"
     27 #include "content/public/browser/cert_store.h"
     28 #include "content/public/browser/notification_service.h"
     29 #include "content/public/browser/user_metrics.h"
     30 #include "grit/chromium_strings.h"
     31 #include "grit/generated_resources.h"
     32 #include "grit/locale_settings.h"
     33 #include "grit/theme_resources.h"
     34 #include "grit/ui_resources.h"
     35 #include "ui/base/gtk/gtk_hig_constants.h"
     36 #include "ui/base/l10n/l10n_util.h"
     37 #include "ui/base/resource/resource_bundle.h"
     38 #include "ui/gfx/image/cairo_cached_surface.h"
     39 #include "ui/gfx/image/image.h"
     40 #include "url/gurl.h"
     41 
     42 using content::OpenURLParams;
     43 
     44 namespace {
     45 
     46 // The width of the popup.
     47 const int kPopupWidth = 400;
     48 
     49 // Spacing between consecutive tabs in the tabstrip.
     50 const int kInterTabSpacing = 2;
     51 
     52 // Spacing between start of tab and tab text.
     53 const int kTabTextHorizontalMargin = 12;
     54 
     55 // The vertical lift of the tab's text off the bottom of the tab.
     56 const int kTabTextBaseline = 4;
     57 
     58 // The max width of the text labels on the connection tab.
     59 const int kConnectionTabTextWidth = 300;
     60 
     61 // The text color of the site identity status label for websites with a
     62 // verified identity.
     63 const GdkColor kGdkGreen = GDK_COLOR_RGB(0x29, 0x8a, 0x27);
     64 
     65 GtkWidget* CreateTextLabel(const std::string& text,
     66                            int width,
     67                            GtkThemeService* theme_service,
     68                            const GdkColor& color) {
     69   GtkWidget* label = theme_service->BuildLabel(text, color);
     70   if (width > 0)
     71     gtk_util::SetLabelWidth(label, width);
     72   gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD_CHAR);
     73   return label;
     74 }
     75 
     76 void ClearContainer(GtkWidget* container) {
     77   GList* child = gtk_container_get_children(GTK_CONTAINER(container));
     78   for (GList* item = child; item; item = g_list_next(item))
     79     gtk_container_remove(GTK_CONTAINER(container), GTK_WIDGET(item->data));
     80 
     81   g_list_free(child);
     82 }
     83 
     84 void SetConnectionSection(GtkWidget* section_box,
     85                           const gfx::Image& icon,
     86                           GtkWidget* content_box) {
     87   DCHECK(section_box);
     88   ClearContainer(section_box);
     89   gtk_container_set_border_width(GTK_CONTAINER(section_box),
     90                                  ui::kContentAreaBorder);
     91 
     92   GtkWidget* hbox = gtk_hbox_new(FALSE, ui::kControlSpacing);
     93 
     94   GdkPixbuf* pixbuf = icon.ToGdkPixbuf();
     95   GtkWidget* image = gtk_image_new_from_pixbuf(pixbuf);
     96   gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
     97   gtk_misc_set_alignment(GTK_MISC(image), 0, 0);
     98 
     99   gtk_box_pack_start(GTK_BOX(hbox), content_box, TRUE, TRUE, 0);
    100 
    101   gtk_box_pack_start(GTK_BOX(section_box), hbox, TRUE, TRUE, 0);
    102   gtk_widget_show_all(section_box);
    103 }
    104 
    105 GtkWidget* CreatePermissionTabSection(std::string section_title,
    106                                       GtkWidget* section_content,
    107                                       GtkThemeService* theme_service) {
    108   GtkWidget* section_box = gtk_vbox_new(FALSE, ui::kControlSpacing);
    109 
    110   // Add Section title
    111   GtkWidget* title_hbox = gtk_hbox_new(FALSE, ui::kControlSpacing);
    112 
    113   GtkWidget* label = theme_service->BuildLabel(section_title, ui::kGdkBlack);
    114   PangoAttrList* attributes = pango_attr_list_new();
    115   pango_attr_list_insert(attributes,
    116                          pango_attr_weight_new(PANGO_WEIGHT_BOLD));
    117   gtk_label_set_attributes(GTK_LABEL(label), attributes);
    118   pango_attr_list_unref(attributes);
    119   gtk_box_pack_start(GTK_BOX(section_box), title_hbox, FALSE, FALSE, 0);
    120 
    121   gtk_box_pack_start(GTK_BOX(title_hbox), label, FALSE, FALSE, 0);
    122 
    123   // Add section content
    124   gtk_box_pack_start(GTK_BOX(section_box), section_content, FALSE, FALSE, 0);
    125   return section_box;
    126 }
    127 
    128 // A popup that is shown for internal pages (like chrome://).
    129 class InternalPageInfoPopupGtk : public BubbleDelegateGtk {
    130  public:
    131   explicit InternalPageInfoPopupGtk(gfx::NativeWindow parent,
    132                                           Profile* profile);
    133   virtual ~InternalPageInfoPopupGtk();
    134 
    135  private:
    136   // BubbleDelegateGtk implementation.
    137   virtual void BubbleClosing(BubbleGtk* bubble, bool closed_by_escape) OVERRIDE;
    138 
    139   // The popup bubble container.
    140   BubbleGtk* bubble_;
    141 
    142   DISALLOW_COPY_AND_ASSIGN(InternalPageInfoPopupGtk);
    143 };
    144 
    145 InternalPageInfoPopupGtk::InternalPageInfoPopupGtk(
    146     gfx::NativeWindow parent, Profile* profile) {
    147   GtkWidget* contents = gtk_hbox_new(FALSE, ui::kLabelSpacing);
    148   gtk_container_set_border_width(GTK_CONTAINER(contents),
    149                                  ui::kContentAreaBorder);
    150   // Add the popup icon.
    151   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    152   GdkPixbuf* pixbuf = rb.GetNativeImageNamed(IDR_PRODUCT_LOGO_26).ToGdkPixbuf();
    153   GtkWidget* image = gtk_image_new_from_pixbuf(pixbuf);
    154   gtk_box_pack_start(GTK_BOX(contents), image, FALSE, FALSE, 0);
    155   gtk_misc_set_alignment(GTK_MISC(image), 0, 0);
    156 
    157   // Add the popup text.
    158   GtkThemeService* theme_service = GtkThemeService::GetFrom(profile);
    159   GtkWidget* label = theme_service->BuildLabel(
    160       l10n_util::GetStringUTF8(IDS_PAGE_INFO_INTERNAL_PAGE), ui::kGdkBlack);
    161   gtk_box_pack_start(GTK_BOX(contents), label, FALSE, FALSE, 0);
    162 
    163   gtk_widget_show_all(contents);
    164 
    165   // Create the bubble.
    166   BrowserWindowGtk* browser_window =
    167       BrowserWindowGtk::GetBrowserWindowForNativeWindow(parent);
    168   GtkWidget* anchor = browser_window->
    169       GetToolbar()->GetLocationBarView()->location_icon_widget();
    170   bubble_ = BubbleGtk::Show(anchor,
    171                             NULL,  // |rect|
    172                             contents,
    173                             BubbleGtk::ANCHOR_TOP_LEFT,
    174                             BubbleGtk::MATCH_SYSTEM_THEME |
    175                                 BubbleGtk::POPUP_WINDOW |
    176                                 BubbleGtk::GRAB_INPUT,
    177                             theme_service,
    178                             this);  // |delegate|
    179   DCHECK(bubble_);
    180 }
    181 
    182 InternalPageInfoPopupGtk::~InternalPageInfoPopupGtk() {
    183 }
    184 
    185 void InternalPageInfoPopupGtk::BubbleClosing(BubbleGtk* bubble,
    186                                              bool closed_by_escape) {
    187   delete this;
    188 }
    189 
    190 }  // namespace
    191 
    192 // static
    193 void WebsiteSettingsPopupGtk::Show(gfx::NativeWindow parent,
    194                                    Profile* profile,
    195                                    content::WebContents* web_contents,
    196                                    const GURL& url,
    197                                    const content::SSLStatus& ssl) {
    198   if (InternalChromePage(url))
    199     new InternalPageInfoPopupGtk(parent, profile);
    200   else
    201     new WebsiteSettingsPopupGtk(parent, profile, web_contents, url, ssl);
    202 }
    203 
    204 WebsiteSettingsPopupGtk::WebsiteSettingsPopupGtk(
    205     gfx::NativeWindow parent,
    206     Profile* profile,
    207     content::WebContents* web_contents,
    208     const GURL& url,
    209     const content::SSLStatus& ssl)
    210     : parent_(parent),
    211       contents_(NULL),
    212       theme_service_(GtkThemeService::GetFrom(profile)),
    213       profile_(profile),
    214       web_contents_(web_contents),
    215       browser_(NULL),
    216       cert_id_(0),
    217       header_box_(NULL),
    218       cookies_section_contents_(NULL),
    219       permissions_section_contents_(NULL),
    220       identity_contents_(NULL),
    221       connection_contents_(NULL),
    222       first_visit_contents_(NULL),
    223       notebook_(NULL) {
    224   BrowserWindowGtk* browser_window =
    225       BrowserWindowGtk::GetBrowserWindowForNativeWindow(parent);
    226   browser_ = browser_window->browser();
    227   anchor_ = browser_window->
    228       GetToolbar()->GetLocationBarView()->location_icon_widget();
    229 
    230   registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
    231                  content::Source<ThemeService>(theme_service_));
    232 
    233   InitContents();
    234 
    235   bubble_ = BubbleGtk::Show(anchor_,
    236                             NULL,  // |rect|
    237                             contents_,
    238                             BubbleGtk::ANCHOR_TOP_LEFT,
    239                             BubbleGtk::MATCH_SYSTEM_THEME |
    240                                 BubbleGtk::POPUP_WINDOW |
    241                                 BubbleGtk::GRAB_INPUT,
    242                             theme_service_,
    243                             this);  // |delegate|
    244   if (!bubble_) {
    245     NOTREACHED();
    246     return;
    247   }
    248 
    249   presenter_.reset(new WebsiteSettings(
    250       this, profile, TabSpecificContentSettings::FromWebContents(web_contents),
    251       InfoBarService::FromWebContents(web_contents), url, ssl,
    252       content::CertStore::GetInstance()));
    253 }
    254 
    255 WebsiteSettingsPopupGtk::~WebsiteSettingsPopupGtk() {
    256 }
    257 
    258 void WebsiteSettingsPopupGtk::BubbleClosing(BubbleGtk* bubble,
    259                                             bool closed_by_escape) {
    260   if (presenter_.get()) {
    261     presenter_->OnUIClosing();
    262     presenter_.reset();
    263   }
    264 
    265   // Slightly delay destruction to allow the event stack to unwind and release
    266   // references to owned widgets.
    267   base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
    268 }
    269 
    270 void WebsiteSettingsPopupGtk::InitContents() {
    271   if (!contents_)
    272     contents_ = gtk_vbox_new(FALSE, 0);
    273   else
    274     gtk_util::RemoveAllChildren(contents_);
    275 
    276   // Create popup header.
    277   header_box_ = gtk_vbox_new(FALSE, ui::kControlSpacing);
    278   gtk_box_pack_start(GTK_BOX(contents_), header_box_, FALSE, FALSE, 0);
    279   gtk_container_set_border_width(GTK_CONTAINER(header_box_),
    280                                  ui::kContentAreaBorder);
    281 
    282   // Create the container for the contents of the permissions tab.
    283   GtkWidget* permission_tab_contents =
    284       gtk_vbox_new(FALSE, ui::kContentAreaSpacing);
    285   gtk_container_set_border_width(GTK_CONTAINER(permission_tab_contents),
    286                                  ui::kContentAreaBorder);
    287   cookies_section_contents_ = gtk_vbox_new(FALSE, ui::kControlSpacing);
    288   std::string title = l10n_util::GetStringUTF8(
    289       IDS_WEBSITE_SETTINGS_TITLE_SITE_DATA);
    290   gtk_box_pack_start(GTK_BOX(permission_tab_contents),
    291                      CreatePermissionTabSection(title,
    292                                                 cookies_section_contents_,
    293                                                 theme_service_),
    294                      FALSE, FALSE, 0);
    295   permissions_section_contents_ = gtk_vbox_new(FALSE, ui::kControlSpacing);
    296   title = l10n_util::GetStringUTF8(IDS_WEBSITE_SETTINGS_TITLE_SITE_PERMISSIONS);
    297   gtk_box_pack_start(GTK_BOX(permission_tab_contents),
    298                      CreatePermissionTabSection(title,
    299                                                 permissions_section_contents_,
    300                                                 theme_service_),
    301                      FALSE, FALSE, 0);
    302 
    303   // Create the container for the contents of the connection tab.
    304   GtkWidget* connection_tab = gtk_vbox_new(FALSE, 0);
    305   identity_contents_ = gtk_vbox_new(FALSE, 0);
    306   gtk_box_pack_start(GTK_BOX(connection_tab), identity_contents_, FALSE, FALSE,
    307                      0);
    308   gtk_box_pack_start(GTK_BOX(connection_tab), gtk_hseparator_new(), FALSE,
    309                      FALSE, 0);
    310   connection_contents_ = gtk_vbox_new(FALSE, 0);
    311   gtk_box_pack_start(GTK_BOX(connection_tab), connection_contents_, FALSE,
    312                      FALSE, 0);
    313   gtk_box_pack_start(GTK_BOX(connection_tab), gtk_hseparator_new(), FALSE,
    314                      FALSE, 0);
    315   first_visit_contents_ = gtk_vbox_new(FALSE, 0);
    316   gtk_box_pack_start(GTK_BOX(connection_tab), first_visit_contents_, FALSE,
    317                      FALSE, 0);
    318   gtk_box_pack_start(GTK_BOX(connection_tab), gtk_hseparator_new(), FALSE,
    319                      FALSE, 0);
    320 
    321   GtkWidget* help_link = theme_service_->BuildChromeLinkButton(
    322       l10n_util::GetStringUTF8(IDS_PAGE_INFO_HELP_CENTER_LINK));
    323   GtkWidget* help_link_hbox = gtk_hbox_new(FALSE, 0);
    324   gtk_container_set_border_width(GTK_CONTAINER(help_link_hbox),
    325                                  ui::kContentAreaBorder);
    326   gtk_box_pack_start(GTK_BOX(help_link_hbox), help_link, FALSE, FALSE, 0);
    327   gtk_box_pack_start(GTK_BOX(connection_tab), help_link_hbox, FALSE, FALSE, 0);
    328   g_signal_connect(help_link, "clicked",
    329                    G_CALLBACK(OnHelpLinkClickedThunk), this);
    330 
    331   // Create tabstrip (used only for Chrome-theme mode).
    332   GtkWidget* tabstrip = gtk_hbox_new(FALSE, kInterTabSpacing);
    333   tabstrip_alignment_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
    334   gtk_alignment_set_padding(GTK_ALIGNMENT(tabstrip_alignment_), 0, 0,
    335                             ui::kContentAreaBorder, ui::kContentAreaBorder);
    336   int tab_height = ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(
    337       IDR_WEBSITE_SETTINGS_TAB_LEFT2).ToImageSkia()->height();
    338   gtk_widget_set_size_request(tabstrip_alignment_, -1, tab_height);
    339   g_signal_connect(tabstrip_alignment_, "expose-event",
    340                    G_CALLBACK(&OnTabstripExposeThunk), this);
    341   gtk_container_add(GTK_CONTAINER(tabstrip_alignment_), tabstrip);
    342   gtk_box_pack_start(GTK_BOX(contents_), tabstrip_alignment_, FALSE, FALSE, 0);
    343 
    344   gtk_box_pack_start(GTK_BOX(tabstrip),
    345       BuildTab(IDS_WEBSITE_SETTINGS_TAB_LABEL_PERMISSIONS),
    346       FALSE, FALSE, 0);
    347   gtk_box_pack_start(GTK_BOX(tabstrip),
    348       BuildTab(IDS_WEBSITE_SETTINGS_TAB_LABEL_CONNECTION),
    349       FALSE, FALSE, 0);
    350 
    351   // Create tab container and add all tabs.
    352   notebook_ = gtk_notebook_new();
    353   gtk_notebook_set_tab_hborder(GTK_NOTEBOOK(notebook_), 0);
    354 
    355   GtkWidget* label = gtk_label_new(l10n_util::GetStringUTF8(
    356       IDS_WEBSITE_SETTINGS_TAB_LABEL_PERMISSIONS).c_str());
    357   gtk_misc_set_padding(GTK_MISC(label), kTabTextHorizontalMargin, 0);
    358   gtk_notebook_insert_page(GTK_NOTEBOOK(notebook_), permission_tab_contents,
    359                            label, TAB_ID_PERMISSIONS);
    360 
    361   label = gtk_label_new(l10n_util::GetStringUTF8(
    362       IDS_WEBSITE_SETTINGS_TAB_LABEL_CONNECTION).c_str());
    363   gtk_misc_set_padding(GTK_MISC(label), kTabTextHorizontalMargin, 0);
    364   gtk_notebook_insert_page(GTK_NOTEBOOK(notebook_), connection_tab, label,
    365                            TAB_ID_CONNECTION);
    366 
    367   DCHECK_EQ(gtk_notebook_get_n_pages(GTK_NOTEBOOK(notebook_)), NUM_TAB_IDS);
    368 
    369   gtk_box_pack_start(GTK_BOX(contents_), notebook_, FALSE, FALSE, 0);
    370 
    371   theme_service_->InitThemesFor(this);
    372   gtk_widget_show_all(contents_);
    373 }
    374 
    375 GtkWidget* WebsiteSettingsPopupGtk::BuildTab(int ids) {
    376   GtkWidget* tab = gtk_event_box_new();
    377   gtk_event_box_set_visible_window(GTK_EVENT_BOX(tab), FALSE);
    378   GtkWidget* label = gtk_label_new(l10n_util::GetStringUTF8(ids).c_str());
    379   gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &ui::kGdkBlack);
    380   gtk_misc_set_padding(GTK_MISC(label),
    381                        kTabTextHorizontalMargin, kTabTextBaseline);
    382   gtk_misc_set_alignment(GTK_MISC(label), 0.5, 1.0);
    383   gtk_container_add(GTK_CONTAINER(tab), label);
    384   g_signal_connect(tab, "button-press-event",
    385                    G_CALLBACK(&OnTabButtonPressThunk), this);
    386   g_signal_connect(tab, "expose-event",
    387                    G_CALLBACK(&OnTabExposeThunk), this);
    388   return tab;
    389 }
    390 
    391 void WebsiteSettingsPopupGtk::Observe(
    392     int type,
    393     const content::NotificationSource& source,
    394     const content::NotificationDetails& details) {
    395   DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED, type);
    396 
    397   if (theme_service_->UsingNativeTheme()) {
    398     gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook_), TRUE);
    399     gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook_), TRUE);
    400     gtk_widget_set_no_show_all(tabstrip_alignment_, TRUE);
    401   } else {
    402     gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook_), FALSE);
    403     gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook_), FALSE);
    404     gtk_widget_set_no_show_all(tabstrip_alignment_, FALSE);
    405     gtk_widget_show_all(tabstrip_alignment_);
    406   }
    407 }
    408 
    409 void WebsiteSettingsPopupGtk::OnPermissionChanged(
    410     PermissionSelector* selector) {
    411   presenter_->OnSitePermissionChanged(selector->GetType(),
    412                                       selector->GetSetting());
    413 }
    414 
    415 void WebsiteSettingsPopupGtk::SetCookieInfo(
    416     const CookieInfoList& cookie_info_list) {
    417   DCHECK(cookies_section_contents_);
    418   ClearContainer(cookies_section_contents_);
    419 
    420   // Create cookies info rows.
    421   for (CookieInfoList::const_iterator it = cookie_info_list.begin();
    422        it != cookie_info_list.end();
    423        ++it) {
    424     // Create the cookies info box.
    425     GtkWidget* cookies_info = gtk_hbox_new(FALSE, 0);
    426 
    427     // Add the icon to the cookies info box
    428     GdkPixbuf* pixbuf = WebsiteSettingsUI::GetPermissionIcon(
    429         CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_ALLOW).ToGdkPixbuf();
    430     GtkWidget* image = gtk_image_new_from_pixbuf(pixbuf);
    431     gtk_misc_set_alignment(GTK_MISC(image), 0, 0);
    432     gtk_box_pack_start(GTK_BOX(cookies_info), image, FALSE, FALSE, 0);
    433 
    434     // Add the allowed and blocked cookies counts to the cookies info box.
    435     std::string info_str = l10n_util::GetStringFUTF8(
    436         IDS_WEBSITE_SETTINGS_SITE_DATA_STATS_LINE,
    437         UTF8ToUTF16(it->cookie_source),
    438         base::IntToString16(it->allowed),
    439         base::IntToString16(it->blocked));
    440 
    441     GtkWidget* info = theme_service_->BuildLabel(info_str, ui::kGdkBlack);
    442     const int kPadding = 4;
    443     gtk_box_pack_start(GTK_BOX(cookies_info), info, FALSE, FALSE, kPadding);
    444 
    445     // Add the cookies info box to the section box.
    446     gtk_box_pack_start(GTK_BOX(cookies_section_contents_),
    447                        cookies_info,
    448                        FALSE, FALSE, 0);
    449   }
    450 
    451   // Create row with links for cookie settings and for the cookies dialog.
    452   GtkWidget* link_hbox = gtk_hbox_new(FALSE, 0);
    453 
    454   GtkWidget* view_cookies_link = theme_service_->BuildChromeLinkButton(
    455       l10n_util::GetStringUTF8(IDS_WEBSITE_SETTINGS_SHOW_SITE_DATA));
    456   g_signal_connect(view_cookies_link, "clicked",
    457                    G_CALLBACK(OnCookiesLinkClickedThunk), this);
    458   gtk_box_pack_start(GTK_BOX(link_hbox), view_cookies_link,
    459                      FALSE, FALSE, 0);
    460 
    461   gtk_box_pack_start(GTK_BOX(cookies_section_contents_), link_hbox,
    462                      TRUE, FALSE, 0);
    463 
    464   gtk_widget_show_all(cookies_section_contents_);
    465 }
    466 
    467 void WebsiteSettingsPopupGtk::SetIdentityInfo(
    468     const IdentityInfo& identity_info) {
    469   // Create popup header.
    470   DCHECK(header_box_);
    471   ClearContainer(header_box_);
    472 
    473   GtkWidget* hbox = gtk_hbox_new(FALSE, 0);
    474   GtkWidget* identity_label = theme_service_->BuildLabel(
    475       identity_info.site_identity, ui::kGdkBlack);
    476   gtk_label_set_selectable(GTK_LABEL(identity_label), TRUE);
    477   PangoAttrList* attributes = pango_attr_list_new();
    478   pango_attr_list_insert(attributes,
    479                          pango_attr_weight_new(PANGO_WEIGHT_BOLD));
    480   gtk_label_set_attributes(GTK_LABEL(identity_label), attributes);
    481   pango_attr_list_unref(attributes);
    482   gtk_box_pack_start(GTK_BOX(hbox), identity_label, FALSE, FALSE, 0);
    483   close_button_.reset(CustomDrawButton::CloseButtonBubble(theme_service_));
    484   g_signal_connect(close_button_->widget(), "clicked",
    485                    G_CALLBACK(OnCloseButtonClickedThunk), this);
    486   gtk_box_pack_start(GTK_BOX(hbox), close_button_->widget(), FALSE, FALSE, 0);
    487   int label_width = kPopupWidth - close_button_->SurfaceWidth();
    488   gtk_util::SetLabelWidth(identity_label, label_width);
    489   gtk_box_pack_start(GTK_BOX(header_box_), hbox, FALSE, FALSE, 0);
    490 
    491   std::string identity_status_text;
    492   const GdkColor* color = &ui::kGdkBlack;
    493 
    494   switch (identity_info.identity_status) {
    495     case WebsiteSettings::SITE_IDENTITY_STATUS_CERT:
    496     case WebsiteSettings::SITE_IDENTITY_STATUS_EV_CERT:
    497       identity_status_text =
    498           l10n_util::GetStringUTF8(IDS_WEBSITE_SETTINGS_IDENTITY_VERIFIED);
    499       color = &kGdkGreen;
    500       break;
    501     case WebsiteSettings::SITE_IDENTITY_STATUS_ADMIN_PROVIDED_CERT:
    502       identity_status_text =
    503           l10n_util::GetStringUTF8(IDS_CERT_POLICY_PROVIDED_CERT_HEADER);
    504       break;
    505     default:
    506       identity_status_text =
    507           l10n_util::GetStringUTF8(IDS_WEBSITE_SETTINGS_IDENTITY_NOT_VERIFIED);
    508       break;
    509   }
    510   GtkWidget* status_label = CreateTextLabel(
    511       identity_status_text, kPopupWidth, theme_service_, *color);
    512   gtk_box_pack_start(
    513       GTK_BOX(header_box_), status_label, FALSE, FALSE, 0);
    514   gtk_widget_show_all(header_box_);
    515 
    516   // Create identity section.
    517   GtkWidget* section_content = gtk_vbox_new(FALSE, ui::kControlSpacing);
    518   GtkWidget* identity_description =
    519       CreateTextLabel(identity_info.identity_status_description,
    520                       kConnectionTabTextWidth, theme_service_, ui::kGdkBlack);
    521   gtk_box_pack_start(GTK_BOX(section_content), identity_description, FALSE,
    522                      FALSE, 0);
    523   if (identity_info.cert_id) {
    524     cert_id_ = identity_info.cert_id;
    525     GtkWidget* view_cert_link = theme_service_->BuildChromeLinkButton(
    526         l10n_util::GetStringUTF8(IDS_PAGEINFO_CERT_INFO_BUTTON));
    527     g_signal_connect(view_cert_link, "clicked",
    528                      G_CALLBACK(OnViewCertLinkClickedThunk), this);
    529     GtkWidget* link_hbox = gtk_hbox_new(FALSE, 0);
    530     gtk_box_pack_start(GTK_BOX(link_hbox), view_cert_link,
    531                        FALSE, FALSE, 0);
    532     gtk_box_pack_start(GTK_BOX(section_content), link_hbox, FALSE, FALSE, 0);
    533   }
    534   SetConnectionSection(
    535       identity_contents_,
    536       WebsiteSettingsUI::GetIdentityIcon(identity_info.identity_status),
    537       section_content);
    538 
    539   // Create connection section.
    540   GtkWidget* connection_description =
    541       CreateTextLabel(identity_info.connection_status_description,
    542                       kConnectionTabTextWidth, theme_service_, ui::kGdkBlack);
    543   section_content = gtk_vbox_new(FALSE, ui::kControlSpacing);
    544   gtk_box_pack_start(GTK_BOX(section_content), connection_description, FALSE,
    545                      FALSE, 0);
    546   SetConnectionSection(
    547       connection_contents_,
    548       WebsiteSettingsUI::GetConnectionIcon(identity_info.connection_status),
    549       section_content);
    550 }
    551 
    552 void WebsiteSettingsPopupGtk::SetFirstVisit(const string16& first_visit) {
    553   GtkWidget* title = theme_service_->BuildLabel(
    554       l10n_util::GetStringUTF8(IDS_PAGE_INFO_SITE_INFO_TITLE),
    555       ui::kGdkBlack);
    556   PangoAttrList* attributes = pango_attr_list_new();
    557   pango_attr_list_insert(attributes,
    558                          pango_attr_weight_new(PANGO_WEIGHT_BOLD));
    559   gtk_label_set_attributes(GTK_LABEL(title), attributes);
    560   pango_attr_list_unref(attributes);
    561   gtk_misc_set_alignment(GTK_MISC(title), 0, 0);
    562 
    563   GtkWidget* first_visit_label = CreateTextLabel(UTF16ToUTF8(first_visit),
    564                                                  kConnectionTabTextWidth,
    565                                                  theme_service_,
    566                                                  ui::kGdkBlack);
    567   GtkWidget* section_contents = gtk_vbox_new(FALSE, ui::kControlSpacing);
    568   gtk_box_pack_start(GTK_BOX(section_contents), title, FALSE, FALSE, 0);
    569   gtk_box_pack_start(
    570       GTK_BOX(section_contents), first_visit_label, FALSE, FALSE, 0);
    571 
    572   SetConnectionSection(
    573       first_visit_contents_,
    574       WebsiteSettingsUI::GetFirstVisitIcon(first_visit),
    575       section_contents);
    576 }
    577 
    578 void WebsiteSettingsPopupGtk::SetPermissionInfo(
    579       const PermissionInfoList& permission_info_list) {
    580   DCHECK(permissions_section_contents_);
    581   ClearContainer(permissions_section_contents_);
    582   // Clear the map since the UI is reconstructed.
    583   selectors_.clear();
    584 
    585   for (PermissionInfoList::const_iterator permission =
    586            permission_info_list.begin();
    587        permission != permission_info_list.end();
    588        ++permission) {
    589     PermissionSelector* selector =
    590         new PermissionSelector(
    591            theme_service_,
    592            web_contents_ ? web_contents_->GetURL() : GURL::EmptyGURL(),
    593            permission->type,
    594            permission->setting,
    595            permission->default_setting,
    596            permission->source);
    597     selector->AddObserver(this);
    598     GtkWidget* hbox = selector->widget();
    599     selectors_.push_back(selector);
    600     gtk_box_pack_start(GTK_BOX(permissions_section_contents_), hbox, FALSE,
    601                        FALSE, 0);
    602   }
    603 
    604   gtk_widget_show_all(permissions_section_contents_);
    605 }
    606 
    607 void WebsiteSettingsPopupGtk::SetSelectedTab(TabId tab_id) {
    608   DCHECK(notebook_);
    609   gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook_),
    610                                 static_cast<gint>(tab_id));
    611 }
    612 
    613 int WebsiteSettingsPopupGtk::TabstripButtonToTabIndex(GtkWidget* button) {
    614   GList* tabs = gtk_container_get_children(GTK_CONTAINER(button->parent));
    615   int i = 0;
    616   for (GList* it = tabs; it; it = g_list_next(it), ++i) {
    617     if (it->data == button)
    618       break;
    619   }
    620   g_list_free(tabs);
    621 
    622   return i;
    623 }
    624 
    625 gboolean WebsiteSettingsPopupGtk::OnTabButtonPress(
    626     GtkWidget* widget, GdkEvent* event) {
    627   gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook_),
    628                                 TabstripButtonToTabIndex(widget));
    629   gtk_widget_queue_draw(tabstrip_alignment_);
    630   return FALSE;
    631 }
    632 
    633 gboolean WebsiteSettingsPopupGtk::OnTabExpose(
    634     GtkWidget* widget, GdkEventExpose* event) {
    635   if (gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook_)) !=
    636       TabstripButtonToTabIndex(widget)) {
    637     return FALSE;
    638   }
    639 
    640   NineBox nine(IDR_WEBSITE_SETTINGS_TAB_LEFT2,
    641                IDR_WEBSITE_SETTINGS_TAB_CENTER2,
    642                IDR_WEBSITE_SETTINGS_TAB_RIGHT2,
    643                0, 0, 0, 0, 0, 0);
    644   nine.RenderToWidget(widget);
    645 
    646   return FALSE;
    647 }
    648 
    649 gboolean WebsiteSettingsPopupGtk::OnTabstripExpose(
    650     GtkWidget* widget, GdkEventExpose* event) {
    651   int tab_idx = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook_));
    652   GtkWidget* tabstrip = gtk_bin_get_child(GTK_BIN(tabstrip_alignment_));
    653   GList* tabs = gtk_container_get_children(GTK_CONTAINER(tabstrip));
    654   GtkWidget* selected_tab = GTK_WIDGET(g_list_nth_data(tabs, tab_idx));
    655   g_list_free(tabs);
    656   GtkAllocation tab_bounds;
    657   gtk_widget_get_allocation(selected_tab, &tab_bounds);
    658 
    659   cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(gtk_widget_get_window(widget)));
    660   GtkAllocation allocation;
    661   gtk_widget_get_allocation(widget, &allocation);
    662   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
    663 
    664   // Draw the shadows that abut the selected tab.
    665   gfx::CairoCachedSurface* left_tab_shadow =
    666       rb.GetNativeImageNamed(IDR_WEBSITE_SETTINGS_TABSTRIP_LEFT).ToCairo();
    667   int tab_shadow_width = left_tab_shadow->Width();
    668   left_tab_shadow->SetSource(cr, widget,
    669       tab_bounds.x - tab_shadow_width, allocation.y);
    670   cairo_paint(cr);
    671 
    672   gfx::CairoCachedSurface* right_tab_shadow =
    673       rb.GetNativeImageNamed(IDR_WEBSITE_SETTINGS_TABSTRIP_RIGHT).ToCairo();
    674   right_tab_shadow->SetSource(cr, widget,
    675       tab_bounds.x + tab_bounds.width, allocation.y);
    676   cairo_paint(cr);
    677 
    678   // Draw the shadow for the inactive part of the tabstrip.
    679   gfx::CairoCachedSurface* tiling_shadow =
    680       rb.GetNativeImageNamed(IDR_WEBSITE_SETTINGS_TABSTRIP_CENTER).ToCairo();
    681 
    682   tiling_shadow->SetSource(cr, widget, allocation.x, allocation.y);
    683   cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
    684 
    685   GdkRectangle left_tiling_area =
    686       { allocation.x, allocation.y,
    687         tab_bounds.x - tab_shadow_width, allocation.height };
    688   GdkRectangle invalid_left_tiling_area;
    689   if (gdk_rectangle_intersect(&left_tiling_area, &event->area,
    690                               &invalid_left_tiling_area)) {
    691     gdk_cairo_rectangle(cr, &invalid_left_tiling_area);
    692     cairo_fill(cr);
    693   }
    694 
    695   GdkRectangle right_tiling_area =
    696       { tab_bounds.x + tab_bounds.width + tab_shadow_width,
    697         allocation.y,
    698         allocation.width,
    699         allocation.height };
    700   GdkRectangle invalid_right_tiling_area;
    701   if (gdk_rectangle_intersect(&right_tiling_area, &event->area,
    702                               &invalid_right_tiling_area)) {
    703     gdk_cairo_rectangle(cr, &invalid_right_tiling_area);
    704     cairo_fill(cr);
    705   }
    706 
    707   cairo_destroy(cr);
    708   return FALSE;
    709 }
    710 
    711 void WebsiteSettingsPopupGtk::OnCookiesLinkClicked(GtkWidget* widget) {
    712   // Count how often the Collected Cookies dialog is opened.
    713   content::RecordAction(
    714       content::UserMetricsAction("WebsiteSettings_CookiesDialogOpened"));
    715 
    716   new CollectedCookiesGtk(GTK_WINDOW(parent_), web_contents_);
    717   bubble_->Close();
    718 }
    719 
    720 void WebsiteSettingsPopupGtk::OnViewCertLinkClicked(GtkWidget* widget) {
    721   DCHECK_NE(cert_id_, 0);
    722   ShowCertificateViewerByID(web_contents_, GTK_WINDOW(parent_), cert_id_);
    723   bubble_->Close();
    724 }
    725 
    726 void WebsiteSettingsPopupGtk::OnCloseButtonClicked(GtkWidget* widget) {
    727   bubble_->Close();
    728 }
    729 
    730 void WebsiteSettingsPopupGtk::OnHelpLinkClicked(GtkWidget* widget) {
    731   browser_->OpenURL(OpenURLParams(GURL(chrome::kPageInfoHelpCenterURL),
    732                     content::Referrer(),
    733                     NEW_FOREGROUND_TAB,
    734                     content::PAGE_TRANSITION_LINK,
    735                      false));
    736   bubble_->Close();
    737 }
    738