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/input_window_dialog.h" 6 7 #include <gtk/gtk.h> 8 9 #include "base/memory/scoped_ptr.h" 10 #include "base/message_loop.h" 11 #include "base/string_piece.h" 12 #include "base/utf_string_conversions.h" 13 #include "chrome/browser/ui/gtk/gtk_util.h" 14 #include "ui/base/gtk/gtk_signal.h" 15 16 class InputWindowDialogGtk : public InputWindowDialog { 17 public: 18 // Creates a dialog. Takes ownership of |delegate|. 19 InputWindowDialogGtk(GtkWindow* parent, 20 const std::string& window_title, 21 const std::string& label, 22 const std::string& contents, 23 Delegate* delegate); 24 virtual ~InputWindowDialogGtk(); 25 26 virtual void Show(); 27 virtual void Close(); 28 29 private: 30 CHROMEG_CALLBACK_0(InputWindowDialogGtk, void, OnEntryChanged, GtkEditable*); 31 CHROMEGTK_CALLBACK_1(InputWindowDialogGtk, void, OnResponse, int); 32 CHROMEGTK_CALLBACK_1(InputWindowDialogGtk, gboolean, 33 OnWindowDeleteEvent, GdkEvent*); 34 CHROMEGTK_CALLBACK_0(InputWindowDialogGtk, void, OnWindowDestroy); 35 36 // The underlying gtk dialog window. 37 GtkWidget* dialog_; 38 39 // The GtkEntry in this form. 40 GtkWidget* input_; 41 42 // Our delegate. Consumes the window's output. 43 scoped_ptr<InputWindowDialog::Delegate> delegate_; 44 }; 45 46 47 InputWindowDialogGtk::InputWindowDialogGtk(GtkWindow* parent, 48 const std::string& window_title, 49 const std::string& label, 50 const std::string& contents, 51 Delegate* delegate) 52 : dialog_(gtk_dialog_new_with_buttons( 53 window_title.c_str(), 54 parent, 55 GTK_DIALOG_MODAL, 56 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, 57 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, 58 NULL)), 59 delegate_(delegate) { 60 gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_ACCEPT); 61 gtk_dialog_set_has_separator(GTK_DIALOG(dialog_), FALSE); 62 gtk_window_set_resizable(GTK_WINDOW(dialog_), FALSE); 63 64 GtkWidget* content_area = GTK_DIALOG(dialog_)->vbox; 65 gtk_box_set_spacing(GTK_BOX(content_area), 18); 66 67 GtkWidget* hbox = gtk_hbox_new(FALSE, 6); 68 GtkWidget* label_widget = gtk_label_new(label.c_str()); 69 gtk_box_pack_start(GTK_BOX(hbox), label_widget, FALSE, FALSE, 0); 70 71 input_ = gtk_entry_new(); 72 gtk_entry_set_text(GTK_ENTRY(input_), contents.c_str()); 73 g_signal_connect(input_, "changed", 74 G_CALLBACK(OnEntryChangedThunk), this); 75 g_object_set(G_OBJECT(input_), "activates-default", TRUE, NULL); 76 gtk_box_pack_start(GTK_BOX(hbox), input_, TRUE, TRUE, 0); 77 78 gtk_widget_show_all(hbox); 79 80 gtk_box_pack_start(GTK_BOX(content_area), hbox, FALSE, FALSE, 0); 81 82 g_signal_connect(dialog_, "response", 83 G_CALLBACK(OnResponseThunk), this); 84 g_signal_connect(dialog_, "delete-event", 85 G_CALLBACK(OnWindowDeleteEventThunk), this); 86 g_signal_connect(dialog_, "destroy", 87 G_CALLBACK(OnWindowDestroyThunk), this); 88 } 89 90 InputWindowDialogGtk::~InputWindowDialogGtk() { 91 } 92 93 void InputWindowDialogGtk::Show() { 94 gtk_util::ShowDialog(dialog_); 95 } 96 97 void InputWindowDialogGtk::Close() { 98 // Under the model that we've inherited from Windows, dialogs can receive 99 // more than one Close() call inside the current message loop event. 100 if (dialog_) { 101 gtk_widget_destroy(dialog_); 102 dialog_ = NULL; 103 } 104 } 105 106 void InputWindowDialogGtk::OnEntryChanged(GtkEditable* entry) { 107 std::wstring value(UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(entry)))); 108 gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog_), 109 GTK_RESPONSE_ACCEPT, 110 delegate_->IsValid(value)); 111 } 112 113 void InputWindowDialogGtk::OnResponse(GtkWidget* dialog, int response_id) { 114 if (response_id == GTK_RESPONSE_ACCEPT) { 115 std::wstring value(UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(input_)))); 116 delegate_->InputAccepted(value); 117 } else { 118 delegate_->InputCanceled(); 119 } 120 Close(); 121 } 122 123 gboolean InputWindowDialogGtk::OnWindowDeleteEvent(GtkWidget* widget, 124 GdkEvent* event) { 125 Close(); 126 127 // Return true to prevent the gtk dialog from being destroyed. Close will 128 // destroy it for us and the default gtk_dialog_delete_event_handler() will 129 // force the destruction without us being able to stop it. 130 return TRUE; 131 } 132 133 void InputWindowDialogGtk::OnWindowDestroy(GtkWidget* widget) { 134 MessageLoop::current()->DeleteSoon(FROM_HERE, this); 135 } 136 137 InputWindowDialog* InputWindowDialog::Create(gfx::NativeWindow parent, 138 const std::wstring& window_title, 139 const std::wstring& label, 140 const std::wstring& contents, 141 Delegate* delegate) { 142 return new InputWindowDialogGtk(parent, 143 WideToUTF8(window_title), 144 WideToUTF8(label), 145 WideToUTF8(contents), 146 delegate); 147 } 148