| Index: chrome/browser/gtk/pk11_password_dialog.cc
|
| diff --git a/chrome/browser/gtk/pk11_password_dialog.cc b/chrome/browser/gtk/pk11_password_dialog.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e9ca2cce9c0f94c6a521d669f5675e1969acd400
|
| --- /dev/null
|
| +++ b/chrome/browser/gtk/pk11_password_dialog.cc
|
| @@ -0,0 +1,231 @@
|
| +// Copyright (c) 2010 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "chrome/browser/gtk/pk11_password_dialog.h"
|
| +
|
| +#include <gtk/gtk.h>
|
| +#include <pk11pub.h>
|
| +
|
| +#include "app/gtk_signal.h"
|
| +#include "app/l10n_util.h"
|
| +#include "base/basictypes.h"
|
| +#include "base/crypto/scoped_nss_types.h"
|
| +#include "base/nss_util_internal.h"
|
| +#include "base/task.h"
|
| +#include "base/utf_string_conversions.h"
|
| +#include "base/waitable_event.h"
|
| +#include "chrome/browser/chrome_thread.h"
|
| +#include "chrome/browser/gtk/gtk_util.h"
|
| +#include "googleurl/src/gurl.h"
|
| +#include "grit/generated_resources.h"
|
| +
|
| +namespace {
|
| +
|
| +class PK11BlockingDialogDelegate : public base::PK11BlockingPasswordDelegate {
|
| + public:
|
| + PK11BlockingDialogDelegate(browser::PK11PasswordReason reason,
|
| + const GURL& url)
|
| + : event_(false, false),
|
| + reason_(reason),
|
| + url_(url),
|
| + password_(NULL) {
|
| + }
|
| +
|
| + // base::PK11BlockingDialogDelegate implementation.
|
| + virtual char* RequestPassword(PK11SlotInfo* slot, PRBool retry) {
|
| + DCHECK(!ChromeThread::CurrentlyOn(ChromeThread::UI));
|
| + DCHECK(!event_.IsSignaled());
|
| + DCHECK(password_ == NULL);
|
| + event_.Reset();
|
| + if (ChromeThread::PostTask(
|
| + ChromeThread::UI, FROM_HERE,
|
| + NewRunnableMethod(this, &PK11BlockingDialogDelegate::ShowDialog,
|
| + slot, retry != PR_FALSE))) {
|
| + event_.Wait();
|
| + }
|
| + char* password = password_;
|
| + password_ = NULL;
|
| + return password;
|
| + }
|
| +
|
| + private:
|
| + void ShowDialog(PK11SlotInfo* slot, bool retry) {
|
| + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
|
| + ShowPK11PasswordDialog(
|
| + slot, retry, reason_, url_,
|
| + NewCallback(this, &PK11BlockingDialogDelegate::GotPassword));
|
| + }
|
| + void GotPassword(const char* password) {
|
| + password_ = password ? PL_strdup(password) : NULL;
|
| + event_.Signal();
|
| + }
|
| + base::WaitableEvent event_;
|
| + browser::PK11PasswordReason reason_;
|
| + GURL url_;
|
| + char* password_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(PK11BlockingDialogDelegate);
|
| +};
|
| +
|
| +class PK11PasswordDialog {
|
| + public:
|
| + PK11PasswordDialog(PK11SlotInfo* slot,
|
| + bool retry,
|
| + browser::PK11PasswordReason reason,
|
| + const GURL& url,
|
| + browser::PK11PasswordCallback* callback);
|
| + void Show();
|
| + void Close();
|
| +
|
| + private:
|
| + CHROMEGTK_CALLBACK_1(PK11PasswordDialog, void, OnResponse, int);
|
| + CHROMEGTK_CALLBACK_1(PK11PasswordDialog, gboolean,
|
| + OnWindowDeleteEvent, GdkEvent*);
|
| + CHROMEGTK_CALLBACK_0(PK11PasswordDialog, void, OnWindowDestroy);
|
| +
|
| + base::ScopedPK11Slot slot_;
|
| + bool retry_;
|
| + browser::PK11PasswordReason reason_;
|
| + GURL url_;
|
| + scoped_ptr<browser::PK11PasswordCallback> callback_;
|
| +
|
| + GtkWidget* dialog_;
|
| + GtkWidget* password_entry_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(PK11PasswordDialog);
|
| +};
|
| +
|
| +PK11PasswordDialog::PK11PasswordDialog(PK11SlotInfo* slot,
|
| + bool retry,
|
| + browser::PK11PasswordReason reason,
|
| + const GURL& url,
|
| + browser::PK11PasswordCallback* callback)
|
| + : slot_(PK11_ReferenceSlot(slot)),
|
| + retry_(retry),
|
| + reason_(reason),
|
| + url_(url),
|
| + callback_(callback) {
|
| + dialog_ = gtk_dialog_new_with_buttons(
|
| + l10n_util::GetStringUTF8(IDS_PK11_AUTH_DIALOG_TITLE).c_str(),
|
| + NULL,
|
| + GTK_DIALOG_NO_SEPARATOR,
|
| + NULL); // Populate the buttons later, for control over the OK button.
|
| + GtkWidget* ok_button = gtk_button_new_from_stock(GTK_STOCK_OK);
|
| + gtk_button_set_label(
|
| + GTK_BUTTON(ok_button),
|
| + l10n_util::GetStringUTF8(IDS_PK11_AUTH_DIALOG_OK_BUTTON_LABEL).c_str());
|
| + gtk_dialog_add_action_widget(GTK_DIALOG(dialog_),
|
| + ok_button, GTK_RESPONSE_ACCEPT);
|
| + gtk_dialog_add_button(GTK_DIALOG(dialog_),
|
| + GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
|
| + GTK_WIDGET_SET_FLAGS(ok_button, GTK_CAN_DEFAULT);
|
| + gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_ACCEPT);
|
| +
|
| + // Select an appropriate text for the reason.
|
| + std::string text;
|
| + const string16& host = UTF8ToUTF16(url.host());
|
| + const string16& token = UTF8ToUTF16(PK11_GetTokenName(slot));
|
| + switch (reason) {
|
| + case browser::kPK11PasswordKeygen:
|
| + text = l10n_util::GetStringFUTF8(IDS_PK11_AUTH_DIALOG_TEXT_KEYGEN,
|
| + token, host);
|
| + break;
|
| + case browser::kPK11PasswordCertEnrollment:
|
| + text = l10n_util::GetStringFUTF8(IDS_PK11_AUTH_DIALOG_TEXT_CERT_IMPORT,
|
| + token, host);
|
| + break;
|
| + case browser::kPK11PasswordClientAuth:
|
| + text = l10n_util::GetStringFUTF8(IDS_PK11_AUTH_DIALOG_TEXT_CLIENT_AUTH,
|
| + token, host);
|
| + break;
|
| + default:
|
| + NOTREACHED();
|
| + }
|
| + GtkWidget* label = gtk_label_new(text.c_str());
|
| + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
|
| + gtk_util::LeftAlignMisc(label);
|
| + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox), label,
|
| + FALSE, FALSE, 0);
|
| +
|
| + password_entry_ = gtk_entry_new();
|
| + gtk_entry_set_activates_default(GTK_ENTRY(password_entry_), TRUE);
|
| + gtk_entry_set_visibility(GTK_ENTRY(password_entry_), FALSE);
|
| +
|
| + GtkWidget* password_box = gtk_hbox_new(FALSE, gtk_util::kLabelSpacing);
|
| + gtk_box_pack_start(GTK_BOX(password_box),
|
| + gtk_label_new(l10n_util::GetStringUTF8(
|
| + IDS_PK11_AUTH_DIALOG_PASSWORD_FIELD).c_str()),
|
| + FALSE, FALSE, 0);
|
| + gtk_box_pack_start(GTK_BOX(password_box), password_entry_,
|
| + TRUE, TRUE, 0);
|
| +
|
| + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox), password_box,
|
| + FALSE, FALSE, 0);
|
| +
|
| + g_signal_connect(dialog_, "response",
|
| + G_CALLBACK(OnResponseThunk), this);
|
| + g_signal_connect(dialog_, "delete-event",
|
| + G_CALLBACK(OnWindowDeleteEventThunk), this);
|
| + g_signal_connect(dialog_, "destroy",
|
| + G_CALLBACK(OnWindowDestroyThunk), this);
|
| +}
|
| +
|
| +void PK11PasswordDialog::Show() {
|
| + gtk_util::ShowDialog(dialog_);
|
| +}
|
| +
|
| +void PK11PasswordDialog::Close() {
|
| + // Under the model that we've inherited from Windows, dialogs can receive
|
| + // more than one Close() call inside the current message loop event.
|
| + if (dialog_) {
|
| + gtk_widget_destroy(GTK_WIDGET(dialog_));
|
| + dialog_ = NULL;
|
| + }
|
| +}
|
| +
|
| +void PK11PasswordDialog::OnResponse(GtkWidget* dialog, int response_id) {
|
| + if (response_id == GTK_RESPONSE_ACCEPT) {
|
| + callback_->Run(gtk_entry_get_text(GTK_ENTRY(password_entry_)));
|
| + } else {
|
| + callback_->Run(static_cast<const char*>(NULL));
|
| + }
|
| + Close();
|
| +}
|
| +
|
| +gboolean PK11PasswordDialog::OnWindowDeleteEvent(GtkWidget* widget,
|
| + GdkEvent* event) {
|
| + Close();
|
| +
|
| + // Return true to prevent the gtk dialog from being destroyed. Close will
|
| + // destroy it for us and the default gtk_dialog_delete_event_handler() will
|
| + // force the destruction without us being able to stop it.
|
| + return TRUE;
|
| +}
|
| +
|
| +void PK11PasswordDialog::OnWindowDestroy(GtkWidget* widget) {
|
| + MessageLoop::current()->DeleteSoon(FROM_HERE, this);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +// Every post-task we do blocks, so there's no need to ref-count.
|
| +DISABLE_RUNNABLE_METHOD_REFCOUNT(PK11BlockingDialogDelegate);
|
| +
|
| +namespace browser {
|
| +
|
| +void ShowPK11PasswordDialog(PK11SlotInfo* slot,
|
| + bool retry,
|
| + PK11PasswordReason reason,
|
| + const GURL& url,
|
| + PK11PasswordCallback* callback) {
|
| + (new PK11PasswordDialog(slot, retry, reason, url, callback))->Show();
|
| +}
|
| +
|
| +base::PK11BlockingPasswordDelegate* NewPK11BlockingDialogDelegate(
|
| + PK11PasswordReason reason,
|
| + const GURL& url) {
|
| + return new PK11BlockingDialogDelegate(reason, url);
|
| +}
|
| +
|
| +} // namespace browser
|
|
|