| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2010 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/gtk/about_chrome_dialog.h" | |
| 6 | |
| 7 #include <gtk/gtk.h> | |
| 8 | |
| 9 #include <string> | |
| 10 #include <vector> | |
| 11 | |
| 12 #include "app/l10n_util.h" | |
| 13 #include "app/resource_bundle.h" | |
| 14 #include "base/utf_string_conversions.h" | |
| 15 #include "chrome/browser/browser_list.h" | |
| 16 #include "chrome/browser/google/google_util.h" | |
| 17 #include "chrome/browser/gtk/cairo_cached_surface.h" | |
| 18 #include "chrome/browser/gtk/gtk_chrome_link_button.h" | |
| 19 #include "chrome/browser/gtk/gtk_theme_provider.h" | |
| 20 #include "chrome/browser/gtk/gtk_util.h" | |
| 21 #include "chrome/browser/platform_util.h" | |
| 22 #include "chrome/browser/profiles/profile.h" | |
| 23 #include "chrome/common/chrome_constants.h" | |
| 24 #include "chrome/common/chrome_version_info.h" | |
| 25 #include "chrome/common/url_constants.h" | |
| 26 #include "grit/chromium_strings.h" | |
| 27 #include "grit/generated_resources.h" | |
| 28 #include "grit/locale_settings.h" | |
| 29 #include "grit/theme_resources.h" | |
| 30 #include "webkit/glue/webkit_glue.h" | |
| 31 | |
| 32 namespace { | |
| 33 | |
| 34 // Left or right margin. | |
| 35 const int kPanelHorizMargin = 13; | |
| 36 | |
| 37 // Top or bottom margin. | |
| 38 const int kPanelVertMargin = 20; | |
| 39 | |
| 40 // Extra spacing between product name and version number. | |
| 41 const int kExtraLineSpacing = 5; | |
| 42 | |
| 43 // These are used as placeholder text around the links in the text in the about | |
| 44 // dialog. | |
| 45 const char* kBeginLinkChr = "BEGIN_LINK_CHR"; | |
| 46 const char* kBeginLinkOss = "BEGIN_LINK_OSS"; | |
| 47 // We don't actually use this one. | |
| 48 // const char* kEndLinkChr = "END_LINK_CHR"; | |
| 49 const char* kEndLinkOss = "END_LINK_OSS"; | |
| 50 const char* kBeginLink = "BEGIN_LINK"; | |
| 51 const char* kEndLink = "END_LINK"; | |
| 52 | |
| 53 void OnDialogResponse(GtkDialog* dialog, int response_id) { | |
| 54 // We're done. | |
| 55 gtk_widget_destroy(GTK_WIDGET(dialog)); | |
| 56 } | |
| 57 | |
| 58 void FixLabelWrappingCallback(GtkWidget *label, | |
| 59 GtkAllocation *allocation, | |
| 60 gpointer data) { | |
| 61 gtk_widget_set_size_request(label, allocation->width, -1); | |
| 62 } | |
| 63 | |
| 64 GtkWidget* MakeMarkupLabel(const char* format, const std::string& str) { | |
| 65 GtkWidget* label = gtk_label_new(NULL); | |
| 66 char* markup = g_markup_printf_escaped(format, str.c_str()); | |
| 67 gtk_label_set_markup(GTK_LABEL(label), markup); | |
| 68 g_free(markup); | |
| 69 | |
| 70 // Left align it. | |
| 71 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); | |
| 72 | |
| 73 return label; | |
| 74 } | |
| 75 | |
| 76 void OnLinkButtonClick(GtkWidget* button, const char* url) { | |
| 77 BrowserList::GetLastActive()-> | |
| 78 OpenURL(GURL(url), GURL(), NEW_WINDOW, PageTransition::LINK); | |
| 79 } | |
| 80 | |
| 81 const char* GetChromiumUrl() { | |
| 82 static GURL url = google_util::AppendGoogleLocaleParam( | |
| 83 GURL(chrome::kChromiumProjectURL)); | |
| 84 return url.spec().c_str(); | |
| 85 } | |
| 86 | |
| 87 gboolean OnEventBoxExpose(GtkWidget* event_box, | |
| 88 GdkEventExpose* expose, | |
| 89 gboolean user_data) { | |
| 90 cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(event_box->window)); | |
| 91 gdk_cairo_rectangle(cr, &expose->area); | |
| 92 cairo_clip(cr); | |
| 93 GtkThemeProvider* theme_provider = | |
| 94 GtkThemeProvider::GetFrom(BrowserList::GetLastActive()->profile()); | |
| 95 CairoCachedSurface* background = theme_provider->GetSurfaceNamed( | |
| 96 IDR_ABOUT_BACKGROUND_COLOR, event_box); | |
| 97 | |
| 98 background->SetSource(cr, 0, 0); | |
| 99 cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT); | |
| 100 gdk_cairo_rectangle(cr, &expose->area); | |
| 101 cairo_fill(cr); | |
| 102 cairo_destroy(cr); | |
| 103 return FALSE; | |
| 104 } | |
| 105 | |
| 106 } // namespace | |
| 107 | |
| 108 void ShowAboutDialogForProfile(GtkWindow* parent, Profile* profile) { | |
| 109 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 110 static GdkPixbuf* background = rb.GetPixbufNamed(IDR_ABOUT_BACKGROUND); | |
| 111 chrome::VersionInfo version_info; | |
| 112 std::string current_version = version_info.Version(); | |
| 113 #if !defined(GOOGLE_CHROME_BUILD) | |
| 114 current_version += " ("; | |
| 115 current_version += version_info.LastChange(); | |
| 116 current_version += ")"; | |
| 117 #endif | |
| 118 std::string channel = platform_util::GetVersionStringModifier(); | |
| 119 if (!channel.empty()) | |
| 120 current_version += " " + channel; | |
| 121 | |
| 122 // Build the dialog. | |
| 123 GtkWidget* dialog = gtk_dialog_new_with_buttons( | |
| 124 l10n_util::GetStringUTF8(IDS_ABOUT_CHROME_TITLE).c_str(), | |
| 125 parent, | |
| 126 GTK_DIALOG_MODAL, | |
| 127 NULL); | |
| 128 // Pick up the style set in gtk_util.cc:InitRCStyles(). | |
| 129 // The layout of this dialog is special because the logo should be flush | |
| 130 // with the edges of the window. | |
| 131 gtk_widget_set_name(dialog, "about-dialog"); | |
| 132 gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); | |
| 133 | |
| 134 GtkWidget* close_button = gtk_dialog_add_button(GTK_DIALOG(dialog), | |
| 135 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE); | |
| 136 | |
| 137 GtkWidget* content_area = GTK_DIALOG(dialog)->vbox; | |
| 138 | |
| 139 // Use an event box to get the background painting correctly | |
| 140 GtkWidget* ebox = gtk_event_box_new(); | |
| 141 gtk_widget_set_app_paintable(ebox, TRUE); | |
| 142 g_signal_connect(ebox, "expose-event", G_CALLBACK(OnEventBoxExpose), NULL); | |
| 143 | |
| 144 GtkWidget* hbox = gtk_hbox_new(FALSE, 0); | |
| 145 | |
| 146 GtkWidget* text_alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); | |
| 147 gtk_alignment_set_padding(GTK_ALIGNMENT(text_alignment), | |
| 148 kPanelVertMargin, kPanelVertMargin, | |
| 149 kPanelHorizMargin, kPanelHorizMargin); | |
| 150 | |
| 151 GtkWidget* text_vbox = gtk_vbox_new(FALSE, kExtraLineSpacing); | |
| 152 | |
| 153 GdkColor black = gtk_util::kGdkBlack; | |
| 154 GtkWidget* product_label = MakeMarkupLabel( | |
| 155 "<span font_desc=\"18\" style=\"normal\">%s</span>", | |
| 156 l10n_util::GetStringUTF8(IDS_PRODUCT_NAME)); | |
| 157 gtk_widget_modify_fg(product_label, GTK_STATE_NORMAL, &black); | |
| 158 gtk_box_pack_start(GTK_BOX(text_vbox), product_label, FALSE, FALSE, 0); | |
| 159 | |
| 160 GtkWidget* version_label = gtk_label_new(current_version.c_str()); | |
| 161 gtk_misc_set_alignment(GTK_MISC(version_label), 0.0, 0.5); | |
| 162 gtk_label_set_selectable(GTK_LABEL(version_label), TRUE); | |
| 163 gtk_widget_modify_fg(version_label, GTK_STATE_NORMAL, &black); | |
| 164 gtk_box_pack_start(GTK_BOX(text_vbox), version_label, FALSE, FALSE, 0); | |
| 165 | |
| 166 gtk_container_add(GTK_CONTAINER(text_alignment), text_vbox); | |
| 167 gtk_box_pack_start(GTK_BOX(hbox), text_alignment, TRUE, TRUE, 0); | |
| 168 | |
| 169 GtkWidget* image_vbox = gtk_vbox_new(FALSE, 0); | |
| 170 gtk_box_pack_end(GTK_BOX(image_vbox), | |
| 171 gtk_image_new_from_pixbuf(background), | |
| 172 FALSE, FALSE, 0); | |
| 173 | |
| 174 gtk_box_pack_start(GTK_BOX(hbox), image_vbox, FALSE, FALSE, 0); | |
| 175 gtk_container_add(GTK_CONTAINER(ebox), hbox); | |
| 176 gtk_box_pack_start(GTK_BOX(content_area), ebox, TRUE, TRUE, 0); | |
| 177 | |
| 178 // We use a separate box for the licensing etc. text. See the comment near | |
| 179 // the top of this function about using a special layout for this dialog. | |
| 180 GtkWidget* vbox = gtk_vbox_new(FALSE, 0); | |
| 181 | |
| 182 GtkWidget* copyright_label = gtk_label_new( | |
| 183 l10n_util::GetStringUTF8(IDS_ABOUT_VERSION_COPYRIGHT).c_str()); | |
| 184 gtk_misc_set_alignment(GTK_MISC(copyright_label), 0.0, 0.5); | |
| 185 gtk_box_pack_start(GTK_BOX(vbox), copyright_label, FALSE, FALSE, 5); | |
| 186 | |
| 187 std::string license = l10n_util::GetStringUTF8(IDS_ABOUT_VERSION_LICENSE); | |
| 188 bool chromium_url_appears_first = | |
| 189 license.find(kBeginLinkChr) < license.find(kBeginLinkOss); | |
| 190 size_t link1 = license.find(kBeginLink); | |
| 191 DCHECK(link1 != std::string::npos); | |
| 192 size_t link1_end = license.find(kEndLink, link1); | |
| 193 DCHECK(link1_end != std::string::npos); | |
| 194 size_t link2 = license.find(kBeginLink, link1_end); | |
| 195 DCHECK(link2 != std::string::npos); | |
| 196 size_t link2_end = license.find(kEndLink, link2); | |
| 197 DCHECK(link1_end != std::string::npos); | |
| 198 | |
| 199 GtkWidget* license_chunk1 = gtk_label_new(license.substr(0, link1).c_str()); | |
| 200 gtk_misc_set_alignment(GTK_MISC(license_chunk1), 0.0, 0.5); | |
| 201 GtkWidget* license_chunk2 = gtk_label_new( | |
| 202 license.substr(link1_end + strlen(kEndLinkOss), | |
| 203 link2 - link1_end - strlen(kEndLinkOss)).c_str()); | |
| 204 gtk_misc_set_alignment(GTK_MISC(license_chunk2), 0.0, 0.5); | |
| 205 GtkWidget* license_chunk3 = gtk_label_new( | |
| 206 license.substr(link2_end + strlen(kEndLinkOss)).c_str()); | |
| 207 gtk_misc_set_alignment(GTK_MISC(license_chunk3), 0.0, 0.5); | |
| 208 | |
| 209 std::string first_link_text = | |
| 210 license.substr(link1 + strlen(kBeginLinkOss), | |
| 211 link1_end - link1 - strlen(kBeginLinkOss)); | |
| 212 std::string second_link_text = | |
| 213 license.substr(link2 + strlen(kBeginLinkOss), | |
| 214 link2_end - link2 - strlen(kBeginLinkOss)); | |
| 215 | |
| 216 GtkWidget* first_link = gtk_chrome_link_button_new(first_link_text.c_str()); | |
| 217 GtkWidget* second_link = gtk_chrome_link_button_new(second_link_text.c_str()); | |
| 218 if (!chromium_url_appears_first) { | |
| 219 GtkWidget* swap = second_link; | |
| 220 second_link = first_link; | |
| 221 first_link = swap; | |
| 222 } | |
| 223 | |
| 224 g_signal_connect(chromium_url_appears_first ? first_link : second_link, | |
| 225 "clicked", G_CALLBACK(OnLinkButtonClick), | |
| 226 const_cast<char*>(GetChromiumUrl())); | |
| 227 g_signal_connect(chromium_url_appears_first ? second_link : first_link, | |
| 228 "clicked", G_CALLBACK(OnLinkButtonClick), | |
| 229 const_cast<char*>(chrome::kAboutCreditsURL)); | |
| 230 | |
| 231 GtkWidget* license_hbox = gtk_hbox_new(FALSE, 0); | |
| 232 gtk_box_pack_start(GTK_BOX(license_hbox), license_chunk1, | |
| 233 FALSE, FALSE, 0); | |
| 234 gtk_box_pack_start(GTK_BOX(license_hbox), first_link, | |
| 235 FALSE, FALSE, 0); | |
| 236 gtk_box_pack_start(GTK_BOX(license_hbox), license_chunk2, | |
| 237 FALSE, FALSE, 0); | |
| 238 | |
| 239 // Since there's no good way to dynamically wrap the license block, force | |
| 240 // a line break right before the second link (which matches en-US Windows | |
| 241 // chromium). | |
| 242 GtkWidget* license_hbox2 = gtk_hbox_new(FALSE, 0); | |
| 243 gtk_box_pack_start(GTK_BOX(license_hbox2), second_link, | |
| 244 FALSE, FALSE, 0); | |
| 245 gtk_box_pack_start(GTK_BOX(license_hbox2), license_chunk3, | |
| 246 FALSE, FALSE, 0); | |
| 247 | |
| 248 GtkWidget* license_vbox = gtk_vbox_new(FALSE, 0); | |
| 249 gtk_box_pack_start(GTK_BOX(license_vbox), license_hbox, FALSE, FALSE, 0); | |
| 250 gtk_box_pack_start(GTK_BOX(license_vbox), license_hbox2, FALSE, FALSE, 0); | |
| 251 gtk_box_pack_start(GTK_BOX(vbox), license_vbox, FALSE, FALSE, 0); | |
| 252 | |
| 253 #if defined(GOOGLE_CHROME_BUILD) | |
| 254 // Spacing line. | |
| 255 gtk_box_pack_start(GTK_BOX(vbox), gtk_label_new(""), FALSE, FALSE, 0); | |
| 256 | |
| 257 std::vector<size_t> url_offsets; | |
| 258 string16 text = l10n_util::GetStringFUTF16(IDS_ABOUT_TERMS_OF_SERVICE, | |
| 259 string16(), | |
| 260 string16(), | |
| 261 &url_offsets); | |
| 262 | |
| 263 GtkWidget* tos_chunk1 = gtk_label_new( | |
| 264 UTF16ToUTF8(text.substr(0, url_offsets[0])).c_str()); | |
| 265 gtk_misc_set_alignment(GTK_MISC(tos_chunk1), 0.0, 0.5); | |
| 266 GtkWidget* tos_link = gtk_chrome_link_button_new( | |
| 267 l10n_util::GetStringUTF8(IDS_TERMS_OF_SERVICE).c_str()); | |
| 268 GtkWidget* tos_chunk2 = gtk_label_new( | |
| 269 UTF16ToUTF8(text.substr(url_offsets[0])).c_str()); | |
| 270 gtk_misc_set_alignment(GTK_MISC(tos_chunk2), 0.0, 0.5); | |
| 271 | |
| 272 GtkWidget* tos_hbox = gtk_hbox_new(FALSE, 0); | |
| 273 gtk_box_pack_start(GTK_BOX(tos_hbox), tos_chunk1, FALSE, FALSE, 0); | |
| 274 gtk_box_pack_start(GTK_BOX(tos_hbox), tos_link, FALSE, FALSE, 0); | |
| 275 gtk_box_pack_start(GTK_BOX(tos_hbox), tos_chunk2, FALSE, FALSE, 0); | |
| 276 | |
| 277 g_signal_connect(tos_link, "clicked", G_CALLBACK(OnLinkButtonClick), | |
| 278 const_cast<char*>(chrome::kAboutTermsURL)); | |
| 279 gtk_box_pack_start(GTK_BOX(vbox), tos_hbox, TRUE, TRUE, 0); | |
| 280 #endif | |
| 281 | |
| 282 GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); | |
| 283 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), | |
| 284 gtk_util::kContentAreaBorder, 0, | |
| 285 gtk_util::kContentAreaBorder, gtk_util::kContentAreaBorder); | |
| 286 gtk_container_add(GTK_CONTAINER(alignment), vbox); | |
| 287 gtk_box_pack_start(GTK_BOX(content_area), alignment, FALSE, FALSE, 0); | |
| 288 | |
| 289 g_signal_connect(dialog, "response", G_CALLBACK(OnDialogResponse), NULL); | |
| 290 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); | |
| 291 gtk_widget_show_all(dialog); | |
| 292 gtk_widget_grab_focus(close_button); | |
| 293 } | |
| OLD | NEW |