fast_unload_controller.h revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Copyright 2013 The Chromium Authors. All rights reserved. 2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// found in the LICENSE file. 4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#ifndef CHROME_BROWSER_UI_FAST_UNLOAD_CONTROLLER_H_ 6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#define CHROME_BROWSER_UI_FAST_UNLOAD_CONTROLLER_H_ 7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <set> 9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/memory/scoped_ptr.h" 11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/memory/weak_ptr.h" 12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/strings/string_piece.h" 13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/ui/tabs/tab_strip_model_observer.h" 14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "content/public/browser/notification_observer.h" 15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "content/public/browser/notification_registrar.h" 16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass Browser; 18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass TabStripModel; 19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace content { 21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass NotificationSource; 22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass NotifictaionDetails; 23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass WebContents; 24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 25eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace chrome { 27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// FastUnloadController manages closing tabs and windows -- especially in 28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// regards to beforeunload handlers (have proceed/cancel dialogs) and 29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// unload handlers (have no user interaction). 30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// 31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Typical flow of closing a tab: 32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// 1. Browser calls CanCloseContents(). 33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// If true, browser calls contents::CloseWebContents(). 34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// 2. WebContents notifies us via its delegate and BeforeUnloadFired() 35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// that the beforeunload handler was run. If the user allowed the 36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// close to continue, we detached the tab and hold onto it while the 37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// close finishes. 38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// 39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Typical flow of closing a window: 40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// 1. BrowserView::CanClose() calls TabsNeedBeforeUnloadFired(). 41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// If beforeunload/unload handlers need to run, FastUnloadController returns 42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// true and calls ProcessPendingTabs() (private method). 43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// 2. For each tab with a beforeunload/unload handler, ProcessPendingTabs() 44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// calls |CoreTabHelper::OnCloseStarted()| 45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// and |web_contents->GetRenderViewHost()->FirePageBeforeUnload()|. 46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// 3. If the user allowed the close to continue, we detach all the tabs with 47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// unload handlers, remove them from the tab strip, and finish closing 48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// the tabs in the background. 49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// 4. The browser gets notified that the tab strip is empty and calls 50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// CloseFrame where the empty tab strip causes the window to hide. 51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Once the detached tabs finish, the browser calls CloseFrame again and 52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// the window is finally closed. 53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// 54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass FastUnloadController : public content::NotificationObserver, 55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public TabStripModelObserver { 56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public: 57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch explicit FastUnloadController(Browser* browser); 58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual ~FastUnloadController(); 59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Returns true if |contents| can be cleanly closed. When |browser_| is being 61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // closed, this function will return false to indicate |contents| should not 62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // be cleanly closed, since the fast shutdown path will just kill its 63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // renderer. 64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool CanCloseContents(content::WebContents* contents); 65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Called when a BeforeUnload handler is fired for |contents|. |proceed| 67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // indicates the user's response to the Y/N BeforeUnload handler dialog. If 68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // this parameter is false, any pending attempt to close the whole browser 69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // will be canceled. Returns true if Unload handlers should be fired. When the 70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // |browser_| is being closed, Unload handlers for any particular WebContents 71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // will not be run until every WebContents being closed has a chance to run 72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // its BeforeUnloadHandler. 73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool BeforeUnloadFired(content::WebContents* contents, bool proceed); 74eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool is_attempting_to_close_browser() const { 76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return is_attempting_to_close_browser_; 77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Called in response to a request to close |browser_|'s window. Returns true 80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // when there are no remaining beforeunload handlers to be run. 81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool ShouldCloseWindow(); 82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Returns true if |browser_| has any tabs that have BeforeUnload handlers 84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // that have not been fired. This method is non-const because it builds a list 85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // of tabs that need their BeforeUnloadHandlers fired. 86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // TODO(beng): This seems like it could be private but it is used by 87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // AreAllBrowsersCloseable() in application_lifetime.cc. It seems 88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // very similar to ShouldCloseWindow() and some consolidation 89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // could be pursued. 90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool TabsNeedBeforeUnloadFired(); 91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Returns true if all tabs' beforeunload/unload events have fired. 93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool HasCompletedUnloadProcessing() const; 94eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 95eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private: 96eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Overridden from content::NotificationObserver: 97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual void Observe(int type, 98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const content::NotificationSource& source, 99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const content::NotificationDetails& details) OVERRIDE; 100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Overridden from TabStripModelObserver: 102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual void TabInsertedAt(content::WebContents* contents, 103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int index, 104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool foreground) OVERRIDE; 105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual void TabDetachedAt(content::WebContents* contents, 106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int index) OVERRIDE; 107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual void TabReplacedAt(TabStripModel* tab_strip_model, 108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch content::WebContents* old_contents, 109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch content::WebContents* new_contents, 110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int index) OVERRIDE; 111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual void TabStripEmpty() OVERRIDE; 112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void TabAttachedImpl(content::WebContents* contents); 114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void TabDetachedImpl(content::WebContents* contents); 115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Detach |contents| and wait for it to finish closing. 117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // The close must be inititiated outside of this method. 118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Returns true if it succeeds. 119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool DetachWebContents(content::WebContents* contents); 120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Processes the next tab that needs it's beforeunload/unload event fired. 122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void ProcessPendingTabs(); 123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Clears all the state associated with processing tabs' beforeunload/unload 125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // events since the user cancelled closing the window. 126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void CancelWindowClose(); 127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Cleans up state appropriately when we are trying to close the 129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // browser or close a tab in the background. We also use this in the 130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // cases where a tab crashes or hangs even if the 131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // beforeunload/unload haven't successfully fired. 132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void ClearUnloadState(content::WebContents* contents); 133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Helper for |ClearUnloadState| to unwind stack before proceeding. 135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void PostTaskForProcessPendingTabs(); 136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Log a step of the unload processing. 138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void LogUnloadStep(const base::StringPiece& step_name, 139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch content::WebContents* contents) const; 140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Browser* browser_; 142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch content::NotificationRegistrar registrar_; 144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch typedef std::set<content::WebContents*> WebContentsSet; 146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Tracks tabs that need their beforeunload event started. 148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Only gets populated when we try to close the browser. 149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch WebContentsSet tabs_needing_before_unload_; 150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Tracks the tab that needs its beforeunload event result. 152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Only gets populated when we try to close the browser. 153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch content::WebContents* tab_needing_before_unload_ack_; 154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Tracks tabs that need their unload event started. 156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Only gets populated when we try to close the browser. 157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch WebContentsSet tabs_needing_unload_; 158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Tracks tabs that need to finish running their unload event. 160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Populated both when closing individual tabs and when closing the browser. 161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch WebContentsSet tabs_needing_unload_ack_; 162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Whether we are processing the beforeunload and unload events of each tab 164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // in preparation for closing the browser. FastUnloadController owns this 165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // state rather than Browser because unload handlers are the only reason that 166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // a Browser window isn't just immediately closed. 167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool is_attempting_to_close_browser_; 168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Manage tabs with beforeunload/unload handlers that close detached. 170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch class DetachedWebContentsDelegate; 171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch scoped_ptr<DetachedWebContentsDelegate> detached_delegate_; 172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::WeakPtrFactory<FastUnloadController> weak_factory_; 174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DISALLOW_COPY_AND_ASSIGN(FastUnloadController); 176eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}; 177eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 178eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} // namespace chrome 179eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 180eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif // CHROME_BROWSER_UI_FAST_UNLOAD_CONTROLLER_H_ 181