1dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chromeos/tab_closeable_state_watcher.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
73345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/command_line.h"
83345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/browser_shutdown.h"
921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/tabs/tab_strip_model.h"
1121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/chrome_switches.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/url_constants.h"
14dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h"
15dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents_view.h"
16dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/common/notification_service.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace chromeos {
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch////////////////////////////////////////////////////////////////////////////////
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TabCloseableStateWatcher::TabStripWatcher, public:
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabCloseableStateWatcher::TabStripWatcher::TabStripWatcher(
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TabCloseableStateWatcher* main_watcher, const Browser* browser)
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : main_watcher_(main_watcher),
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      browser_(browser) {
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  browser_->tabstrip_model()->AddObserver(this);
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabCloseableStateWatcher::TabStripWatcher::~TabStripWatcher() {
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  browser_->tabstrip_model()->RemoveObserver(this);
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch////////////////////////////////////////////////////////////////////////////////
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TabCloseableStateWatcher::TabStripWatcher,
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//     TabStripModelObserver implementation:
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabCloseableStateWatcher::TabStripWatcher::TabInsertedAt(
39201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    TabContentsWrapper* tab_contents, int index, bool foreground) {
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  main_watcher_->OnTabStripChanged(browser_, false);
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabCloseableStateWatcher::TabStripWatcher::TabClosingAt(
44201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    TabStripModel* tab_strip_model,
45201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    TabContentsWrapper* tab_contents,
46201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    int index) {
47731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Check if the last tab is closing.
48731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (tab_strip_model->count() == 1)
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    main_watcher_->OnTabStripChanged(browser_, true);
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabCloseableStateWatcher::TabStripWatcher::TabDetachedAt(
53201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    TabContentsWrapper* tab_contents, int index) {
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  main_watcher_->OnTabStripChanged(browser_, false);
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabCloseableStateWatcher::TabStripWatcher::TabChangedAt(
58201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    TabContentsWrapper* tab_contents, int index, TabChangeType change_type) {
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  main_watcher_->OnTabStripChanged(browser_, false);
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch////////////////////////////////////////////////////////////////////////////////
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TabCloseableStateWatcher, public:
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabCloseableStateWatcher::TabCloseableStateWatcher()
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : can_close_tab_(true),
673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      signing_off_(false),
68731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      guest_session_(
69731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          CommandLine::ForCurrentProcess()->HasSwitch(
70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen              switches::kGuestSession)),
71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      waiting_for_browser_(false) {
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BrowserList::AddObserver(this);
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  notification_registrar_.Add(this, NotificationType::APP_EXITING,
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationService::AllSources());
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabCloseableStateWatcher::~TabCloseableStateWatcher() {
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BrowserList::RemoveObserver(this);
793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!browser_shutdown::ShuttingDownWithoutClosingBrowsers())
803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DCHECK(tabstrip_watchers_.empty());
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TabCloseableStateWatcher::CanCloseTab(const Browser* browser) const {
84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return browser->type() != Browser::TYPE_NORMAL ? true :
85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      (can_close_tab_ || waiting_for_browser_);
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TabCloseableStateWatcher::CanCloseBrowser(Browser* browser) {
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BrowserActionType action_type;
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool can_close = CanCloseBrowserImpl(browser, &action_type);
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (action_type == OPEN_WINDOW) {
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser->NewWindow();
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (action_type == OPEN_NTP) {
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // NTP will be opened before closing last tab (via TabStripModelObserver::
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TabClosingAt), close all tabs now.
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser->CloseAllTabs();
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return can_close;
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabCloseableStateWatcher::OnWindowCloseCanceled(Browser* browser) {
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This could be a call to cancel APP_EXITING if user doesn't proceed with
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // unloading handler.
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (signing_off_) {
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    signing_off_ = false;
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CheckAndUpdateState(browser);
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch////////////////////////////////////////////////////////////////////////////////
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TabCloseableStateWatcher, BrowserList::Observer implementation:
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabCloseableStateWatcher::OnBrowserAdded(const Browser* browser) {
114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  waiting_for_browser_ = false;
115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Only normal browsers may affect closeable state.
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (browser->type() != Browser::TYPE_NORMAL)
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Create TabStripWatcher to observe tabstrip of new browser.
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tabstrip_watchers_.push_back(new TabStripWatcher(this, browser));
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // When a normal browser is just added, there's no tabs yet, so we wait till
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TabInsertedAt notification to check for change in state.
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
127731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid TabCloseableStateWatcher::OnBrowserRemoved(const Browser* browser) {
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Only normal browsers may affect closeable state.
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (browser->type() != Browser::TYPE_NORMAL)
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Remove TabStripWatcher for browser that is being removed.
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::vector<TabStripWatcher*>::iterator it = tabstrip_watchers_.begin();
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       it != tabstrip_watchers_.end(); ++it) {
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if ((*it)->browser() == browser) {
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delete (*it);
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tabstrip_watchers_.erase(it);
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CheckAndUpdateState(NULL);
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch////////////////////////////////////////////////////////////////////////////////
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TabCloseableStateWatcher, NotificationObserver implementation:
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabCloseableStateWatcher::Observe(NotificationType type,
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const NotificationSource& source, const NotificationDetails& details) {
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (type.value != NotificationType::APP_EXITING)
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!signing_off_) {
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    signing_off_ = true;
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SetCloseableState(true);
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch////////////////////////////////////////////////////////////////////////////////
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TabCloseableStateWatcher, private
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabCloseableStateWatcher::OnTabStripChanged(const Browser* browser,
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool closing_last_tab) {
163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (waiting_for_browser_)
164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
165ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!closing_last_tab) {
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CheckAndUpdateState(browser);
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Before closing last tab, open new window or NTP if necessary.
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BrowserActionType action_type;
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CanCloseBrowserImpl(browser, &action_type);
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (action_type != NONE) {
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Browser* mutable_browser = const_cast<Browser*>(browser);
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (action_type == OPEN_WINDOW)
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      mutable_browser->NewWindow();
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else if (action_type == OPEN_NTP)
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      mutable_browser->NewTab();
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabCloseableStateWatcher::CheckAndUpdateState(
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const Browser* browser_to_check) {
185ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (waiting_for_browser_ || signing_off_ || tabstrip_watchers_.empty() ||
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      (browser_to_check && browser_to_check->type() != Browser::TYPE_NORMAL))
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool new_can_close;
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (tabstrip_watchers_.size() > 1) {
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    new_can_close = true;
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {  // There's only 1 normal browser.
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!browser_to_check)
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      browser_to_check = tabstrip_watchers_[0]->browser();
196731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (browser_to_check->profile()->IsOffTheRecord() && !guest_session_) {
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new_can_close = true;
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      TabStripModel* tabstrip_model = browser_to_check->tabstrip_model();
200731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      if (tabstrip_model->count() == 1) {
201201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        new_can_close =
202201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch            tabstrip_model->GetTabContentsAt(0)->tab_contents()->GetURL() !=
203201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                GURL(chrome::kChromeUINewTabURL);  // Tab is not NewTabPage.
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new_can_close = true;
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SetCloseableState(new_can_close);
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabCloseableStateWatcher::SetCloseableState(bool closeable) {
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (can_close_tab_ == closeable)  // No change in state.
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  can_close_tab_ = closeable;
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Notify of change in tab closeable state.
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotificationService::current()->Notify(
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationType::TAB_CLOSEABLE_STATE_CHANGED,
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationService::AllSources(),
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Details<bool>(&can_close_tab_));
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
226ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool TabCloseableStateWatcher::CanCloseBrowserImpl(
227ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const Browser* browser,
228ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    BrowserActionType* action_type) {
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *action_type = NONE;
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
231ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // If we're waiting for a new browser allow the close.
232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (waiting_for_browser_)
233ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return true;
234ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Browser is always closeable when signing off.
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (signing_off_)
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Non-normal browsers are always closeable.
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (browser->type() != Browser::TYPE_NORMAL)
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If this is not the last normal browser, it's always closeable.
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (tabstrip_watchers_.size() > 1)
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
247ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // If last normal browser is incognito, open a non-incognito window, and allow
248ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // closing of incognito one (if not guest). When this happens we need to wait
249ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // for the new browser before doing any other actions as the new browser may
250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // be created by way of session restore, which is async.
251731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (browser->profile()->IsOffTheRecord() && !guest_session_) {
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *action_type = OPEN_WINDOW;
253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    waiting_for_browser_ = true;
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If tab is not closeable, browser is not closeable.
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!can_close_tab_)
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Otherwise, close existing tabs, and deny closing of browser.
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TabClosingAt will open NTP when the last tab is being closed.
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *action_type = OPEN_NTP;
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace chromeos
268