browser_list.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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/browser_list.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <algorithm>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/browser_process.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/browser_shutdown.h"
127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/lifetime/application_lifetime.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/browser_finder.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/browser_iterator.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_list_observer.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/browser_window.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/host_desktop.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/notification_service.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/user_metrics.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_CHROMEOS)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/login/user_manager.h"
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using base::UserMetricsAction;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::WebContents;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::LazyInstance<ObserverList<chrome::BrowserListObserver> >::Leaky
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserList::observers_ = LAZY_INSTANCE_INITIALIZER;
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)BrowserList* BrowserList::native_instance_ = NULL;
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)BrowserList* BrowserList::ash_instance_ = NULL;
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// BrowserList, public:
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Browser* BrowserList::GetLastActive() const {
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!last_active_browsers_.empty())
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return *(last_active_browsers_.rbegin());
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return NULL;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)BrowserList* BrowserList::GetInstance(chrome::HostDesktopType type) {
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserList** list = NULL;
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (type == chrome::HOST_DESKTOP_TYPE_NATIVE)
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    list = &native_instance_;
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else if (type == chrome::HOST_DESKTOP_TYPE_ASH)
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    list = &ash_instance_;
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NOTREACHED();
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!*list)
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *list = new BrowserList;
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return *list;
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserList::AddBrowser(Browser* browser) {
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(browser);
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Push |browser| on the appropriate list instance.
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserList* browser_list = GetInstance(browser->host_desktop_type());
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  browser_list->browsers_.push_back(browser);
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  g_browser_process->AddRefModule();
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::NotificationService::current()->Notify(
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      chrome::NOTIFICATION_BROWSER_OPENED,
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      content::Source<Browser>(browser),
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      content::NotificationService::NoDetails());
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FOR_EACH_OBSERVER(chrome::BrowserListObserver, observers_.Get(),
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    OnBrowserAdded(browser));
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserList::RemoveBrowser(Browser* browser) {
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Remove |browser| from the appropriate list instance.
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserList* browser_list = GetInstance(browser->host_desktop_type());
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RemoveBrowserFrom(browser, &browser_list->last_active_browsers_);
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::NotificationService::current()->Notify(
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      chrome::NOTIFICATION_BROWSER_CLOSED,
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      content::Source<Browser>(browser),
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      content::NotificationService::NoDetails());
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RemoveBrowserFrom(browser, &browser_list->browsers_);
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FOR_EACH_OBSERVER(chrome::BrowserListObserver, observers_.Get(),
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    OnBrowserRemoved(browser));
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  g_browser_process->ReleaseModule();
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If we're exiting, send out the APP_TERMINATING notification to allow other
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // modules to shut themselves down.
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (chrome::GetTotalBrowserCount() == 0 &&
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (browser_shutdown::IsTryingToQuit() ||
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       g_browser_process->IsShuttingDown())) {
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Last browser has just closed, and this is a user-initiated quit or there
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // is no module keeping the app alive, so send out our notification. No need
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // to call ProfileManager::ShutdownSessionServices() as part of the
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // shutdown, because Browser::WindowClosing() already makes sure that the
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // SessionService is created and notified.
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    chrome::NotifyAppTerminating();
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    chrome::OnAppExiting();
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserList::AddObserver(chrome::BrowserListObserver* observer) {
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  observers_.Get().AddObserver(observer);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserList::RemoveObserver(chrome::BrowserListObserver* observer) {
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  observers_.Get().RemoveObserver(observer);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserList::CloseAllBrowsersWithProfile(Profile* profile) {
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserVector browsers_to_close;
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (it->profile()->GetOriginalProfile() == profile->GetOriginalProfile())
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      browsers_to_close.push_back(*it);
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (BrowserVector::const_iterator it = browsers_to_close.begin();
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != browsers_to_close.end(); ++it) {
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    (*it)->window()->Close();
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BrowserList::SetLastActive(Browser* browser) {
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::RecordAction(UserMetricsAction("ActiveBrowserChanged"));
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserList* browser_list = GetInstance(browser->host_desktop_type());
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RemoveBrowserFrom(browser, &browser_list->last_active_browsers_);
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  browser_list->last_active_browsers_.push_back(browser);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FOR_EACH_OBSERVER(chrome::BrowserListObserver, observers_.Get(),
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    OnBrowserSetLastActive(browser));
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BrowserList::IsOffTheRecordSessionActive() {
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (it->profile()->IsOffTheRecord())
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return true;
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BrowserList::IsOffTheRecordSessionActiveForProfile(Profile* profile) {
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  #if defined(OS_CHROMEOS)
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // In ChromeOS, we assume that the default profile is always valid, so if
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // we are in guest mode, keep the OTR profile active so it won't be deleted.
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (chromeos::UserManager::Get()->IsLoggedInAsGuest())
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (it->profile()->IsSameProfile(profile) &&
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        it->profile()->IsOffTheRecord()) {
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return true;
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// BrowserList, private:
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)BrowserList::BrowserList() {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)BrowserList::~BrowserList() {
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BrowserList::RemoveBrowserFrom(Browser* browser,
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    BrowserVector* browser_list) {
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserVector::iterator remove_browser =
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::find(browser_list->begin(), browser_list->end(), browser);
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (remove_browser != browser_list->end())
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    browser_list->erase(remove_browser);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
191