Extend batched shutdown to include the in-progress downloads dialog.

Previously, when Chrome shut down, the dialog warning about cancelling
downloads was displayed when the last window was about to close. With
this change, the dialog is displayed before any windows are closed.

BUG=265764

Review URL: https://chromiumcodereview.appspot.com/22545008

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@217976 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 2e9bc1a..30df6ec 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -604,6 +604,7 @@
 
 bool Browser::CallBeforeUnloadHandlers(
     const base::Callback<void(bool)>& on_close_confirmed) {
+  cancel_download_confirmation_state_ = RESPONSE_RECEIVED;
   if (IsFastTabUnloadEnabled()) {
     return fast_unload_controller_->CallBeforeUnloadHandlers(
         on_close_confirmed);
@@ -612,6 +613,7 @@
 }
 
 void Browser::ResetBeforeUnloadHandlers() {
+  cancel_download_confirmation_state_ = NOT_PROMPTED;
   if (IsFastTabUnloadEnabled())
     fast_unload_controller_->ResetBeforeUnloadHandlers();
   else
@@ -2055,14 +2057,20 @@
     return cancel_download_confirmation_state_ != WAITING_FOR_RESPONSE;
 
   int num_downloads_blocking;
-  if (DOWNLOAD_CLOSE_OK ==
-      OkToCloseWithInProgressDownloads(&num_downloads_blocking))
+  Browser::DownloadClosePreventionType dialog_type =
+      OkToCloseWithInProgressDownloads(&num_downloads_blocking);
+  if (dialog_type == DOWNLOAD_CLOSE_OK)
     return true;
 
   // Closing this window will kill some downloads; prompt to make sure
   // that's ok.
   cancel_download_confirmation_state_ = WAITING_FOR_RESPONSE;
-  window_->ConfirmBrowserCloseWithPendingDownloads();
+  window_->ConfirmBrowserCloseWithPendingDownloads(
+      num_downloads_blocking,
+      dialog_type,
+      false,
+      base::Bind(&Browser::InProgressDownloadResponse,
+                 weak_factory_.GetWeakPtr()));
 
   // Return false so the browser does not close.  We'll close if the user
   // confirms in the dialog.
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h
index a8f7c30..893b8dd 100644
--- a/chrome/browser/ui/browser_window.h
+++ b/chrome/browser/ui/browser_window.h
@@ -8,6 +8,7 @@
 #include "base/callback_forward.h"
 #include "chrome/browser/lifetime/browser_close_manager.h"
 #include "chrome/browser/ui/bookmarks/bookmark_bar.h"
+#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/fullscreen/fullscreen_exit_bubble_type.h"
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/sync/one_click_signin_sync_starter.h"
@@ -244,9 +245,12 @@
 
   // Shows the confirmation dialog box warning that the browser is closing with
   // in-progress downloads.
-  // This method should call Browser::InProgressDownloadResponse once the user
-  // has confirmed.
-  virtual void ConfirmBrowserCloseWithPendingDownloads() = 0;
+  // This method should call |callback| with the user's response.
+  virtual void ConfirmBrowserCloseWithPendingDownloads(
+      int download_count,
+      Browser::DownloadClosePreventionType dialog_type,
+      bool app_modal,
+      const base::Callback<void(bool)>& callback) = 0;
 
   // ThemeService calls this when a user has changed his or her theme,
   // indicating that it's time to redraw everything.
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.h b/chrome/browser/ui/cocoa/browser_window_cocoa.h
index d060c027..cd2f95e3 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.h
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.h
@@ -106,7 +106,11 @@
 #endif
   virtual bool IsDownloadShelfVisible() const OVERRIDE;
   virtual DownloadShelf* GetDownloadShelf() OVERRIDE;
-  virtual void ConfirmBrowserCloseWithPendingDownloads() OVERRIDE;
+  virtual void ConfirmBrowserCloseWithPendingDownloads(
+      int download_count,
+      Browser::DownloadClosePreventionType dialog_type,
+      bool app_modal,
+      const base::Callback<void(bool)>& callback) OVERRIDE;
   virtual void UserChangedTheme() OVERRIDE;
   virtual int GetExtraRenderViewHeight() const OVERRIDE;
   virtual void WebContentsFocused(content::WebContents* contents) OVERRIDE;
@@ -165,7 +169,6 @@
 
   Browser* browser_;  // weak, owned by controller
   BrowserWindowController* controller_;  // weak, owns us
-  base::WeakPtrFactory<Browser> confirm_close_factory_;
   base::scoped_nsobject<NSString> pending_window_title_;
   ui::WindowShowState initial_show_state_;
   NSInteger attention_request_id_;  // identifier from requestUserAttention
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
index 56e8bc8..ab607ee8 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.mm
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -118,7 +118,6 @@
                                        BrowserWindowController* controller)
   : browser_(browser),
     controller_(controller),
-    confirm_close_factory_(browser),
     initial_show_state_(ui::SHOW_STATE_DEFAULT),
     attention_request_id_(0) {
 
@@ -532,12 +531,12 @@
 
 // We allow closing the window here since the real quit decision on Mac is made
 // in [AppController quit:].
-void BrowserWindowCocoa::ConfirmBrowserCloseWithPendingDownloads() {
-  // Call InProgressDownloadResponse asynchronously to avoid a crash when the
-  // browser window is closed here (http://crbug.com/44454).
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-      base::Bind(&Browser::InProgressDownloadResponse,
-                 confirm_close_factory_.GetWeakPtr(), true));
+void BrowserWindowCocoa::ConfirmBrowserCloseWithPendingDownloads(
+      int download_count,
+      Browser::DownloadClosePreventionType dialog_type,
+      bool app_modal,
+      const base::Callback<void(bool)>& callback) {
+  callback.Run(true);
 }
 
 void BrowserWindowCocoa::UserChangedTheme() {
diff --git a/chrome/browser/ui/gtk/browser_window_gtk.cc b/chrome/browser/ui/gtk/browser_window_gtk.cc
index e092ad0..7ec112ea 100644
--- a/chrome/browser/ui/gtk/browser_window_gtk.cc
+++ b/chrome/browser/ui/gtk/browser_window_gtk.cc
@@ -1176,8 +1176,13 @@
   new PasswordGenerationBubbleGtk(rect, form, web_contents, password_generator);
 }
 
-void BrowserWindowGtk::ConfirmBrowserCloseWithPendingDownloads() {
-  DownloadInProgressDialogGtk::Show(browser(), GetNativeWindow());
+void BrowserWindowGtk::ConfirmBrowserCloseWithPendingDownloads(
+    int download_count,
+    Browser::DownloadClosePreventionType dialog_type,
+    bool app_modal,
+    const base::Callback<void(bool)>& callback) {
+  DownloadInProgressDialogGtk::Show(
+      GetNativeWindow(), download_count, dialog_type, app_modal, callback);
 }
 
 void BrowserWindowGtk::Observe(int type,
diff --git a/chrome/browser/ui/gtk/browser_window_gtk.h b/chrome/browser/ui/gtk/browser_window_gtk.h
index 7b44b8c..cfb2ff8 100644
--- a/chrome/browser/ui/gtk/browser_window_gtk.h
+++ b/chrome/browser/ui/gtk/browser_window_gtk.h
@@ -141,7 +141,11 @@
 #endif
   virtual bool IsDownloadShelfVisible() const OVERRIDE;
   virtual DownloadShelf* GetDownloadShelf() OVERRIDE;
-  virtual void ConfirmBrowserCloseWithPendingDownloads() OVERRIDE;
+  virtual void ConfirmBrowserCloseWithPendingDownloads(
+      int download_count,
+      Browser::DownloadClosePreventionType dialog_type,
+      bool app_modal,
+      const base::Callback<void(bool)>& callback) OVERRIDE;
   virtual void UserChangedTheme() OVERRIDE;
   virtual int GetExtraRenderViewHeight() const OVERRIDE;
   virtual void WebContentsFocused(content::WebContents* contents) OVERRIDE;
diff --git a/chrome/browser/ui/gtk/download/download_in_progress_dialog_gtk.cc b/chrome/browser/ui/gtk/download/download_in_progress_dialog_gtk.cc
index e188a58..b047ea1 100644
--- a/chrome/browser/ui/gtk/download/download_in_progress_dialog_gtk.cc
+++ b/chrome/browser/ui/gtk/download/download_in_progress_dialog_gtk.cc
@@ -6,28 +6,33 @@
 
 #include <gtk/gtk.h>
 
+#include "base/callback.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
-#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/gtk/gtk_util.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 
 // static
-void DownloadInProgressDialogGtk::Show(Browser* browser,
-                                       gfx::NativeWindow parent_window) {
-  new DownloadInProgressDialogGtk(browser, parent_window);
+void DownloadInProgressDialogGtk::Show(
+    gfx::NativeWindow parent_window,
+    int download_count,
+    Browser::DownloadClosePreventionType dialog_type,
+    bool app_modal,
+    const base::Callback<void(bool)>& callback) {
+  new DownloadInProgressDialogGtk(parent_window, download_count, dialog_type,
+                                  app_modal, callback);
 }
 
 DownloadInProgressDialogGtk::DownloadInProgressDialogGtk(
-    Browser* browser,
-    gfx::NativeWindow parent_window)
-    : browser_(browser) {
-  int download_count;
-  Browser::DownloadClosePreventionType dialog_type =
-      browser_->OkToCloseWithInProgressDownloads(&download_count);
-
+    gfx::NativeWindow parent_window,
+    int download_count,
+    Browser::DownloadClosePreventionType dialog_type,
+    bool app_modal,
+    const base::Callback<void(bool)>& callback)
+    : app_modal_(app_modal),
+      callback_(callback) {
   std::string title_text;
   std::string explanation_text;
   std::string ok_button_text;
@@ -71,6 +76,8 @@
   std::string cancel_button_text = l10n_util::GetStringUTF8(
       IDS_DOWNLOAD_REMOVE_CONFIRM_CANCEL_BUTTON_LABEL);
 
+  if (app_modal_)
+    gtk_util::MakeAppModalWindowGroup();
   GtkWidget* dialog = gtk_message_dialog_new(
       parent_window,
       static_cast<GtkDialogFlags>(GTK_DIALOG_MODAL),
@@ -98,6 +105,8 @@
 void DownloadInProgressDialogGtk::OnResponse(GtkWidget* dialog,
                                              int response_id) {
   gtk_widget_destroy(dialog);
-  browser_->InProgressDownloadResponse(response_id == GTK_RESPONSE_ACCEPT);
+  if (app_modal_)
+    gtk_util::AppModalDismissedUngroupWindows();
+  callback_.Run(response_id == GTK_RESPONSE_ACCEPT);
   delete this;
 }
diff --git a/chrome/browser/ui/gtk/download/download_in_progress_dialog_gtk.h b/chrome/browser/ui/gtk/download/download_in_progress_dialog_gtk.h
index 6eb439e..b45ab488 100644
--- a/chrome/browser/ui/gtk/download/download_in_progress_dialog_gtk.h
+++ b/chrome/browser/ui/gtk/download/download_in_progress_dialog_gtk.h
@@ -6,23 +6,30 @@
 #define CHROME_BROWSER_UI_GTK_DOWNLOAD_DOWNLOAD_IN_PROGRESS_DIALOG_GTK_H_
 
 #include "base/basictypes.h"
+#include "chrome/browser/ui/browser.h"
 #include "ui/base/gtk/gtk_signal.h"
 #include "ui/gfx/native_widget_types.h"
 
-class Browser;
-
 class DownloadInProgressDialogGtk {
  public:
-  static void Show(Browser* browser, gfx::NativeWindow parent_window);
+  static void Show(gfx::NativeWindow parent_window,
+                   int download_count,
+                   Browser::DownloadClosePreventionType dialog_type,
+                   bool app_modal,
+                   const base::Callback<void(bool)>& callback);
 
  private:
-  explicit DownloadInProgressDialogGtk(Browser* browser,
-                                       gfx::NativeWindow parent_window);
+  DownloadInProgressDialogGtk(gfx::NativeWindow parent_window,
+                              int download_count,
+                              Browser::DownloadClosePreventionType dialog_type,
+                              bool app_modal,
+                              const base::Callback<void(bool)>& callback);
   ~DownloadInProgressDialogGtk();
 
   CHROMEGTK_CALLBACK_1(DownloadInProgressDialogGtk, void, OnResponse, int);
 
-  Browser* browser_;
+  const bool app_modal_;
+  const base::Callback<void(bool)> callback_;
 
   DISALLOW_COPY_AND_ASSIGN(DownloadInProgressDialogGtk);
 };
diff --git a/chrome/browser/ui/views/download/download_in_progress_dialog_view.cc b/chrome/browser/ui/views/download/download_in_progress_dialog_view.cc
index 15bc3c1..d234b2b 100644
--- a/chrome/browser/ui/views/download/download_in_progress_dialog_view.cc
+++ b/chrome/browser/ui/views/download/download_in_progress_dialog_view.cc
@@ -7,7 +7,6 @@
 #include <algorithm>
 
 #include "base/strings/string_number_conversions.h"
-#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/views/constrained_window_views.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
@@ -21,20 +20,25 @@
 #include "ui/views/widget/widget.h"
 
 // static
-void DownloadInProgressDialogView::Show(Browser* browser,
-                                        gfx::NativeWindow parent) {
-  DownloadInProgressDialogView* window =
-      new DownloadInProgressDialogView(browser);
+void DownloadInProgressDialogView::Show(
+    gfx::NativeWindow parent,
+    int download_count,
+    Browser::DownloadClosePreventionType dialog_type,
+    bool app_modal,
+    const base::Callback<void(bool)>& callback) {
+  DownloadInProgressDialogView* window = new DownloadInProgressDialogView(
+      download_count, dialog_type, app_modal, callback);
   CreateBrowserModalDialogViews(window, parent)->Show();
 }
 
-DownloadInProgressDialogView::DownloadInProgressDialogView(Browser* browser)
-    : browser_(browser),
+DownloadInProgressDialogView::DownloadInProgressDialogView(
+    int download_count,
+    Browser::DownloadClosePreventionType dialog_type,
+    bool app_modal,
+    const base::Callback<void(bool)>& callback)
+    : app_modal_(app_modal),
+      callback_(callback),
       message_box_view_(NULL) {
-  int download_count;
-  Browser::DownloadClosePreventionType dialog_type =
-      browser_->OkToCloseWithInProgressDownloads(&download_count);
-
   string16 explanation_text;
   switch (dialog_type) {
     case Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN:
@@ -93,17 +97,17 @@
 }
 
 bool DownloadInProgressDialogView::Cancel() {
-  browser_->InProgressDownloadResponse(false);
+  callback_.Run(false);
   return true;
 }
 
 bool DownloadInProgressDialogView::Accept() {
-  browser_->InProgressDownloadResponse(true);
+  callback_.Run(true);
   return true;
 }
 
 ui::ModalType DownloadInProgressDialogView::GetModalType() const {
-  return ui::MODAL_TYPE_WINDOW;
+  return app_modal_ ? ui::MODAL_TYPE_SYSTEM : ui::MODAL_TYPE_WINDOW;
 }
 
 string16 DownloadInProgressDialogView::GetWindowTitle() const {
diff --git a/chrome/browser/ui/views/download/download_in_progress_dialog_view.h b/chrome/browser/ui/views/download/download_in_progress_dialog_view.h
index cf53d3f..acce8e8 100644
--- a/chrome/browser/ui/views/download/download_in_progress_dialog_view.h
+++ b/chrome/browser/ui/views/download/download_in_progress_dialog_view.h
@@ -7,20 +7,26 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
+#include "chrome/browser/ui/browser.h"
 #include "ui/views/window/dialog_delegate.h"
 
-class Browser;
-
 namespace views {
 class MessageBoxView;
 }
 
 class DownloadInProgressDialogView : public views::DialogDelegate {
  public:
-  static void Show(Browser* browser, gfx::NativeWindow parent);
+  static void Show(gfx::NativeWindow parent_window,
+                   int download_count,
+                   Browser::DownloadClosePreventionType dialog_type,
+                   bool app_modal,
+                   const base::Callback<void(bool)>& callback);
 
  private:
-  explicit DownloadInProgressDialogView(Browser* browser);
+  DownloadInProgressDialogView(int download_count,
+                               Browser::DownloadClosePreventionType dialog_type,
+                               bool app_modal,
+                               const base::Callback<void(bool)>& callback);
   virtual ~DownloadInProgressDialogView();
 
   // views::DialogDelegate:
@@ -37,7 +43,8 @@
   virtual const views::Widget* GetWidget() const OVERRIDE;
   virtual views::View* GetContentsView() OVERRIDE;
 
-  Browser* browser_;
+  const bool app_modal_;
+  const base::Callback<void(bool)> callback_;
   views::MessageBoxView* message_box_view_;
 
   string16 title_text_;
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 3287269..95f1cbd6 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -1164,8 +1164,13 @@
   return download_shelf_.get();
 }
 
-void BrowserView::ConfirmBrowserCloseWithPendingDownloads() {
-  DownloadInProgressDialogView::Show(browser_.get(), GetNativeWindow());
+void BrowserView::ConfirmBrowserCloseWithPendingDownloads(
+    int download_count,
+    Browser::DownloadClosePreventionType dialog_type,
+    bool app_modal,
+    const base::Callback<void(bool)>& callback) {
+  DownloadInProgressDialogView::Show(
+      GetNativeWindow(), download_count, dialog_type, app_modal, callback);
 }
 
 void BrowserView::ShowCreateChromeAppShortcutsDialog(
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 7befa2c..a4f277b8 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -344,7 +344,11 @@
   void SetDownloadShelfVisible(bool visible);
   virtual bool IsDownloadShelfVisible() const OVERRIDE;
   virtual DownloadShelf* GetDownloadShelf() OVERRIDE;
-  virtual void ConfirmBrowserCloseWithPendingDownloads() OVERRIDE;
+  virtual void ConfirmBrowserCloseWithPendingDownloads(
+      int download_count,
+      Browser::DownloadClosePreventionType dialog_type,
+      bool app_modal,
+      const base::Callback<void(bool)>& callback) OVERRIDE;
   virtual void UserChangedTheme() OVERRIDE;
   virtual int GetExtraRenderViewHeight() const OVERRIDE;
   virtual void WebContentsFocused(content::WebContents* contents) OVERRIDE;