172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/login/login_prompt.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <gtk/gtk.h> 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h" 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/password_manager/password_manager.h" 113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/tab_contents/tab_contents_view_gtk.h" 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/tab_contents/tab_util.h" 1372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/constrained_window_gtk.h" 1472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/gtk_util.h" 1521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/login/login_model.h" 16dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h" 17dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/resource_dispatcher_host.h" 18dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/navigation_controller.h" 19dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h" 20dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents_delegate.h" 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h" 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/url_request/url_request.h" 2372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/gtk/gtk_signal.h" 2472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h" 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing webkit_glue::PasswordForm; 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// ---------------------------------------------------------------------------- 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// LoginHandlerGtk 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This class simply forwards the authentication from the LoginView (on 3221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// the UI thread) to the net::URLRequest (on the I/O thread). 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This class uses ref counting to ensure that it lives until all InvokeLaters 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// have been called. 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass LoginHandlerGtk : public LoginHandler, 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public ConstrainedWindowGtkDelegate { 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 3821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen LoginHandlerGtk(net::AuthChallengeInfo* auth_info, net::URLRequest* request) 39731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick : LoginHandler(auth_info, request), 40731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick username_entry_(NULL), 41731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick password_entry_(NULL), 42731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ok_(NULL) { 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual ~LoginHandlerGtk() { 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch root_.Destroy(); 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // LoginModelObserver implementation. 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void OnAutofillDataAvailable(const std::wstring& username, 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::wstring& password) { 52731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // NOTE: Would be nice to use gtk_entry_get_text_length, but it is fairly 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // new and not always in our GTK version. 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (strlen(gtk_entry_get_text(GTK_ENTRY(username_entry_))) == 0) { 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_entry_set_text(GTK_ENTRY(username_entry_), 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WideToUTF8(username).c_str()); 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_entry_set_text(GTK_ENTRY(password_entry_), 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WideToUTF8(password).c_str()); 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_editable_select_region(GTK_EDITABLE(username_entry_), 0, -1); 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // LoginHandler: 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void BuildViewForPasswordManager(PasswordManager* manager, 6772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16& explanation) { 68731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch root_.Own(gtk_vbox_new(FALSE, gtk_util::kContentAreaBorder)); 7172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen GtkWidget* label = gtk_label_new(UTF16ToUTF8(explanation).c_str()); 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_box_pack_start(GTK_BOX(root_.get()), label, FALSE, FALSE, 0); 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch username_entry_ = gtk_entry_new(); 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_entry_set_activates_default(GTK_ENTRY(username_entry_), TRUE); 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch password_entry_ = gtk_entry_new(); 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_entry_set_activates_default(GTK_ENTRY(password_entry_), TRUE); 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_entry_set_visibility(GTK_ENTRY(password_entry_), FALSE); 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GtkWidget* table = gtk_util::CreateLabeledControlsGroup(NULL, 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch l10n_util::GetStringUTF8(IDS_LOGIN_DIALOG_USERNAME_FIELD).c_str(), 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch username_entry_, 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch l10n_util::GetStringUTF8(IDS_LOGIN_DIALOG_PASSWORD_FIELD).c_str(), 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch password_entry_, 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NULL); 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_box_pack_start(GTK_BOX(root_.get()), table, FALSE, FALSE, 0); 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GtkWidget* hbox = gtk_hbox_new(FALSE, 12); 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_box_pack_start(GTK_BOX(root_.get()), hbox, FALSE, FALSE, 0); 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ok_ = gtk_button_new_from_stock(GTK_STOCK_OK); 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_button_set_label( 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GTK_BUTTON(ok_), 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch l10n_util::GetStringUTF8(IDS_LOGIN_DIALOG_OK_BUTTON_LABEL).c_str()); 973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick g_signal_connect(ok_, "clicked", G_CALLBACK(OnOKClickedThunk), this); 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_box_pack_end(GTK_BOX(hbox), ok_, FALSE, FALSE, 0); 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GtkWidget* cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL); 1013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick g_signal_connect(cancel, "clicked", G_CALLBACK(OnCancelClickedThunk), this); 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_box_pack_end(GTK_BOX(hbox), cancel, FALSE, FALSE, 0); 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_signal_connect(root_.get(), "hierarchy-changed", 1053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick G_CALLBACK(OnPromptHierarchyChangedThunk), this); 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetModel(manager); 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Scary thread safety note: This can potentially be called *after* SetAuth 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // or CancelAuth (say, if the request was cancelled before the UI thread got 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // control). However, that's OK since any UI interaction in those functions 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // will occur via an InvokeLater on the UI thread, which is guaranteed 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to happen after this is called (since this was InvokeLater'd first). 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetDialog(GetTabContentsForLogin()->CreateConstrainedDialog(this)); 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotifyAuthNeeded(); 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Overridden from ConstrainedWindowGtkDelegate: 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual GtkWidget* GetWidgetRoot() { 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return root_.get(); 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 124dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen virtual GtkWidget* GetFocusWidget() { 125dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return username_entry_; 126dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 127dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void DeleteDelegate() { 129731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The constrained window is going to delete itself; clear our pointer. 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetDialog(NULL); 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetModel(NULL); 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ReleaseSoon(); 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch friend class LoginPrompt; 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick CHROMEGTK_CALLBACK_0(LoginHandlerGtk, void, OnOKClicked); 1423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick CHROMEGTK_CALLBACK_0(LoginHandlerGtk, void, OnCancelClicked); 1433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick CHROMEGTK_CALLBACK_1(LoginHandlerGtk, void, OnPromptHierarchyChanged, 1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick GtkWidget*); 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The GtkWidgets that form our visual hierarchy: 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The root container we pass to our parent. 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch OwnedWidgetGtk root_; 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // GtkEntry widgets that the user types into. 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GtkWidget* username_entry_; 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GtkWidget* password_entry_; 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GtkWidget* ok_; 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DISALLOW_COPY_AND_ASSIGN(LoginHandlerGtk); 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid LoginHandlerGtk::OnOKClicked(GtkWidget* sender) { 1593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SetAuth( 16072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(username_entry_))), 16172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(password_entry_)))); 1623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 1633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid LoginHandlerGtk::OnCancelClicked(GtkWidget* sender) { 1653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick CancelAuth(); 1663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 1673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid LoginHandlerGtk::OnPromptHierarchyChanged(GtkWidget* sender, 1693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick GtkWidget* previous_toplevel) { 170731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!GTK_WIDGET_TOPLEVEL(gtk_widget_get_toplevel(ok_))) 1733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return; 1743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Now that we have attached ourself to the window, we can make our OK 1763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // button the default action and mess with the focus. 1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick GTK_WIDGET_SET_FLAGS(ok_, GTK_CAN_DEFAULT); 1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick gtk_widget_grab_default(ok_); 1793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochLoginHandler* LoginHandler::Create(net::AuthChallengeInfo* auth_info, 18321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen net::URLRequest* request) { 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return new LoginHandlerGtk(auth_info, request); 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 186