Home | History | Annotate | Download | only in ui
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/browser_list.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/auto_reset.h"
     10 #include "base/logging.h"
     11 #include "chrome/browser/browser_process.h"
     12 #include "chrome/browser/browser_shutdown.h"
     13 #include "chrome/browser/chrome_notification_types.h"
     14 #include "chrome/browser/lifetime/application_lifetime.h"
     15 #include "chrome/browser/profiles/profile.h"
     16 #include "chrome/browser/ui/browser.h"
     17 #include "chrome/browser/ui/browser_finder.h"
     18 #include "chrome/browser/ui/browser_iterator.h"
     19 #include "chrome/browser/ui/browser_list_observer.h"
     20 #include "chrome/browser/ui/browser_window.h"
     21 #include "chrome/browser/ui/host_desktop.h"
     22 #include "content/public/browser/notification_service.h"
     23 #include "content/public/browser/user_metrics.h"
     24 
     25 using base::UserMetricsAction;
     26 using content::WebContents;
     27 
     28 // static
     29 base::LazyInstance<ObserverList<chrome::BrowserListObserver> >::Leaky
     30     BrowserList::observers_ = LAZY_INSTANCE_INITIALIZER;
     31 
     32 // static
     33 BrowserList* BrowserList::native_instance_ = NULL;
     34 BrowserList* BrowserList::ash_instance_ = NULL;
     35 
     36 ////////////////////////////////////////////////////////////////////////////////
     37 // BrowserList, public:
     38 
     39 Browser* BrowserList::GetLastActive() const {
     40   if (!last_active_browsers_.empty())
     41     return *(last_active_browsers_.rbegin());
     42   return NULL;
     43 }
     44 
     45 // static
     46 BrowserList* BrowserList::GetInstance(chrome::HostDesktopType type) {
     47   BrowserList** list = NULL;
     48   if (type == chrome::HOST_DESKTOP_TYPE_NATIVE)
     49     list = &native_instance_;
     50   else if (type == chrome::HOST_DESKTOP_TYPE_ASH)
     51     list = &ash_instance_;
     52   else
     53     NOTREACHED();
     54   if (!*list)
     55     *list = new BrowserList;
     56   return *list;
     57 }
     58 
     59 // static
     60 void BrowserList::AddBrowser(Browser* browser) {
     61   DCHECK(browser);
     62   // Push |browser| on the appropriate list instance.
     63   BrowserList* browser_list = GetInstance(browser->host_desktop_type());
     64   browser_list->browsers_.push_back(browser);
     65 
     66   g_browser_process->AddRefModule();
     67 
     68   content::NotificationService::current()->Notify(
     69       chrome::NOTIFICATION_BROWSER_OPENED,
     70       content::Source<Browser>(browser),
     71       content::NotificationService::NoDetails());
     72 
     73   FOR_EACH_OBSERVER(chrome::BrowserListObserver, observers_.Get(),
     74                     OnBrowserAdded(browser));
     75 }
     76 
     77 // static
     78 void BrowserList::RemoveBrowser(Browser* browser) {
     79   // Remove |browser| from the appropriate list instance.
     80   BrowserList* browser_list = GetInstance(browser->host_desktop_type());
     81   RemoveBrowserFrom(browser, &browser_list->last_active_browsers_);
     82 
     83   content::NotificationService::current()->Notify(
     84       chrome::NOTIFICATION_BROWSER_CLOSED,
     85       content::Source<Browser>(browser),
     86       content::NotificationService::NoDetails());
     87 
     88   RemoveBrowserFrom(browser, &browser_list->browsers_);
     89 
     90   FOR_EACH_OBSERVER(chrome::BrowserListObserver, observers_.Get(),
     91                     OnBrowserRemoved(browser));
     92 
     93   g_browser_process->ReleaseModule();
     94 
     95   // If we're exiting, send out the APP_TERMINATING notification to allow other
     96   // modules to shut themselves down.
     97   if (chrome::GetTotalBrowserCount() == 0 &&
     98       (browser_shutdown::IsTryingToQuit() ||
     99        g_browser_process->IsShuttingDown())) {
    100     // Last browser has just closed, and this is a user-initiated quit or there
    101     // is no module keeping the app alive, so send out our notification. No need
    102     // to call ProfileManager::ShutdownSessionServices() as part of the
    103     // shutdown, because Browser::WindowClosing() already makes sure that the
    104     // SessionService is created and notified.
    105     chrome::NotifyAppTerminating();
    106     chrome::OnAppExiting();
    107   }
    108 }
    109 
    110 // static
    111 void BrowserList::AddObserver(chrome::BrowserListObserver* observer) {
    112   observers_.Get().AddObserver(observer);
    113 }
    114 
    115 // static
    116 void BrowserList::RemoveObserver(chrome::BrowserListObserver* observer) {
    117   observers_.Get().RemoveObserver(observer);
    118 }
    119 
    120 // static
    121 void BrowserList::CloseAllBrowsersWithProfile(Profile* profile) {
    122   BrowserVector browsers_to_close;
    123   for (chrome::BrowserIterator it; !it.done(); it.Next()) {
    124     if (it->profile()->GetOriginalProfile() == profile->GetOriginalProfile())
    125       browsers_to_close.push_back(*it);
    126   }
    127 
    128   for (BrowserVector::const_iterator it = browsers_to_close.begin();
    129        it != browsers_to_close.end(); ++it) {
    130     (*it)->window()->Close();
    131   }
    132 }
    133 
    134 // static
    135 void BrowserList::CloseAllBrowsersWithProfile(Profile* profile,
    136     const base::Callback<void(const base::FilePath&)>& on_close_success) {
    137   BrowserVector browsers_to_close;
    138   for (chrome::BrowserIterator it; !it.done(); it.Next()) {
    139     if (it->profile()->GetOriginalProfile() == profile->GetOriginalProfile())
    140       browsers_to_close.push_back(*it);
    141   }
    142 
    143   TryToCloseBrowserList(browsers_to_close,
    144                         on_close_success,
    145                         profile->GetPath());
    146 }
    147 
    148 // static
    149 void BrowserList::TryToCloseBrowserList(const BrowserVector& browsers_to_close,
    150     const base::Callback<void(const base::FilePath&)>& on_close_success,
    151     const base::FilePath& profile_path) {
    152   for (BrowserVector::const_iterator it = browsers_to_close.begin();
    153        it != browsers_to_close.end(); ++it) {
    154     if ((*it)->CallBeforeUnloadHandlers(
    155             base::Bind(&BrowserList::PostBeforeUnloadHandlers,
    156                        browsers_to_close,
    157                        on_close_success,
    158                        profile_path))) {
    159       return;
    160     }
    161   }
    162 
    163   on_close_success.Run(profile_path);
    164 
    165   for (Browser* b : browsers_to_close) {
    166     // BeforeUnload handlers may close browser windows, so we need to explicitly
    167     // check whether they still exist.
    168     if (b->window())
    169       b->window()->Close();
    170   }
    171 }
    172 
    173 // static
    174 void BrowserList::PostBeforeUnloadHandlers(
    175     const BrowserVector& browsers_to_close,
    176     const base::Callback<void(const base::FilePath&)>& on_close_success,
    177     const base::FilePath& profile_path,
    178     bool tab_close_confirmed) {
    179   // We need this bool to avoid infinite recursion when resetting the
    180   // BeforeUnload handlers, since doing that will trigger calls back to this
    181   // method for each affected window.
    182   static bool resetting_handlers = false;
    183 
    184   if (tab_close_confirmed) {
    185     TryToCloseBrowserList(browsers_to_close, on_close_success, profile_path);
    186   } else if (!resetting_handlers) {
    187     base::AutoReset<bool> resetting_handlers_scoper(&resetting_handlers, true);
    188     for (BrowserVector::const_iterator it = browsers_to_close.begin();
    189          it != browsers_to_close.end(); ++it) {
    190       (*it)->ResetBeforeUnloadHandlers();
    191     }
    192   }
    193 }
    194 
    195 // static
    196 void BrowserList::SetLastActive(Browser* browser) {
    197   content::RecordAction(UserMetricsAction("ActiveBrowserChanged"));
    198   BrowserList* browser_list = GetInstance(browser->host_desktop_type());
    199 
    200   RemoveBrowserFrom(browser, &browser_list->last_active_browsers_);
    201   browser_list->last_active_browsers_.push_back(browser);
    202 
    203   FOR_EACH_OBSERVER(chrome::BrowserListObserver, observers_.Get(),
    204                     OnBrowserSetLastActive(browser));
    205 }
    206 
    207 // static
    208 bool BrowserList::IsOffTheRecordSessionActive() {
    209   for (chrome::BrowserIterator it; !it.done(); it.Next()) {
    210     if (it->profile()->IsOffTheRecord())
    211       return true;
    212   }
    213   return false;
    214 }
    215 
    216 // static
    217 bool BrowserList::IsOffTheRecordSessionActiveForProfile(Profile* profile) {
    218   if (profile->IsGuestSession())
    219     return true;
    220   for (chrome::BrowserIterator it; !it.done(); it.Next()) {
    221     if (it->profile()->IsSameProfile(profile) &&
    222         it->profile()->IsOffTheRecord()) {
    223       return true;
    224     }
    225   }
    226   return false;
    227 }
    228 
    229 ////////////////////////////////////////////////////////////////////////////////
    230 // BrowserList, private:
    231 
    232 BrowserList::BrowserList() {
    233 }
    234 
    235 BrowserList::~BrowserList() {
    236 }
    237 
    238 // static
    239 void BrowserList::RemoveBrowserFrom(Browser* browser,
    240                                     BrowserVector* browser_list) {
    241   BrowserVector::iterator remove_browser =
    242       std::find(browser_list->begin(), browser_list->end(), browser);
    243   if (remove_browser != browser_list->end())
    244     browser_list->erase(remove_browser);
    245 }
    246