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) 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::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