unload_controller.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/unload_controller.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/message_loop.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_tabstrip.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_notification_types.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_source.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_types.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_view_host.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chrome {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// UnloadController, public:
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)UnloadController::UnloadController(Browser* browser)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : browser_(browser),
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_attempting_to_close_browser_(false),
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  browser_->tab_strip_model()->AddObserver(this);
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)UnloadController::~UnloadController() {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  browser_->tab_strip_model()->RemoveObserver(this);
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool UnloadController::CanCloseContents(content::WebContents* contents) {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Don't try to close the tab when the whole browser is being closed, since
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that avoids the fast shutdown path where we just kill all the renderers.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_attempting_to_close_browser_)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ClearUnloadState(contents, true);
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !is_attempting_to_close_browser_;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool UnloadController::BeforeUnloadFired(content::WebContents* contents,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         bool proceed) {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_attempting_to_close_browser_) {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!proceed)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      contents->SetClosedByUserGesture(false);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return proceed;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!proceed) {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CancelWindowClose();
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    contents->SetClosedByUserGesture(false);
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (RemoveFromSet(&tabs_needing_before_unload_fired_, contents)) {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Now that beforeunload has fired, put the tab on the queue to fire
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // unload.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tabs_needing_unload_fired_.insert(contents);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProcessPendingTabs();
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We want to handle firing the unload event ourselves since we want to
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // fire all the beforeunload events before attempting to fire the unload
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // events should the user cancel closing the browser.
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool UnloadController::ShouldCloseWindow() {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HasCompletedUnloadProcessing())
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_attempting_to_close_browser_ = true;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!TabsNeedBeforeUnloadFired())
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProcessPendingTabs();
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool UnloadController::TabsNeedBeforeUnloadFired() {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (tabs_needing_before_unload_fired_.empty()) {
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::WebContents* contents =
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          browser_->tab_strip_model()->GetWebContentsAt(i);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (contents->NeedToFireBeforeUnload())
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tabs_needing_before_unload_fired_.insert(contents);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !tabs_needing_before_unload_fired_.empty();
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// UnloadController, content::NotificationObserver implementation:
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UnloadController::Observe(int type,
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const content::NotificationSource& source,
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const content::NotificationDetails& details) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED:
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (is_attempting_to_close_browser_) {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ClearUnloadState(content::Source<content::WebContents>(source).ptr(),
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         false);  // See comment for ClearUnloadState().
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Got a notification we didn't register for.";
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// UnloadController, TabStripModelObserver implementation:
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UnloadController::TabInsertedAt(content::WebContents* contents,
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     int index,
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     bool foreground) {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TabAttachedImpl(contents);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UnloadController::TabDetachedAt(content::WebContents* contents,
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     int index) {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TabDetachedImpl(contents);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UnloadController::TabReplacedAt(TabStripModel* tab_strip_model,
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     content::WebContents* old_contents,
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     content::WebContents* new_contents,
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     int index) {
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  TabDetachedImpl(old_contents);
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  TabAttachedImpl(new_contents);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UnloadController::TabStripEmpty() {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set is_attempting_to_close_browser_ here, so that extensions, etc, do not
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // attempt to add tabs to the browser before it closes.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_attempting_to_close_browser_ = true;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// UnloadController, private:
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UnloadController::TabAttachedImpl(content::WebContents* contents) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the tab crashes in the beforeunload or unload handler, it won't be
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // able to ack. But we know we can close it.
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registrar_.Add(
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this,
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::Source<content::WebContents>(contents));
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UnloadController::TabDetachedImpl(content::WebContents* contents) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_attempting_to_close_browser_)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ClearUnloadState(contents, false);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registrar_.Remove(this,
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    content::Source<content::WebContents>(contents));
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UnloadController::ProcessPendingTabs() {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_attempting_to_close_browser_) {
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Because we might invoke this after a delay it's possible for the value of
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // is_attempting_to_close_browser_ to have changed since we scheduled the
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // task.
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HasCompletedUnloadProcessing()) {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We've finished all the unload events and can proceed to close the
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // browser.
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    browser_->OnWindowClosing();
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Process beforeunload tabs first. When that queue is empty, process
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // unload tabs.
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!tabs_needing_before_unload_fired_.empty()) {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::WebContents* web_contents =
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *(tabs_needing_before_unload_fired_.begin());
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Null check render_view_host here as this gets called on a PostTask and
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the tab's render_view_host may have been nulled out.
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (web_contents->GetRenderViewHost()) {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      web_contents->GetRenderViewHost()->FirePageBeforeUnload(false);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ClearUnloadState(web_contents, true);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (!tabs_needing_unload_fired_.empty()) {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We've finished firing all beforeunload events and can proceed with unload
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // events.
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // somewhere around here so that we have accurate measurements of shutdown
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // time.
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(ojan): We can probably fire all the unload events in parallel and
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // get a perf benefit from that in the cases where the tab hangs in it's
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // unload handler or takes a long time to page in.
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::WebContents* web_contents = *(tabs_needing_unload_fired_.begin());
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Null check render_view_host here as this gets called on a PostTask and
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the tab's render_view_host may have been nulled out.
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (web_contents->GetRenderViewHost()) {
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      web_contents->GetRenderViewHost()->ClosePage();
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ClearUnloadState(web_contents, true);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool UnloadController::HasCompletedUnloadProcessing() const {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return is_attempting_to_close_browser_ &&
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tabs_needing_before_unload_fired_.empty() &&
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tabs_needing_unload_fired_.empty();
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UnloadController::CancelWindowClose() {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Closing of window can be canceled from a beforeunload handler.
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(is_attempting_to_close_browser_);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tabs_needing_before_unload_fired_.clear();
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tabs_needing_unload_fired_.clear();
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_attempting_to_close_browser_ = false;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::NotificationService::current()->Notify(
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED,
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::Source<Browser>(browser_),
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::NotificationService::NoDetails());
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool UnloadController::RemoveFromSet(UnloadListenerSet* set,
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     content::WebContents* web_contents) {
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(is_attempting_to_close_browser_);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UnloadListenerSet::iterator iter =
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::find(set->begin(), set->end(), web_contents);
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter != set->end()) {
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    set->erase(iter);
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UnloadController::ClearUnloadState(content::WebContents* web_contents,
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        bool process_now) {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_attempting_to_close_browser_) {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RemoveFromSet(&tabs_needing_before_unload_fired_, web_contents);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RemoveFromSet(&tabs_needing_unload_fired_, web_contents);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (process_now) {
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ProcessPendingTabs();
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MessageLoop::current()->PostTask(
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE,
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&UnloadController::ProcessPendingTabs,
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     weak_factory_.GetWeakPtr()));
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace chrome
259