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)#ifndef CHROME_BROWSER_UI_UNLOAD_CONTROLLER_H_ 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CHROME_BROWSER_UI_UNLOAD_CONTROLLER_H_ 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/callback.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/weak_ptr.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model_observer.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_observer.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_registrar.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Browser; 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TabStripModel; 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content { 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class NotificationSource; 21010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)class NotificationDetails; 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class WebContents; 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chrome { 26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class UnloadController : public content::NotificationObserver, 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public TabStripModelObserver { 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit UnloadController(Browser* browser); 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~UnloadController(); 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns true if |contents| can be cleanly closed. When |browser_| is being 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // closed, this function will return false to indicate |contents| should not 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // be cleanly closed, since the fast shutdown path will just kill its 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // renderer. 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool CanCloseContents(content::WebContents* contents); 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Returns true if we need to run unload events for the |contents|. 40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) static bool ShouldRunUnloadEventsHelper(content::WebContents* contents); 41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Helper function to run beforeunload listeners on a WebContents. 434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Returns true if |contents| beforeunload listeners were invoked. 444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) static bool RunUnloadEventsHelper(content::WebContents* contents); 454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Called when a BeforeUnload handler is fired for |contents|. |proceed| 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // indicates the user's response to the Y/N BeforeUnload handler dialog. If 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // this parameter is false, any pending attempt to close the whole browser 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // will be canceled. Returns true if Unload handlers should be fired. When the 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |browser_| is being closed, Unload handlers for any particular WebContents 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // will not be run until every WebContents being closed has a chance to run 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // its BeforeUnloadHandler. 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool BeforeUnloadFired(content::WebContents* contents, bool proceed); 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_attempting_to_close_browser() const { 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return is_attempting_to_close_browser_; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Called in response to a request to close |browser_|'s window. Returns true 603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // when there are no remaining beforeunload handlers to be run. 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ShouldCloseWindow(); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // Begins the process of confirming whether the associated browser can be 643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // closed. 653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) bool CallBeforeUnloadHandlers( 663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) const base::Callback<void(bool)>& on_close_confirmed); 673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // Clears the results of any beforeunload confirmation dialogs triggered by a 693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // CallBeforeUnloadHandlers call. 703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) void ResetBeforeUnloadHandlers(); 713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns true if |browser_| has any tabs that have BeforeUnload handlers 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that have not been fired. This method is non-const because it builds a list 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of tabs that need their BeforeUnloadHandlers fired. 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(beng): This seems like it could be private but it is used by 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // AreAllBrowsersCloseable() in application_lifetime.cc. It seems 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // very similar to ShouldCloseWindow() and some consolidation 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // could be pursued. 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool TabsNeedBeforeUnloadFired(); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Clears all the state associated with processing tabs' beforeunload/unload 82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // events since the user cancelled closing the window. 83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) void CancelWindowClose(); 84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) private: 86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch typedef std::set<content::WebContents*> UnloadListenerSet; 87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Overridden from content::NotificationObserver: 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void Observe(int type, 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::NotificationSource& source, 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::NotificationDetails& details) OVERRIDE; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Overridden from TabStripModelObserver: 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void TabInsertedAt(content::WebContents* contents, 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool foreground) OVERRIDE; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void TabDetachedAt(content::WebContents* contents, 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index) OVERRIDE; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void TabReplacedAt(TabStripModel* tab_strip_model, 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::WebContents* old_contents, 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::WebContents* new_contents, 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index) OVERRIDE; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void TabStripEmpty() OVERRIDE; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void TabAttachedImpl(content::WebContents* contents); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void TabDetachedImpl(content::WebContents* contents); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Processes the next tab that needs it's beforeunload/unload event fired. 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ProcessPendingTabs(); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Whether we've completed firing all the tabs' beforeunload/unload events. 112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool HasCompletedUnloadProcessing() const; 113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Removes |web_contents| from the passed |set|. 115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Returns whether the tab was in the set in the first place. 116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool RemoveFromSet(UnloadListenerSet* set, 117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch content::WebContents* web_contents); 118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Cleans up state appropriately when we are trying to close the browser and 120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // the tab has finished firing its unload handler. We also use this in the 121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // cases where a tab crashes or hangs even if the beforeunload/unload haven't 122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // successfully fired. If |process_now| is true |ProcessPendingTabs| is 123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // invoked immediately, otherwise it is invoked after a delay (PostTask). 124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // 125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Typically you'll want to pass in true for |process_now|. Passing in true 126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // may result in deleting |tab|. If you know that shouldn't happen (because of 127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // the state of the stack), pass in false. 128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void ClearUnloadState(content::WebContents* web_contents, bool process_now); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) bool is_calling_before_unload_handlers() { 1313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return !on_close_confirmed_.is_null(); 1323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 1333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Browser* browser_; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::NotificationRegistrar registrar_; 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Tracks tabs that need there beforeunload event fired before we can 139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // close the browser. Only gets populated when we try to close the browser. 140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch UnloadListenerSet tabs_needing_before_unload_fired_; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Tracks tabs that need there unload event fired before we can 143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // close the browser. Only gets populated when we try to close the browser. 144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch UnloadListenerSet tabs_needing_unload_fired_; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Whether we are processing the beforeunload and unload events of each tab 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in preparation for closing the browser. UnloadController owns this state 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // rather than Browser because unload handlers are the only reason that a 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Browser window isn't just immediately closed. 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_attempting_to_close_browser_; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // A callback to call to report whether the user chose to close all tabs of 1533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // |browser_| that have beforeunload event handlers. This is set only if we 1543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // are currently confirming that the browser is closable. 1553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) base::Callback<void(bool)> on_close_confirmed_; 1563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::WeakPtrFactory<UnloadController> weak_factory_; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(UnloadController); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace chrome 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // CHROME_BROWSER_UI_UNLOAD_CONTROLLER_H_ 165