Home | History | Annotate | Download | only in gtk
      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/js_modal_dialog_gtk.h"
      6 
      7 #include <gtk/gtk.h>
      8 
      9 #include "base/logging.h"
     10 #include "base/utf_string_conversions.h"
     11 #include "chrome/browser/ui/app_modal_dialogs/js_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/message_box_flags.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 std::wstring GetPromptText(GtkDialog* dialog) {
     28   GtkWidget* widget = static_cast<GtkWidget*>(
     29       g_object_get_data(G_OBJECT(dialog), kPromptTextId));
     30   if (widget)
     31     return UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(widget)));
     32   return std::wstring();
     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 // JSModalDialogGtk, public:
     49 
     50 JSModalDialogGtk::JSModalDialogGtk(JavaScriptAppModalDialog* dialog,
     51                                    gfx::NativeWindow parent_window)
     52     : dialog_(dialog) {
     53   GtkButtonsType buttons = GTK_BUTTONS_NONE;
     54   GtkMessageType message_type = GTK_MESSAGE_OTHER;
     55 
     56   // We add in the OK button manually later because we want to focus it
     57   // explicitly.
     58   switch (dialog_->dialog_flags()) {
     59     case ui::MessageBoxFlags::kIsJavascriptAlert:
     60       buttons = GTK_BUTTONS_NONE;
     61       message_type = GTK_MESSAGE_WARNING;
     62       break;
     63 
     64     case ui::MessageBoxFlags::kIsJavascriptConfirm:
     65       if (dialog_->is_before_unload_dialog()) {
     66         // onbeforeunload also uses a confirm prompt, it just has custom
     67         // buttons.  We add the buttons using gtk_dialog_add_button below.
     68         buttons = GTK_BUTTONS_NONE;
     69       } else {
     70         buttons = GTK_BUTTONS_CANCEL;
     71       }
     72       message_type = GTK_MESSAGE_QUESTION;
     73       break;
     74 
     75     case ui::MessageBoxFlags::kIsJavascriptPrompt:
     76       buttons = GTK_BUTTONS_CANCEL;
     77       message_type = GTK_MESSAGE_QUESTION;
     78       break;
     79 
     80     default:
     81       NOTREACHED();
     82   }
     83 
     84   // We want the alert to be app modal so put all the browser windows into the
     85   // same window group.
     86   gtk_util::MakeAppModalWindowGroup();
     87 
     88   gtk_dialog_ = gtk_message_dialog_new(parent_window,
     89       GTK_DIALOG_MODAL, message_type, buttons, "%s",
     90       WideToUTF8(dialog_->message_text()).c_str());
     91   gtk_util::ApplyMessageDialogQuirks(gtk_dialog_);
     92   gtk_window_set_title(GTK_WINDOW(gtk_dialog_),
     93                        WideToUTF8(dialog_->title()).c_str());
     94 
     95   // Adjust content area as needed.  Set up the prompt text entry or
     96   // suppression check box.
     97   if (ui::MessageBoxFlags::kIsJavascriptPrompt == dialog_->dialog_flags()) {
     98     // TODO(tc): Replace with gtk_dialog_get_content_area() when using GTK 2.14+
     99     GtkWidget* contents_vbox = GTK_DIALOG(gtk_dialog_)->vbox;
    100     GtkWidget* text_box = gtk_entry_new();
    101     gtk_entry_set_text(GTK_ENTRY(text_box),
    102         WideToUTF8(dialog_->default_prompt_text()).c_str());
    103     gtk_box_pack_start(GTK_BOX(contents_vbox), text_box, TRUE, TRUE, 0);
    104     g_object_set_data(G_OBJECT(gtk_dialog_), kPromptTextId, text_box);
    105     gtk_entry_set_activates_default(GTK_ENTRY(text_box), TRUE);
    106   }
    107 
    108   if (dialog_->display_suppress_checkbox()) {
    109     GtkWidget* contents_vbox = GTK_DIALOG(gtk_dialog_)->vbox;
    110     GtkWidget* check_box = gtk_check_button_new_with_label(
    111         l10n_util::GetStringUTF8(
    112         IDS_JAVASCRIPT_MESSAGEBOX_SUPPRESS_OPTION).c_str());
    113     gtk_box_pack_start(GTK_BOX(contents_vbox), check_box, TRUE, TRUE, 0);
    114     g_object_set_data(G_OBJECT(gtk_dialog_), kSuppressCheckboxId, check_box);
    115   }
    116 
    117   // Adjust buttons/action area as needed.
    118   if (dialog_->is_before_unload_dialog()) {
    119     std::string button_text = l10n_util::GetStringUTF8(
    120       IDS_BEFOREUNLOAD_MESSAGEBOX_OK_BUTTON_LABEL);
    121     gtk_dialog_add_button(GTK_DIALOG(gtk_dialog_), button_text.c_str(),
    122         GTK_RESPONSE_OK);
    123 
    124     button_text = l10n_util::GetStringUTF8(
    125         IDS_BEFOREUNLOAD_MESSAGEBOX_CANCEL_BUTTON_LABEL);
    126     gtk_dialog_add_button(GTK_DIALOG(gtk_dialog_), button_text.c_str(),
    127         GTK_RESPONSE_CANCEL);
    128   } else {
    129     // Add the OK button and focus it.
    130     GtkWidget* ok_button = gtk_dialog_add_button(GTK_DIALOG(gtk_dialog_),
    131         GTK_STOCK_OK, GTK_RESPONSE_OK);
    132     if (ui::MessageBoxFlags::kIsJavascriptPrompt != dialog_->dialog_flags())
    133       gtk_widget_grab_focus(ok_button);
    134   }
    135 
    136   gtk_dialog_set_default_response(GTK_DIALOG(gtk_dialog_), GTK_RESPONSE_OK);
    137   g_signal_connect(gtk_dialog_, "response", G_CALLBACK(OnResponseThunk), this);
    138 }
    139 
    140 JSModalDialogGtk::~JSModalDialogGtk() {
    141 }
    142 
    143 ////////////////////////////////////////////////////////////////////////////////
    144 // JSModalDialogGtk, NativeAppModalDialog implementation:
    145 
    146 int JSModalDialogGtk::GetAppModalDialogButtons() const {
    147   switch (dialog_->dialog_flags()) {
    148     case ui::MessageBoxFlags::kIsJavascriptAlert:
    149       return ui::MessageBoxFlags::DIALOGBUTTON_OK;
    150 
    151     case ui::MessageBoxFlags::kIsJavascriptConfirm:
    152       return ui::MessageBoxFlags::DIALOGBUTTON_OK |
    153         ui::MessageBoxFlags::DIALOGBUTTON_CANCEL;
    154 
    155     case ui::MessageBoxFlags::kIsJavascriptPrompt:
    156       return ui::MessageBoxFlags::DIALOGBUTTON_OK;
    157 
    158     default:
    159       NOTREACHED();
    160       return 0;
    161   }
    162 }
    163 
    164 void JSModalDialogGtk::ShowAppModalDialog() {
    165   gtk_util::ShowDialogWithMinLocalizedWidth(GTK_WIDGET(gtk_dialog_),
    166       IDS_ALERT_DIALOG_WIDTH_CHARS);
    167 }
    168 
    169 void JSModalDialogGtk::ActivateAppModalDialog() {
    170   DCHECK(gtk_dialog_);
    171   gtk_window_present(GTK_WINDOW(gtk_dialog_));}
    172 
    173 void JSModalDialogGtk::CloseAppModalDialog() {
    174   DCHECK(gtk_dialog_);
    175   OnResponse(gtk_dialog_, GTK_RESPONSE_DELETE_EVENT);
    176 }
    177 
    178 void JSModalDialogGtk::AcceptAppModalDialog() {
    179   OnResponse(gtk_dialog_, GTK_RESPONSE_OK);
    180 }
    181 
    182 void JSModalDialogGtk::CancelAppModalDialog() {
    183   OnResponse(gtk_dialog_, GTK_RESPONSE_CANCEL);
    184 }
    185 
    186 ////////////////////////////////////////////////////////////////////////////////
    187 // JSModalDialogGtk, private:
    188 
    189 void JSModalDialogGtk::OnResponse(GtkWidget* dialog, int response_id) {
    190   switch (response_id) {
    191     case GTK_RESPONSE_OK:
    192       // The first arg is the prompt text and the second is true if we want to
    193       // suppress additional popups from the page.
    194       dialog_->OnAccept(GetPromptText(GTK_DIALOG(dialog)),
    195                         ShouldSuppressJSDialogs(GTK_DIALOG(dialog)));
    196       break;
    197 
    198     case GTK_RESPONSE_CANCEL:
    199     case GTK_RESPONSE_DELETE_EVENT:   // User hit the X on the dialog.
    200       dialog_->OnCancel(ShouldSuppressJSDialogs(GTK_DIALOG(dialog)));
    201       break;
    202 
    203     default:
    204       NOTREACHED();
    205   }
    206   gtk_widget_destroy(dialog);
    207 
    208   // Now that the dialog is gone, we can put all the  windows into separate
    209   // window groups so other dialogs are no longer app modal.
    210   gtk_util::AppModalDismissedUngroupWindows();
    211   delete this;
    212 }
    213 
    214 ////////////////////////////////////////////////////////////////////////////////
    215 // NativeAppModalDialog, public:
    216 
    217 // static
    218 NativeAppModalDialog* NativeAppModalDialog::CreateNativeJavaScriptPrompt(
    219     JavaScriptAppModalDialog* dialog,
    220     gfx::NativeWindow parent_window) {
    221   return new JSModalDialogGtk(dialog, parent_window);
    222 }
    223