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/javascript_app_modal_dialog_gtk.h" 6 7 #include <gtk/gtk.h> 8 9 #include "base/logging.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.h" 12 #include "chrome/browser/ui/gtk/gtk_util.h" 13 #include "grit/generated_resources.h" 14 #include "grit/locale_settings.h" 15 #include "ui/base/l10n/l10n_util.h" 16 #include "ui/base/ui_base_types.h" 17 18 namespace { 19 20 // We stash pointers to widgets on the gtk_dialog so we can refer to them 21 // after dialog creation. 22 const char kPromptTextId[] = "chrome_prompt_text"; 23 const char kSuppressCheckboxId[] = "chrome_suppress_checkbox"; 24 25 // If there's a text entry in the dialog, get the text from the first one and 26 // return it. 27 string16 GetPromptText(GtkDialog* dialog) { 28 GtkWidget* widget = static_cast<GtkWidget*>( 29 g_object_get_data(G_OBJECT(dialog), kPromptTextId)); 30 if (widget) 31 return UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(widget))); 32 return string16(); 33 } 34 35 // If there's a toggle button in the dialog, return the toggled state. 36 // Otherwise, return false. 37 bool ShouldSuppressJSDialogs(GtkDialog* dialog) { 38 GtkWidget* widget = static_cast<GtkWidget*>( 39 g_object_get_data(G_OBJECT(dialog), kSuppressCheckboxId)); 40 if (widget) 41 return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); 42 return false; 43 } 44 45 } // namespace 46 47 //////////////////////////////////////////////////////////////////////////////// 48 // JavaScriptAppModalDialogGtk, public: 49 50 JavaScriptAppModalDialogGtk::JavaScriptAppModalDialogGtk( 51 JavaScriptAppModalDialog* dialog, 52 gfx::NativeWindow parent_window) 53 : dialog_(dialog) { 54 GtkButtonsType buttons = GTK_BUTTONS_NONE; 55 GtkMessageType message_type = GTK_MESSAGE_OTHER; 56 57 // We add in the OK button manually later because we want to focus it 58 // explicitly. 59 switch (dialog_->javascript_message_type()) { 60 case content::JAVASCRIPT_MESSAGE_TYPE_ALERT: 61 buttons = GTK_BUTTONS_NONE; 62 message_type = GTK_MESSAGE_WARNING; 63 break; 64 65 case content::JAVASCRIPT_MESSAGE_TYPE_CONFIRM: 66 if (dialog_->is_before_unload_dialog()) { 67 // onbeforeunload also uses a confirm prompt, it just has custom 68 // buttons. We add the buttons using gtk_dialog_add_button below. 69 buttons = GTK_BUTTONS_NONE; 70 } else { 71 buttons = GTK_BUTTONS_CANCEL; 72 } 73 message_type = GTK_MESSAGE_QUESTION; 74 break; 75 76 case content::JAVASCRIPT_MESSAGE_TYPE_PROMPT: 77 buttons = GTK_BUTTONS_CANCEL; 78 message_type = GTK_MESSAGE_QUESTION; 79 break; 80 81 default: 82 NOTREACHED(); 83 } 84 85 // We want the alert to be app modal so put all the browser windows into the 86 // same window group. 87 gtk_util::MakeAppModalWindowGroup(); 88 89 gtk_dialog_ = gtk_message_dialog_new(parent_window, 90 GTK_DIALOG_MODAL, message_type, buttons, "%s", 91 UTF16ToUTF8(dialog_->message_text()).c_str()); 92 g_signal_connect(gtk_dialog_, "delete-event", 93 G_CALLBACK(gtk_widget_hide_on_delete), NULL); 94 gtk_util::ApplyMessageDialogQuirks(gtk_dialog_); 95 gtk_window_set_title(GTK_WINDOW(gtk_dialog_), 96 UTF16ToUTF8(dialog_->title()).c_str()); 97 98 // Adjust content area as needed. Set up the prompt text entry or 99 // suppression check box. 100 if (dialog_->javascript_message_type() == 101 content::JAVASCRIPT_MESSAGE_TYPE_PROMPT) { 102 GtkWidget* content_area = 103 gtk_dialog_get_content_area(GTK_DIALOG(gtk_dialog_)); 104 GtkWidget* text_box = gtk_entry_new(); 105 gtk_entry_set_text(GTK_ENTRY(text_box), 106 UTF16ToUTF8(dialog_->default_prompt_text()).c_str()); 107 gtk_box_pack_start(GTK_BOX(content_area), text_box, TRUE, TRUE, 0); 108 g_object_set_data(G_OBJECT(gtk_dialog_), kPromptTextId, text_box); 109 gtk_entry_set_activates_default(GTK_ENTRY(text_box), TRUE); 110 } 111 112 if (dialog_->display_suppress_checkbox()) { 113 GtkWidget* content_area = 114 gtk_dialog_get_content_area(GTK_DIALOG(gtk_dialog_)); 115 GtkWidget* check_box = gtk_check_button_new_with_label( 116 l10n_util::GetStringUTF8( 117 IDS_JAVASCRIPT_MESSAGEBOX_SUPPRESS_OPTION).c_str()); 118 gtk_box_pack_start(GTK_BOX(content_area), check_box, TRUE, TRUE, 0); 119 g_object_set_data(G_OBJECT(gtk_dialog_), kSuppressCheckboxId, check_box); 120 } 121 122 // Adjust buttons/action area as needed. 123 if (dialog_->is_before_unload_dialog()) { 124 std::string button_text = l10n_util::GetStringUTF8( 125 dialog_->is_reload() ? 126 IDS_BEFORERELOAD_MESSAGEBOX_OK_BUTTON_LABEL : 127 IDS_BEFOREUNLOAD_MESSAGEBOX_OK_BUTTON_LABEL); 128 gtk_dialog_add_button(GTK_DIALOG(gtk_dialog_), button_text.c_str(), 129 GTK_RESPONSE_OK); 130 131 button_text = l10n_util::GetStringUTF8( 132 dialog_->is_reload() ? 133 IDS_BEFORERELOAD_MESSAGEBOX_CANCEL_BUTTON_LABEL : 134 IDS_BEFOREUNLOAD_MESSAGEBOX_CANCEL_BUTTON_LABEL); 135 gtk_dialog_add_button(GTK_DIALOG(gtk_dialog_), button_text.c_str(), 136 GTK_RESPONSE_CANCEL); 137 } else { 138 // Add the OK button and focus it. 139 GtkWidget* ok_button = gtk_dialog_add_button(GTK_DIALOG(gtk_dialog_), 140 GTK_STOCK_OK, GTK_RESPONSE_OK); 141 if (dialog_->javascript_message_type() != 142 content::JAVASCRIPT_MESSAGE_TYPE_PROMPT) 143 gtk_widget_grab_focus(ok_button); 144 } 145 146 gtk_dialog_set_default_response(GTK_DIALOG(gtk_dialog_), GTK_RESPONSE_OK); 147 g_signal_connect(gtk_dialog_, "response", G_CALLBACK(OnResponseThunk), this); 148 } 149 150 JavaScriptAppModalDialogGtk::~JavaScriptAppModalDialogGtk() { 151 } 152 153 //////////////////////////////////////////////////////////////////////////////// 154 // JavaScriptAppModalDialogGtk, NativeAppModalDialog implementation: 155 156 int JavaScriptAppModalDialogGtk::GetAppModalDialogButtons() const { 157 switch (dialog_->javascript_message_type()) { 158 case content::JAVASCRIPT_MESSAGE_TYPE_ALERT: 159 return ui::DIALOG_BUTTON_OK; 160 161 case content::JAVASCRIPT_MESSAGE_TYPE_CONFIRM: 162 return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL; 163 164 case content::JAVASCRIPT_MESSAGE_TYPE_PROMPT: 165 return ui::DIALOG_BUTTON_OK; 166 167 default: 168 NOTREACHED(); 169 return 0; 170 } 171 } 172 173 void JavaScriptAppModalDialogGtk::ShowAppModalDialog() { 174 gtk_util::ShowDialogWithMinLocalizedWidth(GTK_WIDGET(gtk_dialog_), 175 IDS_ALERT_DIALOG_WIDTH_CHARS); 176 } 177 178 void JavaScriptAppModalDialogGtk::ActivateAppModalDialog() { 179 DCHECK(gtk_dialog_); 180 gtk_window_present(GTK_WINDOW(gtk_dialog_)); 181 } 182 183 void JavaScriptAppModalDialogGtk::CloseAppModalDialog() { 184 DCHECK(gtk_dialog_); 185 OnResponse(gtk_dialog_, GTK_RESPONSE_DELETE_EVENT); 186 } 187 188 void JavaScriptAppModalDialogGtk::AcceptAppModalDialog() { 189 OnResponse(gtk_dialog_, GTK_RESPONSE_OK); 190 } 191 192 void JavaScriptAppModalDialogGtk::CancelAppModalDialog() { 193 OnResponse(gtk_dialog_, GTK_RESPONSE_CANCEL); 194 } 195 196 //////////////////////////////////////////////////////////////////////////////// 197 // JavaScriptAppModalDialogGtk, private: 198 199 void JavaScriptAppModalDialogGtk::OnResponse(GtkWidget* dialog, 200 int response_id) { 201 switch (response_id) { 202 case GTK_RESPONSE_OK: 203 // The first arg is the prompt text and the second is true if we want to 204 // suppress additional popups from the page. 205 dialog_->OnAccept(GetPromptText(GTK_DIALOG(dialog)), 206 ShouldSuppressJSDialogs(GTK_DIALOG(dialog))); 207 break; 208 209 case GTK_RESPONSE_CANCEL: 210 case GTK_RESPONSE_DELETE_EVENT: // User hit the X on the dialog. 211 dialog_->OnCancel(ShouldSuppressJSDialogs(GTK_DIALOG(dialog))); 212 break; 213 214 default: 215 NOTREACHED(); 216 } 217 gtk_widget_destroy(dialog); 218 219 // Now that the dialog is gone, we can put all the windows into separate 220 // window groups so other dialogs are no longer app modal. 221 gtk_util::AppModalDismissedUngroupWindows(); 222 delete this; 223 } 224 225 //////////////////////////////////////////////////////////////////////////////// 226 // NativeAppModalDialog, public: 227 228 // static 229 NativeAppModalDialog* NativeAppModalDialog::CreateNativeJavaScriptPrompt( 230 JavaScriptAppModalDialog* dialog, 231 gfx::NativeWindow parent_window) { 232 return new JavaScriptAppModalDialogGtk(dialog, parent_window); 233 } 234