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/sad_tab_gtk.h"
      6 
      7 #include "base/metrics/histogram.h"
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "chrome/browser/ui/gtk/gtk_chrome_link_button.h"
     10 #include "chrome/browser/ui/gtk/tab_contents/chrome_web_contents_view_delegate_gtk.h"
     11 #include "chrome/common/url_constants.h"
     12 #include "content/public/browser/web_contents.h"
     13 #include "grit/generated_resources.h"
     14 #include "grit/locale_settings.h"
     15 #include "grit/theme_resources.h"
     16 #include "ui/base/gtk/gtk_hig_constants.h"
     17 #include "ui/base/l10n/l10n_util.h"
     18 #include "ui/base/resource/resource_bundle.h"
     19 #include "ui/gfx/image/image.h"
     20 
     21 using content::OpenURLParams;
     22 using content::WebContents;
     23 
     24 namespace {
     25 
     26 // Background color of the content (a grayish blue) for a crashed tab.
     27 const GdkColor kCrashedBackgroundColor = GDK_COLOR_RGB(35, 48, 64);
     28 
     29 // Background color of the content (a grayish purple) for a killed
     30 // tab.  TODO(gspencer): update this for the "real" color when the UI
     31 // team provides one.  See http://crosbug.com/10711
     32 const GdkColor kKilledBackgroundColor = GDK_COLOR_RGB(57, 48, 88);
     33 
     34 // Construct a centered GtkLabel with a white foreground.
     35 // |format| is a printf-style format containing a %s;
     36 // |str| is substituted into the format.
     37 GtkWidget* MakeWhiteMarkupLabel(const char* format, const std::string& str) {
     38   GtkWidget* label = gtk_label_new(NULL);
     39   char* markup = g_markup_printf_escaped(format, str.c_str());
     40   gtk_label_set_markup(GTK_LABEL(label), markup);
     41   g_free(markup);
     42 
     43   // Center align and justify it.
     44   gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5);
     45   gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
     46 
     47   // Set text to white.
     48   GdkColor white = ui::kGdkWhite;
     49   gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &white);
     50 
     51   return label;
     52 }
     53 
     54 }  // namespace
     55 
     56 SadTabGtk::SadTabGtk(WebContents* web_contents, chrome::SadTabKind kind)
     57     : web_contents_(web_contents),
     58       kind_(kind) {
     59   DCHECK(web_contents_);
     60 
     61   switch (kind_) {
     62     case chrome::SAD_TAB_KIND_CRASHED: {
     63       static int crashed = 0;
     64       UMA_HISTOGRAM_CUSTOM_COUNTS(
     65           "Tabs.SadTab.CrashCreated", ++crashed, 1, 1000, 50);
     66       break;
     67     }
     68     case chrome::SAD_TAB_KIND_KILLED: {
     69       static int killed = 0;
     70       UMA_HISTOGRAM_CUSTOM_COUNTS(
     71           "Tabs.SadTab.KilledCreated", ++killed, 1, 1000, 50);
     72       break;
     73     }
     74     default:
     75       NOTREACHED();
     76   }
     77 
     78   // Use an event box to get the background painting correctly.
     79   event_box_.Own(gtk_event_box_new());
     80   gtk_widget_modify_bg(event_box_.get(), GTK_STATE_NORMAL,
     81       (kind == chrome::SAD_TAB_KIND_CRASHED) ?
     82           &kCrashedBackgroundColor : &kKilledBackgroundColor);
     83   // Allow ourselves to be resized arbitrarily small.
     84   gtk_widget_set_size_request(event_box_.get(), 0, 0);
     85 
     86   GtkWidget* centering = gtk_alignment_new(0.5, 0.5, 0.0, 0.0);
     87   gtk_container_add(GTK_CONTAINER(event_box_.get()), centering);
     88 
     89   // Use a vertical box to contain icon, title, message and link.
     90   GtkWidget* vbox = gtk_vbox_new(FALSE, 0);
     91   gtk_container_add(GTK_CONTAINER(centering), vbox);
     92 
     93   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
     94   // Add center-aligned image.
     95   GtkWidget* image = gtk_image_new_from_pixbuf(rb.GetNativeImageNamed(
     96       (kind == chrome::SAD_TAB_KIND_CRASHED) ?
     97           IDR_SAD_TAB : IDR_KILLED_TAB).ToGdkPixbuf());
     98   gtk_misc_set_alignment(GTK_MISC(image), 0.5, 0.5);
     99   gtk_box_pack_start(GTK_BOX(vbox), image, FALSE, FALSE, 0);
    100 
    101   // Add spacer between image and title.
    102   GtkWidget* spacer = gtk_label_new(NULL);
    103   gtk_label_set_markup(GTK_LABEL(spacer), "<span size=\"larger\"> </span>");
    104   gtk_box_pack_start(GTK_BOX(vbox), spacer, FALSE, FALSE, 0);
    105 
    106   // Add center-aligned title.
    107   GtkWidget* title = MakeWhiteMarkupLabel(
    108       "<span size=\"larger\" style=\"normal\"><b>%s</b></span>",
    109       l10n_util::GetStringUTF8((kind == chrome::SAD_TAB_KIND_CRASHED) ?
    110           IDS_SAD_TAB_TITLE : IDS_KILLED_TAB_TITLE));
    111   gtk_box_pack_start(GTK_BOX(vbox), title, FALSE, FALSE, 0);
    112 
    113   // Add spacer between title and message.
    114   spacer = gtk_label_new(" ");
    115   gtk_box_pack_start(GTK_BOX(vbox), spacer, FALSE, FALSE, 0);
    116 
    117   // Add center-aligned message.
    118   GtkWidget* message = MakeWhiteMarkupLabel(
    119       "<span style=\"normal\">%s</span>",
    120       l10n_util::GetStringUTF8((kind == chrome::SAD_TAB_KIND_CRASHED) ?
    121           IDS_SAD_TAB_MESSAGE : IDS_KILLED_TAB_MESSAGE));
    122   gtk_label_set_line_wrap(GTK_LABEL(message), TRUE);
    123   gtk_box_pack_start(GTK_BOX(vbox), message, FALSE, FALSE, 0);
    124 
    125   // Add spacer between message and link.
    126   spacer = gtk_label_new(" ");
    127   gtk_box_pack_start(GTK_BOX(vbox), spacer, FALSE, FALSE, 0);
    128 
    129   if (web_contents_) {
    130     // Create the help link and alignment.
    131     std::string link_text(l10n_util::GetStringUTF8(
    132         (kind == chrome::SAD_TAB_KIND_CRASHED) ?
    133             IDS_SAD_TAB_HELP_LINK : IDS_LEARN_MORE));
    134     GtkWidget* link = gtk_chrome_link_button_new(link_text.c_str());
    135     gtk_chrome_link_button_set_normal_color(GTK_CHROME_LINK_BUTTON(link),
    136                                             &ui::kGdkWhite);
    137     g_signal_connect(link, "clicked", G_CALLBACK(OnLinkButtonClickThunk), this);
    138     GtkWidget* help_alignment = gtk_alignment_new(0.5, 0.5, 0.0, 0.0);
    139 
    140     if (kind == chrome::SAD_TAB_KIND_CRASHED) {
    141       // Use a horizontal box to contain the help text and link.
    142       GtkWidget* help_hbox = gtk_hbox_new(FALSE, 0);
    143       gtk_container_add(GTK_CONTAINER(vbox), help_hbox);
    144 
    145       size_t offset = 0;
    146       string16 help_text(l10n_util::GetStringFUTF16(IDS_SAD_TAB_HELP_MESSAGE,
    147                                                     string16(), &offset));
    148       std::string help_prefix_text(UTF16ToUTF8(help_text.substr(0, offset)));
    149       std::string help_suffix_text(UTF16ToUTF8(help_text.substr(offset)));
    150 
    151       GtkWidget* help_prefix = MakeWhiteMarkupLabel(
    152           "<span style=\"normal\">%s</span>", help_prefix_text);
    153       GtkWidget* help_suffix = MakeWhiteMarkupLabel(
    154           "<span style=\"normal\">%s</span>", help_suffix_text);
    155 
    156       // Add the help link and text to the horizontal box.
    157       gtk_box_pack_start(GTK_BOX(help_hbox), help_prefix, FALSE, FALSE, 0);
    158       GtkWidget* link_alignment = gtk_alignment_new(0.5, 0.5, 0.0, 0.0);
    159       gtk_container_add(GTK_CONTAINER(link_alignment), link);
    160       gtk_box_pack_start(GTK_BOX(help_hbox), link_alignment, FALSE, FALSE, 0);
    161       gtk_box_pack_start(GTK_BOX(help_hbox), help_suffix, FALSE, FALSE, 0);
    162     } else {
    163       // Add just the help link to a centered alignment.
    164       gtk_container_add(GTK_CONTAINER(help_alignment), link);
    165     }
    166     gtk_box_pack_start(GTK_BOX(vbox), help_alignment, FALSE, FALSE, 0);
    167   }
    168 
    169   gtk_widget_show_all(event_box_.get());
    170 }
    171 
    172 SadTabGtk::~SadTabGtk() {
    173   event_box_.Destroy();
    174 }
    175 
    176 void SadTabGtk::Show() {
    177   switch (kind_) {
    178     case chrome::SAD_TAB_KIND_CRASHED: {
    179       static int crashed = 0;
    180       UMA_HISTOGRAM_CUSTOM_COUNTS(
    181           "Tabs.SadTab.CrashDisplayed", ++crashed, 1, 1000, 50);
    182       break;
    183     }
    184     case chrome::SAD_TAB_KIND_KILLED: {
    185       static int killed = 0;
    186       UMA_HISTOGRAM_CUSTOM_COUNTS(
    187           "Tabs.SadTab.KilledDisplayed", ++killed, 1, 1000, 50);
    188       break;
    189     }
    190     default:
    191       NOTREACHED();
    192   }
    193 
    194   GtkWidget* expanded_container =
    195       ChromeWebContentsViewDelegateGtk::GetFor(web_contents_)->
    196           expanded_container();
    197   gtk_container_add(GTK_CONTAINER(expanded_container), event_box_.get());
    198   gtk_widget_show(event_box_.get());
    199 }
    200 
    201 void SadTabGtk::Close() {
    202   GtkWidget* expanded_container =
    203       ChromeWebContentsViewDelegateGtk::GetFor(web_contents_)->
    204           expanded_container();
    205   gtk_container_remove(GTK_CONTAINER(expanded_container), event_box_.get());
    206 }
    207 
    208 void SadTabGtk::OnLinkButtonClick(GtkWidget* sender) {
    209   if (web_contents_) {
    210     GURL help_url((kind_ == chrome::SAD_TAB_KIND_CRASHED) ?
    211         chrome::kCrashReasonURL : chrome::kKillReasonURL);
    212     OpenURLParams params(help_url, content::Referrer(), CURRENT_TAB,
    213                          content::PAGE_TRANSITION_LINK, false);
    214     web_contents_->OpenURL(params);
    215   }
    216 }
    217 
    218 namespace chrome {
    219 
    220 SadTab* SadTab::Create(content::WebContents* web_contents, SadTabKind kind) {
    221   return new SadTabGtk(web_contents, kind);
    222 }
    223 
    224 }  // namespace chrome
    225