1 // Copyright (c) 2011 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/external_protocol_dialog_gtk.h" 6 7 #include <gtk/gtk.h> 8 9 #include <string> 10 11 #include "base/message_loop.h" 12 #include "base/metrics/histogram.h" 13 #include "base/string_util.h" 14 #include "base/utf_string_conversions.h" 15 #include "chrome/browser/external_protocol_handler.h" 16 #include "chrome/browser/tab_contents/tab_util.h" 17 #include "chrome/browser/ui/gtk/gtk_util.h" 18 #include "grit/chromium_strings.h" 19 #include "grit/generated_resources.h" 20 #include "ui/base/l10n/l10n_util.h" 21 #include "ui/base/text/text_elider.h" 22 23 namespace { 24 25 const int kMessageWidth = 400; 26 27 } // namespace 28 29 /////////////////////////////////////////////////////////////////////////////// 30 // ExternalProtocolHandler 31 32 // static 33 void ExternalProtocolHandler::RunExternalProtocolDialog( 34 const GURL& url, int render_process_host_id, int routing_id) { 35 new ExternalProtocolDialogGtk(url); 36 } 37 38 /////////////////////////////////////////////////////////////////////////////// 39 // ExternalProtocolDialogGtk 40 41 ExternalProtocolDialogGtk::ExternalProtocolDialogGtk(const GURL& url) 42 : url_(url), 43 creation_time_(base::TimeTicks::Now()) { 44 DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type()); 45 46 dialog_ = gtk_dialog_new_with_buttons( 47 l10n_util::GetStringUTF8(IDS_EXTERNAL_PROTOCOL_TITLE).c_str(), 48 NULL, 49 GTK_DIALOG_NO_SEPARATOR, 50 NULL); 51 52 // Add the response buttons. 53 gtk_util::AddButtonToDialog(dialog_, 54 l10n_util::GetStringUTF8( 55 IDS_EXTERNAL_PROTOCOL_CANCEL_BUTTON_TEXT).c_str(), 56 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT); 57 gtk_util::AddButtonToDialog(dialog_, 58 l10n_util::GetStringUTF8(IDS_EXTERNAL_PROTOCOL_OK_BUTTON_TEXT).c_str(), 59 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); 60 61 // Construct the message text. 62 const int kMaxUrlWithoutSchemeSize = 256; 63 const int kMaxCommandSize = 256; 64 string16 elided_url_without_scheme; 65 string16 elided_command; 66 ui::ElideString(ASCIIToUTF16(url.possibly_invalid_spec()), 67 kMaxUrlWithoutSchemeSize, &elided_url_without_scheme); 68 ui::ElideString(ASCIIToUTF16(std::string("xdg-open ") + url.spec()), 69 kMaxCommandSize, &elided_command); 70 71 std::string message_text = l10n_util::GetStringFUTF8( 72 IDS_EXTERNAL_PROTOCOL_INFORMATION, 73 ASCIIToUTF16(url.scheme() + ":"), 74 elided_url_without_scheme) + "\n\n"; 75 76 message_text += l10n_util::GetStringFUTF8( 77 IDS_EXTERNAL_PROTOCOL_APPLICATION_TO_LAUNCH, elided_command) + "\n\n"; 78 79 message_text += l10n_util::GetStringUTF8(IDS_EXTERNAL_PROTOCOL_WARNING); 80 81 // Create the content-holding vbox. 82 GtkWidget* vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); 83 gtk_container_set_border_width(GTK_CONTAINER(vbox), 84 gtk_util::kContentAreaBorder); 85 86 // Add the message text. 87 GtkWidget* label = gtk_label_new(message_text.c_str()); 88 gtk_util::SetLabelWidth(label, kMessageWidth); 89 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0); 90 91 // Add the checkbox. 92 checkbox_ = gtk_check_button_new_with_label( 93 l10n_util::GetStringUTF8(IDS_EXTERNAL_PROTOCOL_CHECKBOX_TEXT).c_str()); 94 gtk_box_pack_start(GTK_BOX(vbox), checkbox_, 95 FALSE, FALSE, 0); 96 97 // Add our vbox to the dialog. 98 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox), vbox, 99 FALSE, FALSE, 0); 100 101 g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this); 102 103 gtk_window_set_resizable(GTK_WINDOW(dialog_), FALSE); 104 gtk_widget_show_all(dialog_); 105 } 106 107 ExternalProtocolDialogGtk::~ExternalProtocolDialogGtk() { 108 } 109 110 void ExternalProtocolDialogGtk::OnResponse(GtkWidget* dialog, int response_id) { 111 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbox_))) { 112 if (response_id == GTK_RESPONSE_ACCEPT) { 113 ExternalProtocolHandler::SetBlockState( 114 url_.scheme(), ExternalProtocolHandler::DONT_BLOCK); 115 } else if (response_id == GTK_RESPONSE_REJECT) { 116 ExternalProtocolHandler::SetBlockState( 117 url_.scheme(), ExternalProtocolHandler::BLOCK); 118 } 119 // If the response is GTK_RESPONSE_DELETE, triggered by the user closing 120 // the dialog, do nothing. 121 } 122 123 if (response_id == GTK_RESPONSE_ACCEPT) { 124 UMA_HISTOGRAM_LONG_TIMES("clickjacking.launch_url", 125 base::TimeTicks::Now() - creation_time_); 126 127 ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(url_); 128 } 129 130 gtk_widget_destroy(dialog_); 131 delete this; 132 } 133