• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
LoginHandlerGtk(net::AuthChallengeInfo * auth_info,net::URLRequest * request)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 
~LoginHandlerGtk()45   virtual ~LoginHandlerGtk() {
46     root_.Destroy();
47   }
48 
49   // LoginModelObserver implementation.
OnAutofillDataAvailable(const std::wstring & username,const std::wstring & password)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:
BuildViewForPasswordManager(PasswordManager * manager,const string16 & explanation)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:
GetWidgetRoot()120   virtual GtkWidget* GetWidgetRoot() {
121     return root_.get();
122   }
123 
GetFocusWidget()124   virtual GtkWidget* GetFocusWidget() {
125     return username_entry_;
126   }
127 
DeleteDelegate()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 
OnOKClicked(GtkWidget * sender)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 
OnCancelClicked(GtkWidget * sender)164 void LoginHandlerGtk::OnCancelClicked(GtkWidget* sender) {
165   CancelAuth();
166 }
167 
OnPromptHierarchyChanged(GtkWidget * sender,GtkWidget * previous_toplevel)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
Create(net::AuthChallengeInfo * auth_info,net::URLRequest * request)182 LoginHandler* LoginHandler::Create(net::AuthChallengeInfo* auth_info,
183                                    net::URLRequest* request) {
184   return new LoginHandlerGtk(auth_info, request);
185 }
186