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.
5 #include "chrome/browser/ui/gtk/sad_tab_gtk.h"
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"
21 using content::OpenURLParams
;
22 using content::WebContents
;
26 // Background color of the content (a grayish blue) for a crashed tab.
27 const GdkColor kCrashedBackgroundColor
= GDK_COLOR_RGB(35, 48, 64);
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);
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
);
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
);
48 GdkColor white
= ui::kGdkWhite
;
49 gtk_widget_modify_fg(label
, GTK_STATE_NORMAL
, &white
);
56 SadTabGtk::SadTabGtk(WebContents
* web_contents
, chrome::SadTabKind kind
)
57 : web_contents_(web_contents
),
59 DCHECK(web_contents_
);
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);
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);
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);
86 GtkWidget
* centering
= gtk_alignment_new(0.5, 0.5, 0.0, 0.0);
87 gtk_container_add(GTK_CONTAINER(event_box_
.get()), centering
);
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
);
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);
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);
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);
113 // Add spacer between title and message.
114 spacer
= gtk_label_new(" ");
115 gtk_box_pack_start(GTK_BOX(vbox
), spacer
, FALSE
, FALSE
, 0);
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);
125 // Add spacer between message and link.
126 spacer
= gtk_label_new(" ");
127 gtk_box_pack_start(GTK_BOX(vbox
), spacer
, FALSE
, FALSE
, 0);
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
),
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);
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
);
146 base::string16
help_text(
147 l10n_util::GetStringFUTF16(IDS_SAD_TAB_HELP_MESSAGE
,
148 base::string16(), &offset
));
149 std::string
help_prefix_text(
150 base::UTF16ToUTF8(help_text
.substr(0, offset
)));
151 std::string
help_suffix_text(
152 base::UTF16ToUTF8(help_text
.substr(offset
)));
154 GtkWidget
* help_prefix
= MakeWhiteMarkupLabel(
155 "<span style=\"normal\">%s</span>", help_prefix_text
);
156 GtkWidget
* help_suffix
= MakeWhiteMarkupLabel(
157 "<span style=\"normal\">%s</span>", help_suffix_text
);
159 // Add the help link and text to the horizontal box.
160 gtk_box_pack_start(GTK_BOX(help_hbox
), help_prefix
, FALSE
, FALSE
, 0);
161 GtkWidget
* link_alignment
= gtk_alignment_new(0.5, 0.5, 0.0, 0.0);
162 gtk_container_add(GTK_CONTAINER(link_alignment
), link
);
163 gtk_box_pack_start(GTK_BOX(help_hbox
), link_alignment
, FALSE
, FALSE
, 0);
164 gtk_box_pack_start(GTK_BOX(help_hbox
), help_suffix
, FALSE
, FALSE
, 0);
166 // Add just the help link to a centered alignment.
167 gtk_container_add(GTK_CONTAINER(help_alignment
), link
);
169 gtk_box_pack_start(GTK_BOX(vbox
), help_alignment
, FALSE
, FALSE
, 0);
172 gtk_widget_show_all(event_box_
.get());
175 SadTabGtk::~SadTabGtk() {
176 event_box_
.Destroy();
179 void SadTabGtk::Show() {
181 case chrome::SAD_TAB_KIND_CRASHED
: {
182 static int crashed
= 0;
183 UMA_HISTOGRAM_CUSTOM_COUNTS(
184 "Tabs.SadTab.CrashDisplayed", ++crashed
, 1, 1000, 50);
187 case chrome::SAD_TAB_KIND_KILLED
: {
188 static int killed
= 0;
189 UMA_HISTOGRAM_CUSTOM_COUNTS(
190 "Tabs.SadTab.KilledDisplayed", ++killed
, 1, 1000, 50);
197 GtkWidget
* expanded_container
=
198 ChromeWebContentsViewDelegateGtk::GetFor(web_contents_
)->
199 expanded_container();
200 gtk_container_add(GTK_CONTAINER(expanded_container
), event_box_
.get());
201 gtk_widget_show(event_box_
.get());
204 void SadTabGtk::Close() {
205 GtkWidget
* expanded_container
=
206 ChromeWebContentsViewDelegateGtk::GetFor(web_contents_
)->
207 expanded_container();
208 gtk_container_remove(GTK_CONTAINER(expanded_container
), event_box_
.get());
211 void SadTabGtk::OnLinkButtonClick(GtkWidget
* sender
) {
213 GURL
help_url((kind_
== chrome::SAD_TAB_KIND_CRASHED
) ?
214 chrome::kCrashReasonURL
: chrome::kKillReasonURL
);
215 OpenURLParams
params(help_url
, content::Referrer(), CURRENT_TAB
,
216 content::PAGE_TRANSITION_LINK
, false);
217 web_contents_
->OpenURL(params
);
223 SadTab
* SadTab::Create(content::WebContents
* web_contents
, SadTabKind kind
) {
224 return new SadTabGtk(web_contents
, kind
);
227 } // namespace chrome