Home | History | Annotate | Download | only in login
      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/login/login_prompt.h"
      6 
      7 #include <gtk/gtk.h>
      8 
      9 #include "base/utf_string_conversions.h"
     10 #include "chrome/browser/password_manager/password_manager.h"
     11 #include "chrome/browser/tab_contents/tab_contents_view_gtk.h"
     12 #include "chrome/browser/tab_contents/tab_util.h"
     13 #include "chrome/browser/ui/gtk/constrained_window_gtk.h"
     14 #include "chrome/browser/ui/gtk/gtk_util.h"
     15 #include "chrome/browser/ui/login/login_model.h"
     16 #include "content/browser/browser_thread.h"
     17 #include "content/browser/renderer_host/resource_dispatcher_host.h"
     18 #include "content/browser/tab_contents/navigation_controller.h"
     19 #include "content/browser/tab_contents/tab_contents.h"
     20 #include "content/browser/tab_contents/tab_contents_delegate.h"
     21 #include "grit/generated_resources.h"
     22 #include "net/url_request/url_request.h"
     23 #include "ui/base/gtk/gtk_signal.h"
     24 #include "ui/base/l10n/l10n_util.h"
     25 
     26 using webkit_glue::PasswordForm;
     27 
     28 // ----------------------------------------------------------------------------
     29 // LoginHandlerGtk
     30 
     31 // This class simply forwards the authentication from the LoginView (on
     32 // the UI thread) to the net::URLRequest (on the I/O thread).
     33 // This class uses ref counting to ensure that it lives until all InvokeLaters
     34 // have been called.
     35 class LoginHandlerGtk : public LoginHandler,
     36                         public ConstrainedWindowGtkDelegate {
     37  public:
     38   LoginHandlerGtk(net::AuthChallengeInfo* auth_info, net::URLRequest* request)
     39       : LoginHandler(auth_info, request),
     40         username_entry_(NULL),
     41         password_entry_(NULL),
     42         ok_(NULL) {
     43   }
     44 
     45   virtual ~LoginHandlerGtk() {
     46     root_.Destroy();
     47   }
     48 
     49   // LoginModelObserver implementation.
     50   virtual void OnAutofillDataAvailable(const std::wstring& username,
     51                                        const std::wstring& password) {
     52     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     53 
     54     // NOTE: Would be nice to use gtk_entry_get_text_length, but it is fairly
     55     // new and not always in our GTK version.
     56     if (strlen(gtk_entry_get_text(GTK_ENTRY(username_entry_))) == 0) {
     57       gtk_entry_set_text(GTK_ENTRY(username_entry_),
     58                          WideToUTF8(username).c_str());
     59       gtk_entry_set_text(GTK_ENTRY(password_entry_),
     60                          WideToUTF8(password).c_str());
     61       gtk_editable_select_region(GTK_EDITABLE(username_entry_), 0, -1);
     62     }
     63   }
     64 
     65   // LoginHandler:
     66   virtual void BuildViewForPasswordManager(PasswordManager* manager,
     67                                            const string16& explanation) {
     68     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     69 
     70     root_.Own(gtk_vbox_new(FALSE, gtk_util::kContentAreaBorder));
     71     GtkWidget* label = gtk_label_new(UTF16ToUTF8(explanation).c_str());
     72     gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
     73     gtk_box_pack_start(GTK_BOX(root_.get()), label, FALSE, FALSE, 0);
     74 
     75     username_entry_ = gtk_entry_new();
     76     gtk_entry_set_activates_default(GTK_ENTRY(username_entry_), TRUE);
     77 
     78     password_entry_ = gtk_entry_new();
     79     gtk_entry_set_activates_default(GTK_ENTRY(password_entry_), TRUE);
     80     gtk_entry_set_visibility(GTK_ENTRY(password_entry_), FALSE);
     81 
     82     GtkWidget* table = gtk_util::CreateLabeledControlsGroup(NULL,
     83         l10n_util::GetStringUTF8(IDS_LOGIN_DIALOG_USERNAME_FIELD).c_str(),
     84         username_entry_,
     85         l10n_util::GetStringUTF8(IDS_LOGIN_DIALOG_PASSWORD_FIELD).c_str(),
     86         password_entry_,
     87         NULL);
     88     gtk_box_pack_start(GTK_BOX(root_.get()), table, FALSE, FALSE, 0);
     89 
     90     GtkWidget* hbox = gtk_hbox_new(FALSE, 12);
     91     gtk_box_pack_start(GTK_BOX(root_.get()), hbox, FALSE, FALSE, 0);
     92 
     93     ok_ = gtk_button_new_from_stock(GTK_STOCK_OK);
     94     gtk_button_set_label(
     95         GTK_BUTTON(ok_),
     96         l10n_util::GetStringUTF8(IDS_LOGIN_DIALOG_OK_BUTTON_LABEL).c_str());
     97     g_signal_connect(ok_, "clicked", G_CALLBACK(OnOKClickedThunk), this);
     98     gtk_box_pack_end(GTK_BOX(hbox), ok_, FALSE, FALSE, 0);
     99 
    100     GtkWidget* cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
    101     g_signal_connect(cancel, "clicked", G_CALLBACK(OnCancelClickedThunk), this);
    102     gtk_box_pack_end(GTK_BOX(hbox), cancel, FALSE, FALSE, 0);
    103 
    104     g_signal_connect(root_.get(), "hierarchy-changed",
    105                      G_CALLBACK(OnPromptHierarchyChangedThunk), this);
    106 
    107     SetModel(manager);
    108 
    109     // Scary thread safety note: This can potentially be called *after* SetAuth
    110     // or CancelAuth (say, if the request was cancelled before the UI thread got
    111     // control).  However, that's OK since any UI interaction in those functions
    112     // will occur via an InvokeLater on the UI thread, which is guaranteed
    113     // to happen after this is called (since this was InvokeLater'd first).
    114     SetDialog(GetTabContentsForLogin()->CreateConstrainedDialog(this));
    115 
    116     NotifyAuthNeeded();
    117   }
    118 
    119   // Overridden from ConstrainedWindowGtkDelegate:
    120   virtual GtkWidget* GetWidgetRoot() {
    121     return root_.get();
    122   }
    123 
    124   virtual GtkWidget* GetFocusWidget() {
    125     return username_entry_;
    126   }
    127 
    128   virtual void DeleteDelegate() {
    129     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    130 
    131     // The constrained window is going to delete itself; clear our pointer.
    132     SetDialog(NULL);
    133     SetModel(NULL);
    134 
    135     ReleaseSoon();
    136   }
    137 
    138  private:
    139   friend class LoginPrompt;
    140 
    141   CHROMEGTK_CALLBACK_0(LoginHandlerGtk, void, OnOKClicked);
    142   CHROMEGTK_CALLBACK_0(LoginHandlerGtk, void, OnCancelClicked);
    143   CHROMEGTK_CALLBACK_1(LoginHandlerGtk, void, OnPromptHierarchyChanged,
    144                        GtkWidget*);
    145 
    146   // The GtkWidgets that form our visual hierarchy:
    147   // The root container we pass to our parent.
    148   OwnedWidgetGtk root_;
    149 
    150   // GtkEntry widgets that the user types into.
    151   GtkWidget* username_entry_;
    152   GtkWidget* password_entry_;
    153   GtkWidget* ok_;
    154 
    155   DISALLOW_COPY_AND_ASSIGN(LoginHandlerGtk);
    156 };
    157 
    158 void LoginHandlerGtk::OnOKClicked(GtkWidget* sender) {
    159   SetAuth(
    160       UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(username_entry_))),
    161       UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(password_entry_))));
    162 }
    163 
    164 void LoginHandlerGtk::OnCancelClicked(GtkWidget* sender) {
    165   CancelAuth();
    166 }
    167 
    168 void LoginHandlerGtk::OnPromptHierarchyChanged(GtkWidget* sender,
    169                                                GtkWidget* previous_toplevel) {
    170   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    171 
    172   if (!GTK_WIDGET_TOPLEVEL(gtk_widget_get_toplevel(ok_)))
    173     return;
    174 
    175   // Now that we have attached ourself to the window, we can make our OK
    176   // button the default action and mess with the focus.
    177   GTK_WIDGET_SET_FLAGS(ok_, GTK_CAN_DEFAULT);
    178   gtk_widget_grab_default(ok_);
    179 }
    180 
    181 // static
    182 LoginHandler* LoginHandler::Create(net::AuthChallengeInfo* auth_info,
    183                                    net::URLRequest* request) {
    184   return new LoginHandlerGtk(auth_info, request);
    185 }
    186