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