| Index: chrome/browser/sessions/tab_restore_service.cc
|
| ===================================================================
|
| --- chrome/browser/sessions/tab_restore_service.cc (revision 7147)
|
| +++ chrome/browser/sessions/tab_restore_service.cc (working copy)
|
| @@ -12,6 +12,7 @@
|
| #include "chrome/browser/navigation_entry.h"
|
| #include "chrome/browser/profile.h"
|
| #include "chrome/browser/sessions/session_backend.h"
|
| +#include "chrome/browser/sessions/session_service.h"
|
| #include "chrome/common/scoped_vector.h"
|
| #include "chrome/common/stl_util-inl.h"
|
|
|
| @@ -28,8 +29,8 @@
|
|
|
| // TabRestoreService ----------------------------------------------------------
|
|
|
| -// Max number of entries we'll keep around.
|
| -static const size_t kMaxEntries = 10;
|
| +// static
|
| +const size_t TabRestoreService::kMaxEntries = 10;
|
|
|
| // Identifier for commands written to file.
|
| // The ordering in the file is as follows:
|
| @@ -64,7 +65,7 @@
|
| int32 num_tabs;
|
| };
|
|
|
| -// Paylowed used for the start of a tab close.
|
| +// Payload used for the start of a tab close.
|
| struct SelectedNavigationInTabPayload {
|
| SessionID::id_type id;
|
| int32 index;
|
| @@ -92,7 +93,7 @@
|
| TabRestoreService::TabRestoreService(Profile* profile)
|
| : BaseSessionService(BaseSessionService::TAB_RESTORE, profile,
|
| std::wstring()),
|
| - loaded_last_session_(false),
|
| + load_state_(NOT_LOADED),
|
| restoring_(false),
|
| reached_max_(false),
|
| entries_to_write_(0),
|
| @@ -105,6 +106,7 @@
|
|
|
| FOR_EACH_OBSERVER(Observer, observer_list_, TabRestoreServiceDestroyed(this));
|
| STLDeleteElements(&entries_);
|
| + STLDeleteElements(&staging_entries_);
|
| }
|
|
|
| void TabRestoreService::AddObserver(Observer* observer) {
|
| @@ -242,15 +244,30 @@
|
| }
|
|
|
| void TabRestoreService::LoadTabsFromLastSession() {
|
| - if (loaded_last_session_ || reached_max_)
|
| + if (load_state_ != NOT_LOADED || reached_max_)
|
| return;
|
|
|
| - loaded_last_session_ = true;
|
| + load_state_ = LOADING;
|
|
|
| + if (!profile()->restored_last_session() &&
|
| + !profile()->DidLastSessionExitCleanly() &&
|
| + profile()->GetSessionService()) {
|
| + // The previous session crashed and wasn't restored. Load the tabs/windows
|
| + // that were open at the point of crash from the session service.
|
| + profile()->GetSessionService()->GetLastSession(
|
| + &load_consumer_,
|
| + NewCallback(this, &TabRestoreService::OnGotPreviousSession));
|
| + } else {
|
| + load_state_ |= LOADED_LAST_SESSION;
|
| + }
|
| +
|
| + // Request the tabs closed in the last session. If the last session crashed,
|
| + // this won't contain the tabs/window that were open at the point of the
|
| + // crash (the call to GetLastSession above requests those).
|
| ScheduleGetLastSessionCommands(
|
| new InternalGetCommandsRequest(
|
| NewCallback(this, &TabRestoreService::OnGotLastSessionCommands)),
|
| - &load_tabs_consumer_);
|
| + &load_consumer_);
|
| }
|
|
|
| void TabRestoreService::Save() {
|
| @@ -466,6 +483,18 @@
|
| void TabRestoreService::OnGotLastSessionCommands(
|
| Handle handle,
|
| scoped_refptr<InternalGetCommandsRequest> request) {
|
| + std::vector<Entry*> entries;
|
| + CreateEntriesFromCommands(request, &entries);
|
| + // Closed tabs always go to the end.
|
| + staging_entries_.insert(staging_entries_.end(), entries.begin(),
|
| + entries.end());
|
| + load_state_ |= LOADED_LAST_TABS;
|
| + LoadStateChanged();
|
| +}
|
| +
|
| +void TabRestoreService::CreateEntriesFromCommands(
|
| + scoped_refptr<InternalGetCommandsRequest> request,
|
| + std::vector<Entry*>* loaded_entries) {
|
| if (request->canceled() || entries_.size() == kMaxEntries)
|
| return;
|
|
|
| @@ -575,23 +604,7 @@
|
| // entries with no navigations.
|
| ValidateAndDeleteEmptyEntries(&(entries.get()));
|
|
|
| - if (entries->empty())
|
| - return;
|
| -
|
| - // And add them.
|
| - for (size_t i = 0; i < entries->size(); ++i)
|
| - AddEntry(entries[i], false, false);
|
| -
|
| - // AddEntry takes ownership of the entry, need to clear out entries so that
|
| - // it doesn't delete them.
|
| - entries->clear();
|
| -
|
| - // Make it so we rewrite all the tabs. We need to do this otherwise we won't
|
| - // correctly write out the entries when Save is invoked (Save starts from
|
| - // the front, not the end and we just added the entries to the end).
|
| - entries_to_write_ = entries_.size();
|
| -
|
| - PruneAndNotify();
|
| + loaded_entries->swap(entries.get());
|
| }
|
|
|
| bool TabRestoreService::ValidateTab(Tab* tab) {
|
| @@ -647,3 +660,90 @@
|
| // Delete the remaining entries.
|
| STLDeleteElements(&invalid_entries);
|
| }
|
| +
|
| +void TabRestoreService::OnGotPreviousSession(
|
| + Handle handle,
|
| + std::vector<SessionWindow*>* windows) {
|
| + std::vector<Entry*> entries;
|
| + CreateEntriesFromWindows(windows, &entries);
|
| + // Previous session tabs go first.
|
| + staging_entries_.insert(staging_entries_.begin(), entries.begin(),
|
| + entries.end());
|
| + load_state_ |= LOADED_LAST_SESSION;
|
| + LoadStateChanged();
|
| +}
|
| +
|
| +void TabRestoreService::CreateEntriesFromWindows(
|
| + std::vector<SessionWindow*>* windows,
|
| + std::vector<Entry*>* entries) {
|
| + for (size_t i = 0; i < windows->size(); ++i) {
|
| + scoped_ptr<Window> window(new Window());
|
| + if (ConvertSessionWindowToWindow((*windows)[i], window.get()))
|
| + entries->push_back(window.release());
|
| + }
|
| +}
|
| +
|
| +bool TabRestoreService::ConvertSessionWindowToWindow(
|
| + SessionWindow* session_window,
|
| + Window* window) {
|
| + for (size_t i = 0; i < session_window->tabs.size(); ++i) {
|
| + if (!session_window->tabs[i]->navigations.empty()) {
|
| + window->tabs.resize(window->tabs.size() + 1);
|
| + Tab& tab = window->tabs.back();
|
| + tab.navigations.swap(session_window->tabs[i]->navigations);
|
| + tab.current_navigation_index =
|
| + session_window->tabs[i]->current_navigation_index;
|
| + }
|
| + }
|
| + if (window->tabs.empty())
|
| + return false;
|
| +
|
| + window->selected_tab_index =
|
| + std::min(session_window->selected_tab_index,
|
| + static_cast<int>(window->tabs.size() - 1));
|
| + return true;
|
| +}
|
| +
|
| +void TabRestoreService::LoadStateChanged() {
|
| + if ((load_state_ & (LOADED_LAST_TABS | LOADED_LAST_SESSION)) !=
|
| + (LOADED_LAST_TABS | LOADED_LAST_SESSION)) {
|
| + // Still waiting on previous session or previous tabs.
|
| + return;
|
| + }
|
| +
|
| + // We're done loading.
|
| + load_state_ ^= LOADING;
|
| +
|
| + if (staging_entries_.empty() || reached_max_) {
|
| + STLDeleteElements(&staging_entries_);
|
| + return;
|
| + }
|
| +
|
| + if (staging_entries_.size() + entries_.size() > kMaxEntries) {
|
| + // If we add all the staged entries we'll end up with more than
|
| + // kMaxEntries. Delete entries such that we only end up with
|
| + // at most kMaxEntries.
|
| + DCHECK(entries_.size() < kMaxEntries);
|
| + STLDeleteContainerPointers(
|
| + staging_entries_.begin() + (kMaxEntries - entries_.size()),
|
| + staging_entries_.end());
|
| + staging_entries_.erase(
|
| + staging_entries_.begin() + (kMaxEntries - entries_.size()),
|
| + staging_entries_.end());
|
| + }
|
| +
|
| + // And add them.
|
| + for (size_t i = 0; i < staging_entries_.size(); ++i)
|
| + AddEntry(staging_entries_[i], false, false);
|
| +
|
| + // AddEntry takes ownership of the entry, need to clear out entries so that
|
| + // it doesn't delete them.
|
| + staging_entries_.clear();
|
| +
|
| + // Make it so we rewrite all the tabs. We need to do this otherwise we won't
|
| + // correctly write out the entries when Save is invoked (Save starts from
|
| + // the front, not the end and we just added the entries to the end).
|
| + entries_to_write_ = staging_entries_.size();
|
| +
|
| + PruneAndNotify();
|
| +}
|
|
|