diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-10 20:30:10 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-10 20:30:10 +0000 |
commit | fca656cb7bd5737a18c809d8f44edc6a99e6bb9a (patch) | |
tree | 477a3061a64a4f845642c7de780864214201e3f0 /chrome/browser | |
parent | 381f69ad5478d24e5bbb448727c05379204c87d3 (diff) | |
download | chromium_src-fca656cb7bd5737a18c809d8f44edc6a99e6bb9a.zip chromium_src-fca656cb7bd5737a18c809d8f44edc6a99e6bb9a.tar.gz chromium_src-fca656cb7bd5737a18c809d8f44edc6a99e6bb9a.tar.bz2 |
Adds code to restore application extensions. I'm also enabling tab
pinning on views again as everything in place, except a couple of
bugs.
BUG=32845
TEST=none
Review URL: http://codereview.chromium.org/598027
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@38657 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/browser.cc | 21 | ||||
-rw-r--r-- | chrome/browser/browser.h | 17 | ||||
-rw-r--r-- | chrome/browser/defaults.cc | 6 | ||||
-rw-r--r-- | chrome/browser/defaults.h | 5 | ||||
-rw-r--r-- | chrome/browser/sessions/base_session_service.cc | 32 | ||||
-rw-r--r-- | chrome/browser/sessions/base_session_service.h | 14 | ||||
-rw-r--r-- | chrome/browser/sessions/session_restore.cc | 69 | ||||
-rw-r--r-- | chrome/browser/sessions/session_service.cc | 60 | ||||
-rw-r--r-- | chrome/browser/sessions/session_service.h | 5 | ||||
-rw-r--r-- | chrome/browser/sessions/session_service_test_helper.cc | 7 | ||||
-rw-r--r-- | chrome/browser/sessions/session_service_test_helper.h | 4 | ||||
-rw-r--r-- | chrome/browser/sessions/session_service_unittest.cc | 30 | ||||
-rw-r--r-- | chrome/browser/sessions/session_types.h | 3 | ||||
-rw-r--r-- | chrome/browser/sessions/tab_restore_service.cc | 42 | ||||
-rw-r--r-- | chrome/browser/sessions/tab_restore_service.h | 3 | ||||
-rw-r--r-- | chrome/browser/sessions/tab_restore_service_unittest.cc | 15 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents.cc | 5 | ||||
-rw-r--r-- | chrome/browser/tab_menu_model.cc | 13 |
18 files changed, 322 insertions, 29 deletions
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index 2e6e0d0..0de4558 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -671,11 +671,13 @@ TabContents* Browser::AddRestoredTab( const std::vector<TabNavigation>& navigations, int tab_index, int selected_navigation, + const std::string& app_extension_id, bool select, bool pin, bool from_last_session) { TabContents* new_tab = new TabContents(profile(), NULL, MSG_ROUTING_NONE, tabstrip_model_.GetSelectedTabContents()); + SetAppExtensionById(new_tab, app_extension_id); new_tab->controller().RestoreFromState(navigations, selected_navigation, from_last_session); @@ -697,9 +699,11 @@ TabContents* Browser::AddRestoredTab( void Browser::ReplaceRestoredTab( const std::vector<TabNavigation>& navigations, int selected_navigation, - bool from_last_session) { + bool from_last_session, + const std::string& app_extension_id) { TabContents* replacement = new TabContents(profile(), NULL, MSG_ROUTING_NONE, tabstrip_model_.GetSelectedTabContents()); + SetAppExtensionById(replacement, app_extension_id); replacement->controller().RestoreFromState(navigations, selected_navigation, from_last_session); @@ -3262,3 +3266,18 @@ bool Browser::RunUnloadEventsHelper(TabContents* contents) { } return false; } + +void Browser::SetAppExtensionById(TabContents* contents, + const std::string& app_extension_id) { + if (app_extension_id.empty()) + return; + + ExtensionsService* extension_service = profile()->GetExtensionsService(); + if (extension_service && extension_service->is_ready()) { + Extension* extension = + extension_service->GetExtensionById(app_extension_id, false); + if (extension) + contents->SetAppExtension(extension); + } +} + diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h index e7123c8..bee4138 100644 --- a/chrome/browser/browser.h +++ b/chrome/browser/browser.h @@ -279,12 +279,15 @@ class Browser : public TabStripModelDelegate, // Add a tab with its session history restored from the SessionRestore // system. If select is true, the tab is selected. |tab_index| gives the index // to insert the tab at. |selected_navigation| is the index of the - // TabNavigation in |navigations| to select. If |pin| is true and |tab_index| - // is the last pinned tab, then the newly created tab is pinned. If - // |from_last_session| is true, |navigations| are from the previous session. + // TabNavigation in |navigations| to select. If |app_extension_id| is + // non-empty the tab is an app tab and |app_extension_id| is the id of the + // extension. If |pin| is true and |tab_index|/ is the last pinned tab, then + // the newly created tab is pinned. If |from_last_session| is true, + // |navigations| are from the previous session. TabContents* AddRestoredTab(const std::vector<TabNavigation>& navigations, int tab_index, int selected_navigation, + const std::string& app_extension_id, bool select, bool pin, bool from_last_session); @@ -321,7 +324,8 @@ class Browser : public TabStripModelDelegate, void ReplaceRestoredTab( const std::vector<TabNavigation>& navigations, int selected_navigation, - bool from_last_session); + bool from_last_session, + const std::string& app_extension_id); // Returns true if a tab can be restored. virtual bool CanRestoreTab(); @@ -764,6 +768,11 @@ class Browser : public TabStripModelDelegate, // done only once per application name / per session. static void RegisterAppPrefs(const std::wstring& app_name); + // If |app_extension_id| is not empty this sets the application extension of + // |contents| to the extension whose id is |app_extension_id|. + void SetAppExtensionById(TabContents* contents, + const std::string& app_extension_id); + // Data members ///////////////////////////////////////////////////////////// NotificationRegistrar registrar_; diff --git a/chrome/browser/defaults.cc b/chrome/browser/defaults.cc index 544041d..16017ab 100644 --- a/chrome/browser/defaults.cc +++ b/chrome/browser/defaults.cc @@ -45,6 +45,12 @@ const bool kCanToggleSystemTitleBar = true; #endif +#if defined(TOOLKIT_VIEWS) +const bool kEnablePinnedTabs = true; +#else +const bool kEnablePinnedTabs = false; +#endif + #if !defined(OS_CHROMEOS) const SessionStartupPref::Type kDefaultSessionStartupType = diff --git a/chrome/browser/defaults.h b/chrome/browser/defaults.h index f4ebe02a..c2e2c1d 100644 --- a/chrome/browser/defaults.h +++ b/chrome/browser/defaults.h @@ -64,6 +64,11 @@ extern const bool kSizeTabButtonToTopOfTabStrip; // asking the user for credentials. extern const bool kBootstrapSyncAuthentication; +// Are pinned tabs enabled? +// TODO: if you're the last to make this true on all platforms, remove the +// field. +extern const bool kEnablePinnedTabs; + } // namespace browser_defaults #endif // CHROME_BROWSER_DEFAULTS_H_ diff --git a/chrome/browser/sessions/base_session_service.cc b/chrome/browser/sessions/base_session_service.cc index 64b3949..a8be23d 100644 --- a/chrome/browser/sessions/base_session_service.cc +++ b/chrome/browser/sessions/base_session_service.cc @@ -180,6 +180,25 @@ SessionCommand* BaseSessionService::CreateUpdateTabNavigationCommand( return new SessionCommand(command_id, pickle); } +SessionCommand* BaseSessionService::CreateSetTabAppExtensionIDCommand( + SessionID::id_type command_id, + SessionID::id_type tab_id, + const std::string& extension_id) { + // Use pickle to handle marshalling. + Pickle pickle; + pickle.WriteInt(tab_id); + + // Enforce a max for ids. They should never be anywhere near this size. + static const SessionCommand::size_type max_id_size = + std::numeric_limits<SessionCommand::size_type>::max() - 1024; + + int bytes_written = 0; + + WriteStringToPickle(pickle, &bytes_written, max_id_size, extension_id); + + return new SessionCommand(command_id, pickle); +} + bool BaseSessionService::RestoreUpdateTabNavigationCommand( const SessionCommand& command, TabNavigation* navigation, @@ -214,6 +233,19 @@ bool BaseSessionService::RestoreUpdateTabNavigationCommand( return true; } +bool BaseSessionService::RestoreSetTabAppExtensionIDCommand( + const SessionCommand& command, + SessionID::id_type* tab_id, + std::string* app_extension_id) { + scoped_ptr<Pickle> pickle(command.PayloadAsPickle()); + if (!pickle.get()) + return false; + + void* iterator = NULL; + return pickle->ReadInt(&iterator, tab_id) && + pickle->ReadString(&iterator, app_extension_id); +} + bool BaseSessionService::ShouldTrackEntry(const NavigationEntry& entry) { return entry.virtual_url().is_valid(); } diff --git a/chrome/browser/sessions/base_session_service.h b/chrome/browser/sessions/base_session_service.h index ae4cbce..b311fd8 100644 --- a/chrome/browser/sessions/base_session_service.h +++ b/chrome/browser/sessions/base_session_service.h @@ -119,6 +119,12 @@ class BaseSessionService : public CancelableRequestProvider, int index, const NavigationEntry& entry); + // Creates a SessionCommand that represents marking a tab as an application. + SessionCommand* CreateSetTabAppExtensionIDCommand( + SessionID::id_type command_id, + SessionID::id_type tab_id, + const std::string& extension_id); + // Converts a SessionCommand previously created by // CreateUpdateTabNavigationCommand into a TabNavigation. Returns true // on success. If successful |tab_id| is set to the id of the restored tab. @@ -126,6 +132,14 @@ class BaseSessionService : public CancelableRequestProvider, TabNavigation* navigation, SessionID::id_type* tab_id); + // Extracts a SessionCommand as previously created by + // CreateSetTabAppExtensionIDCommand into the tab id and application + // extension id. + bool RestoreSetTabAppExtensionIDCommand( + const SessionCommand& command, + SessionID::id_type* tab_id, + std::string* app_extension_id); + // Returns true if the NavigationEntry should be written to disk. bool ShouldTrackEntry(const NavigationEntry& entry); diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc index f450013..58be396 100644 --- a/chrome/browser/sessions/session_restore.cc +++ b/chrome/browser/sessions/session_restore.cc @@ -14,6 +14,7 @@ #include "chrome/browser/browser_list.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_window.h" +#include "chrome/browser/extensions/extensions_service.h" #include "chrome/browser/profile.h" #include "chrome/browser/sessions/session_service.h" #include "chrome/browser/sessions/session_types.h" @@ -180,7 +181,8 @@ class SessionRestoreImpl : public NotificationObserver { synchronous_(synchronous), clobber_existing_window_(clobber_existing_window), always_create_tabbed_browser_(always_create_tabbed_browser), - urls_to_open_(urls_to_open) { + urls_to_open_(urls_to_open), + waiting_for_extension_service_(false) { } void Restore() { @@ -210,11 +212,28 @@ class SessionRestoreImpl : public NotificationObserver { virtual void Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { - if (type != NotificationType::BROWSER_CLOSED) { - NOTREACHED(); - return; + switch (type.value) { + case NotificationType::BROWSER_CLOSED: + delete this; + return; + + case NotificationType::EXTENSIONS_READY: { + if (!waiting_for_extension_service_) + return; + + waiting_for_extension_service_ = false; + if (synchronous_) { + MessageLoop::current()->Quit(); + return; + } + ProcessSessionWindows(&windows_); + return; + } + + default: + NOTREACHED(); + break; } - delete this; } private: @@ -255,15 +274,50 @@ class SessionRestoreImpl : public NotificationObserver { void OnGotSession(SessionService::Handle handle, std::vector<SessionWindow*>* windows) { + if (HasAppExtensions(*windows) && profile_->GetExtensionsService() && + !profile_->GetExtensionsService()->is_ready()) { + // At least one tab is an app tab and the extension service hasn't + // finished loading. Wait to continue processing until the extensions + // service finishes loading. + registrar_.Add(this, NotificationType::EXTENSIONS_READY, + Source<Profile>(profile_)); + windows_.swap(*windows); + waiting_for_extension_service_ = true; + return; + } + if (synchronous_) { // See comment above windows_ as to why we don't process immediately. windows_.swap(*windows); MessageLoop::current()->Quit(); return; } + ProcessSessionWindows(windows); } + // Returns true if any tab in |windows| has an application extension id. + bool HasAppExtensions(const std::vector<SessionWindow*>& windows) { + for (std::vector<SessionWindow*>::const_iterator i = windows.begin(); + i != windows.end(); ++i) { + if (HasAppExtensions((*i)->tabs)) + return true; + } + + return false; + } + + // Returns true if any tab in |tabs| has an application extension id. + bool HasAppExtensions(const std::vector<SessionTab*>& tabs) { + for (std::vector<SessionTab*>::const_iterator i = tabs.begin(); + i != tabs.end(); ++i) { + if (!(*i)->app_extension_id.empty()) + return true; + } + + return false; + } + void ProcessSessionWindows(std::vector<SessionWindow*>* windows) { if (windows->empty()) { // Restore was unsuccessful. @@ -340,6 +394,7 @@ class SessionRestoreImpl : public NotificationObserver { &browser->AddRestoredTab(tab.navigations, static_cast<int>(i - window.tabs.begin()), selected_index, + tab.app_extension_id, false, tab.pinned, true)->controller()); @@ -415,6 +470,10 @@ class SessionRestoreImpl : public NotificationObserver { // windows when the nested message loop exits. std::vector<SessionWindow*> windows_; + // If true, indicates at least one tab has an application extension id and + // we're waiting for the extension service to finish loading. + bool waiting_for_extension_service_; + NotificationRegistrar registrar_; }; diff --git a/chrome/browser/sessions/session_service.cc b/chrome/browser/sessions/session_service.cc index 58dcd1a..73689d4 100644 --- a/chrome/browser/sessions/session_service.cc +++ b/chrome/browser/sessions/session_service.cc @@ -17,6 +17,7 @@ #include "chrome/browser/browser_list.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_window.h" +#include "chrome/browser/defaults.h" #include "chrome/browser/profile.h" #include "chrome/browser/session_startup_pref.h" #include "chrome/browser/sessions/session_backend.h" @@ -26,6 +27,7 @@ #include "chrome/browser/tab_contents/navigation_controller.h" #include "chrome/browser/tab_contents/navigation_entry.h" #include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/common/extensions/extension.h" #include "chrome/common/notification_details.h" #include "chrome/common/notification_service.h" @@ -53,6 +55,7 @@ static const SessionCommand::id_type kCommandSetWindowBounds2 = 10; static const SessionCommand::id_type kCommandTabNavigationPathPrunedFromFront = 11; static const SessionCommand::id_type kCommandSetPinnedState = 12; +static const SessionCommand::id_type kCommandSetAppExtensionID = 13; // Every kWritesPerReset commands triggers recreating the file. static const int kWritesPerReset = 250; @@ -402,6 +405,9 @@ void SessionService::Init() { NotificationService::AllSources()); registrar_.Add(this, NotificationType::BROWSER_OPENED, NotificationService::AllSources()); + registrar_.Add(this, + NotificationType::TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED, + NotificationService::AllSources()); } void SessionService::Observe(NotificationType type, @@ -445,6 +451,12 @@ void SessionService::Observe(NotificationType type, NavigationController* controller = Source<NavigationController>(source).ptr(); SetTabWindow(controller->window_id(), controller->session_id()); + if (controller->tab_contents()->app_extension()) { + SetTabAppExtensionID( + controller->window_id(), + controller->session_id(), + controller->tab_contents()->app_extension()->id()); + } break; } @@ -493,11 +505,35 @@ void SessionService::Observe(NotificationType type, break; } + case NotificationType::TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED: { + TabContents* tab_contents = Source<TabContents>(source).ptr(); + DCHECK(tab_contents); + if (tab_contents->app_extension()) { + SetTabAppExtensionID(tab_contents->controller().window_id(), + tab_contents->controller().session_id(), + tab_contents->app_extension()->id()); + } + break; + } + default: NOTREACHED(); } } +void SessionService::SetTabAppExtensionID( + const SessionID& window_id, + const SessionID& tab_id, + const std::string& app_extension_id) { + if (!ShouldTrackChangesToWindow(window_id)) + return; + + ScheduleCommand(CreateSetTabAppExtensionIDCommand( + kCommandSetAppExtensionID, + tab_id.id(), + app_extension_id)); +} + SessionCommand* SessionService::CreateSetSelectedTabInWindow( const SessionID& window_id, int index) { @@ -910,9 +946,20 @@ bool SessionService::CreateTabsAndWindows( PinnedStatePayload payload; if (!command->GetPayload(&payload, sizeof(payload))) return true; -#if defined(ENABLE_PINNED_TABS) - GetTab(payload.tab_id, tabs)->pinned = payload.pinned_state; -#endif + if (browser_defaults::kEnablePinnedTabs) + GetTab(payload.tab_id, tabs)->pinned = payload.pinned_state; + break; + } + + case kCommandSetAppExtensionID: { + SessionID::id_type tab_id; + std::string app_extension_id; + if (!RestoreSetTabAppExtensionIDCommand( + *command, &tab_id, &app_extension_id)) { + return true; + } + + GetTab(tab_id, tabs)->app_extension_id.swap(app_extension_id); break; } @@ -947,6 +994,13 @@ void SessionService::BuildCommandsForTab( commands->push_back( CreatePinnedStateCommand(controller->session_id(), true)); } + if (controller->tab_contents()->app_extension()) { + commands->push_back( + CreateSetTabAppExtensionIDCommand( + kCommandSetAppExtensionID, + controller->session_id().id(), + controller->tab_contents()->app_extension()->id())); + } for (int i = min_index; i < max_index; ++i) { const NavigationEntry* entry = (i == pending_index) ? controller->pending_entry() : controller->GetEntryAtIndex(i); diff --git a/chrome/browser/sessions/session_service.h b/chrome/browser/sessions/session_service.h index 5ec3783..940824e 100644 --- a/chrome/browser/sessions/session_service.h +++ b/chrome/browser/sessions/session_service.h @@ -173,6 +173,11 @@ class SessionService : public BaseSessionService, const NotificationSource& source, const NotificationDetails& details); + // Sets the application extension id of the specified tab. + void SetTabAppExtensionID(const SessionID& window_id, + const SessionID& tab_id, + const std::string& app_extension_id); + // Methods to create the various commands. It is up to the caller to delete // the returned the SessionCommand* object. SessionCommand* CreateSetSelectedTabInWindow(const SessionID& window_id, diff --git a/chrome/browser/sessions/session_service_test_helper.cc b/chrome/browser/sessions/session_service_test_helper.cc index 871c222..7703bc8 100644 --- a/chrome/browser/sessions/session_service_test_helper.cc +++ b/chrome/browser/sessions/session_service_test_helper.cc @@ -29,6 +29,13 @@ void SessionServiceTestHelper::PrepareTabInWindow(const SessionID& window_id, service()->SetSelectedTabInWindow(window_id, visual_index); } +void SessionServiceTestHelper::SetTabAppExtensionID( + const SessionID& window_id, + const SessionID& tab_id, + const std::string& app_extension_id) { + service()->SetTabAppExtensionID(window_id, tab_id, app_extension_id); +} + // Be sure and null out service to force closing the file. void SessionServiceTestHelper::ReadWindows( std::vector<SessionWindow*>* windows) { diff --git a/chrome/browser/sessions/session_service_test_helper.h b/chrome/browser/sessions/session_service_test_helper.h index 0f04635..869ca50a 100644 --- a/chrome/browser/sessions/session_service_test_helper.h +++ b/chrome/browser/sessions/session_service_test_helper.h @@ -34,6 +34,10 @@ class SessionServiceTestHelper { int visual_index, bool select); + void SetTabAppExtensionID(const SessionID& window_id, + const SessionID& tab_id, + const std::string& app_extension_id); + // Reads the contents of the last session. void ReadWindows(std::vector<SessionWindow*>* windows); diff --git a/chrome/browser/sessions/session_service_unittest.cc b/chrome/browser/sessions/session_service_unittest.cc index 25fc8ad..8d2a9da 100644 --- a/chrome/browser/sessions/session_service_unittest.cc +++ b/chrome/browser/sessions/session_service_unittest.cc @@ -9,6 +9,7 @@ #include "base/stl_util-inl.h" #include "base/string_util.h" #include "base/time.h" +#include "chrome/browser/defaults.h" #include "chrome/browser/sessions/session_backend.h" #include "chrome/browser/sessions/session_service.h" #include "chrome/browser/sessions/session_service_test_helper.h" @@ -510,6 +511,9 @@ TEST_F(SessionServiceTest, PruneFromFront) { ASSERT_EQ(window_id.id(), windows[0]->window_id.id()); ASSERT_EQ(1U, windows[0]->tabs.size()); + // There shouldn't be an app id. + EXPECT_TRUE(windows[0]->tabs[0]->app_extension_id.empty()); + // We should be left with three navigations, the 2nd selected. SessionTab* tab = windows[0]->tabs[0]; ASSERT_EQ(1, tab->current_navigation_index); @@ -553,9 +557,31 @@ TEST_F(SessionServiceTest, PinnedFalseWhenSetToFalse) { EXPECT_FALSE(CreateAndWriteSessionWithOneTab(false, true)); } -#if defined(ENABLE_PINNED_TABS) +// Make sure application extension ids are persisted. +TEST_F(SessionServiceTest, PersistApplicationExtensionID) { + SessionID tab_id; + ASSERT_NE(window_id.id(), tab_id.id()); + std::string app_id("foo"); + + TabNavigation nav1(0, GURL("http://google.com"), GURL(), + ASCIIToUTF16("abc"), std::string(), + PageTransition::QUALIFIER_MASK); + + helper_.PrepareTabInWindow(window_id, tab_id, 0, true); + UpdateNavigation(window_id, tab_id, nav1, 0, true); + helper_.SetTabAppExtensionID(window_id, tab_id, app_id); + + ScopedVector<SessionWindow> windows; + ReadWindows(&(windows.get())); + + helper_.AssertSingleWindowWithSingleTab(windows.get(), 1); + EXPECT_TRUE(app_id == windows[0]->tabs[0]->app_extension_id); +} + // Explicitly set the pinned state to true and make sure we get back true. TEST_F(SessionServiceTest, PinnedTrue) { + if (!browser_defaults::kEnablePinnedTabs) + return; + EXPECT_TRUE(CreateAndWriteSessionWithOneTab(true, true)); } -#endif diff --git a/chrome/browser/sessions/session_types.h b/chrome/browser/sessions/session_types.h index 5841810..6bc0142 100644 --- a/chrome/browser/sessions/session_types.h +++ b/chrome/browser/sessions/session_types.h @@ -136,6 +136,9 @@ struct SessionTab { // True if the tab is pinned. bool pinned; + // If non-empty, this tab is an app tab and this is the id of the extension. + std::string app_extension_id; + std::vector<TabNavigation> navigations; private: diff --git a/chrome/browser/sessions/tab_restore_service.cc b/chrome/browser/sessions/tab_restore_service.cc index aeaceab..68ccc10 100644 --- a/chrome/browser/sessions/tab_restore_service.cc +++ b/chrome/browser/sessions/tab_restore_service.cc @@ -19,6 +19,7 @@ #include "chrome/browser/tab_contents/navigation_controller.h" #include "chrome/browser/tab_contents/navigation_entry.h" #include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/common/extensions/extension.h" using base::Time; @@ -47,8 +48,9 @@ const size_t TabRestoreService::kMaxEntries = 10; // . When the user closes a tab a command of type // kCommandSelectedNavigationInTab is written identifying the tab and // the selected index, then a kCommandPinnedState command if the tab was -// pinned. This is followed by any number of kCommandUpdateTabNavigation -// commands (1 per navigation entry). +// pinned and kCommandSetAppExtensionID if the tab has an app id. This is +// followed by any number of kCommandUpdateTabNavigation commands (1 per +// navigation entry). // . When the user closes a window a kCommandSelectedNavigationInTab command // is written out and followed by n tab closed sequences (as previoulsy // described). @@ -59,6 +61,7 @@ static const SessionCommand::id_type kCommandRestoredEntry = 2; static const SessionCommand::id_type kCommandWindow = 3; static const SessionCommand::id_type kCommandSelectedNavigationInTab = 4; static const SessionCommand::id_type kCommandPinnedState = 5; +static const SessionCommand::id_type kCommandSetAppExtensionID = 6; // Number of entries (not commands) before we clobber the file and write // everything. @@ -269,7 +272,8 @@ void TabRestoreService::RestoreEntryById(Browser* browser, if (replace_existing_tab && browser) { browser->ReplaceRestoredTab(tab->navigations, tab->current_navigation_index, - tab->from_last_session); + tab->from_last_session, + tab->app_extension_id); } else { // Use the tab's former browser and index, if available. Browser* tab_browser = NULL; @@ -291,8 +295,9 @@ void TabRestoreService::RestoreEntryById(Browser* browser, if (tab_index < 0 || tab_index > tab_browser->tab_count()) tab_index = tab_browser->tab_count(); tab_browser->AddRestoredTab(tab->navigations, tab_index, - tab->current_navigation_index, true, - tab->pinned, tab->from_last_session); + tab->current_navigation_index, + tab->app_extension_id, true, tab->pinned, + tab->from_last_session); } } else if (entry->type == WINDOW) { Browser* current_browser = browser; @@ -303,6 +308,7 @@ void TabRestoreService::RestoreEntryById(Browser* browser, TabContents* restored_tab = browser->AddRestoredTab(tab.navigations, browser->tab_count(), tab.current_navigation_index, + tab.app_extension_id, (static_cast<int>(tab_i) == window->selected_tab_index), tab.pinned, tab.from_last_session); @@ -407,6 +413,10 @@ void TabRestoreService::PopulateTab(Tab* tab, if (tab->current_navigation_index == -1 && entry_count > 0) tab->current_navigation_index = 0; + Extension* extension = controller->tab_contents()->app_extension(); + if (extension) + tab->app_extension_id = extension->id(); + // Browser may be NULL during unit tests. if (browser) { tab->browser_id = browser->session_id().id(); @@ -509,6 +519,12 @@ void TabRestoreService::ScheduleCommandsForTab(const Tab& tab, ScheduleCommand(command); } + if (!tab.app_extension_id.empty()) { + ScheduleCommand( + CreateSetTabAppExtensionIDCommand(kCommandSetAppExtensionID, tab.id, + tab.app_extension_id)); + } + // Then write the navigations. for (int i = first_index_to_persist, wrote_count = 0; i < max_index && wrote_count < 2 * max_persist_navigation_count; ++i) { @@ -740,6 +756,21 @@ void TabRestoreService::CreateEntriesFromCommands( break; } + case kCommandSetAppExtensionID: { + if (!current_tab) { + // Should be in a tab when we get this. + return; + } + SessionID::id_type tab_id; + std::string app_extension_id; + if (!RestoreSetTabAppExtensionIDCommand(command, &tab_id, + &app_extension_id)) { + return; + } + current_tab->app_extension_id.swap(app_extension_id); + break; + } + default: // Unknown type, usually indicates corruption of file. Ignore it. return; @@ -852,6 +883,7 @@ bool TabRestoreService::ConvertSessionWindowToWindow( tab.navigations.swap(session_window->tabs[i]->navigations); tab.current_navigation_index = session_window->tabs[i]->current_navigation_index; + tab.app_extension_id = session_window->tabs[i]->app_extension_id; tab.timestamp = Time(); } } diff --git a/chrome/browser/sessions/tab_restore_service.h b/chrome/browser/sessions/tab_restore_service.h index ce488be..f8488e1 100644 --- a/chrome/browser/sessions/tab_restore_service.h +++ b/chrome/browser/sessions/tab_restore_service.h @@ -99,6 +99,9 @@ class TabRestoreService : public BaseSessionService { // True if the tab was pinned. bool pinned; + + // If non-empty gives the id of the extension for the tab. + std::string app_extension_id; }; // Represents a previously open window. diff --git a/chrome/browser/sessions/tab_restore_service_unittest.cc b/chrome/browser/sessions/tab_restore_service_unittest.cc index 19f1056..1cc3bf1 100644 --- a/chrome/browser/sessions/tab_restore_service_unittest.cc +++ b/chrome/browser/sessions/tab_restore_service_unittest.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chrome/browser/defaults.h" #include "chrome/browser/renderer_host/test/test_render_view_host.h" #include "chrome/browser/sessions/session_types.h" #include "chrome/browser/sessions/session_service.h" @@ -126,6 +127,7 @@ TEST_F(TabRestoreServiceTest, Basic) { ASSERT_EQ(TabRestoreService::TAB, entry->type); TabRestoreService::Tab* tab = static_cast<TabRestoreService::Tab*>(entry); EXPECT_FALSE(tab->pinned); + EXPECT_TRUE(tab->app_extension_id.empty()); ASSERT_EQ(3U, tab->navigations.size()); EXPECT_TRUE(url1_ == tab->navigations[0].url()); EXPECT_TRUE(url2_ == tab->navigations[1].url()); @@ -191,7 +193,10 @@ TEST_F(TabRestoreServiceTest, Restore) { } // Tests restoring a single pinned tab. -TEST_F(TabRestoreServiceTest, RestorePinned) { +TEST_F(TabRestoreServiceTest, RestorePinnedAndApp) { + if (!browser_defaults::kEnablePinnedTabs) + return; + AddThreeNavigations(); // Have the service record the tab. @@ -206,6 +211,8 @@ TEST_F(TabRestoreServiceTest, RestorePinned) { ASSERT_EQ(TabRestoreService::TAB, entry->type); TabRestoreService::Tab* tab = static_cast<TabRestoreService::Tab*>(entry); tab->pinned = true; + const std::string app_extension_id("test"); + tab->app_extension_id = app_extension_id; // Recreate the service and have it load the tabs. RecreateService(); @@ -223,6 +230,7 @@ TEST_F(TabRestoreServiceTest, RestorePinned) { EXPECT_TRUE(url2_ == tab->navigations[1].url()); EXPECT_TRUE(url3_ == tab->navigations[2].url()); EXPECT_EQ(2, tab->current_navigation_index); + EXPECT_TRUE(app_extension_id == tab->app_extension_id); } // Make sure we persist entries to disk that have post data. @@ -363,9 +371,11 @@ TEST_F(TabRestoreServiceTest, LoadPreviousSessionAndTabs) { EXPECT_TRUE(url3_ == tab->navigations[2].url()); } -#if defined(ENABLE_PINNED_TABS) // Make sure pinned state is correctly loaded from session service. TEST_F(TabRestoreServiceTest, LoadPreviousSessionAndTabsPinned) { + if (!browser_defaults::kEnablePinnedTabs) + return; + CreateSessionServiceWithOneWindow(true); profile()->GetSessionService()->MoveCurrentSessionToLastSession(); @@ -402,7 +412,6 @@ TEST_F(TabRestoreServiceTest, LoadPreviousSessionAndTabsPinned) { EXPECT_TRUE(url2_ == tab->navigations[1].url()); EXPECT_TRUE(url3_ == tab->navigations[2].url()); } -#endif // Creates TabRestoreService::kMaxEntries + 1 windows in the session service // and makes sure we only get back TabRestoreService::kMaxEntries on restore. diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index 58eb083..704428d 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -462,6 +462,11 @@ RenderProcessHost* TabContents::GetRenderProcessHost() const { void TabContents::SetAppExtension(Extension* extension) { DCHECK(!extension || extension->IsApp()); app_extension_ = extension; + + NotificationService::current()->Notify( + NotificationType::TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED, + Source<TabContents>(this), + NotificationService::NoDetails()); } const GURL& TabContents::GetURL() const { diff --git a/chrome/browser/tab_menu_model.cc b/chrome/browser/tab_menu_model.cc index 986d352..f0fe251 100644 --- a/chrome/browser/tab_menu_model.cc +++ b/chrome/browser/tab_menu_model.cc @@ -4,6 +4,7 @@ #include "chrome/browser/tab_menu_model.h" +#include "chrome/browser/defaults.h" #include "chrome/browser/tabs/tab_strip_model.h" #include "grit/generated_resources.h" @@ -18,17 +19,17 @@ void TabMenuModel::Build() { AddItemWithStringId(TabStripModel::CommandReload, IDS_TAB_CXMENU_RELOAD); AddItemWithStringId(TabStripModel::CommandDuplicate, IDS_TAB_CXMENU_DUPLICATE); -#if defined(ENABLE_PINNED_TABS) + if (browser_defaults::kEnablePinnedTabs) { // On Mac the HIG prefers "pin/unpin" to a checkmark. The Mac code will fix up // the actual string based on the tab's state via the delegate. #if defined(OS_MACOSX) - AddItemWithStringId(TabStripModel::CommandTogglePinned, - IDS_TAB_CXMENU_PIN_TAB); + AddItemWithStringId(TabStripModel::CommandTogglePinned, + IDS_TAB_CXMENU_PIN_TAB); #else - AddCheckItemWithStringId(TabStripModel::CommandTogglePinned, - IDS_TAB_CXMENU_PIN_TAB); -#endif + AddCheckItemWithStringId(TabStripModel::CommandTogglePinned, + IDS_TAB_CXMENU_PIN_TAB); #endif + } AddSeparator(); AddItemWithStringId(TabStripModel::CommandCloseTab, IDS_TAB_CXMENU_CLOSETAB); |