From f86df64b912f450fe3002ffb98510131cb4997dd Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Fri, 13 Nov 2015 14:27:24 +0100 Subject: [PATCH] Web+: implement a simple session management system. When quitting the app or closing the last window, all windows and tabs are stored in a "Session" file. This is reloaded when the browser starts, allowing to restore all windows and tabs. Limitations: the page content and navigation history are not saved. The file is written only at exit so this can't be used for crash recovery (but you can make a backup of your default session). Fixes #6680. --- src/apps/webpositive/BrowserApp.cpp | 80 +++++++++++++++++++++----- src/apps/webpositive/BrowserApp.h | 1 + src/apps/webpositive/BrowserWindow.cpp | 23 +++++++- src/apps/webpositive/BrowserWindow.h | 1 + 4 files changed, 89 insertions(+), 16 deletions(-) diff --git a/src/apps/webpositive/BrowserApp.cpp b/src/apps/webpositive/BrowserApp.cpp index 8140d4298f..6bacb3fc47 100644 --- a/src/apps/webpositive/BrowserApp.cpp +++ b/src/apps/webpositive/BrowserApp.cpp @@ -77,6 +77,7 @@ BrowserApp::BrowserApp() fInitialized(false), fSettings(NULL), fCookies(NULL), + fSession(NULL), fContext(NULL), fDownloadWindow(NULL), fSettingsWindow(NULL), @@ -92,6 +93,11 @@ BrowserApp::BrowserApp() fContext = new BUrlContext(); fContext->SetCookieJar(BNetworkCookieJar(&cookieArchive)); #endif + + BString sessionStorePath = kApplicationName; + sessionStorePath << "/Session"; + fSession = new SettingsMessage(B_USER_SETTINGS_DIRECTORY, + sessionStorePath.String()); } @@ -100,6 +106,7 @@ BrowserApp::~BrowserApp() delete fLaunchRefsMessage; delete fSettings; delete fCookies; + delete fSession; delete fContext; } @@ -223,6 +230,29 @@ BrowserApp::ReadyToRun() delete fLaunchRefsMessage; fLaunchRefsMessage = NULL; } + + BMessage archivedWindow; + for (int i = 0; fSession->FindMessage("window", i, &archivedWindow) == B_OK; + i++) { + + BRect frame = archivedWindow.FindRect("window frame"); + BString url; + archivedWindow.FindString("tab", 0, &url); + BrowserWindow* window = new(std::nothrow) BrowserWindow(frame, + fSettings, url, fContext); + + if (window != NULL) { + window->Show(); + + for (int j = 1; archivedWindow.FindString("tab", j, &url) == B_OK; + j++) { + printf("Create %d:%d\n", i, j); + _CreateNewTab(window, url, false); + pagesCreated++; + } + } + } + if (pagesCreated == 0) _CreateNewWindow("", fullscreen); @@ -267,8 +297,11 @@ BrowserApp::MessageReceived(BMessage* message) case WINDOW_CLOSED: fWindowCount--; message->FindRect("window frame", &fLastWindowFrame); - if (fWindowCount <= 0) - PostMessage(B_QUIT_REQUESTED); + if (fWindowCount <= 0) { + BMessage* message = new BMessage(B_QUIT_REQUESTED); + message->AddMessage("window", DetachCurrentMessage()); + PostMessage(message); + } break; case SHOW_DOWNLOAD_WINDOW: @@ -333,19 +366,36 @@ BrowserApp::QuitRequested() } } - for (int i = 0; BWindow* window = WindowAt(i); i++) { - BrowserWindow* webWindow = dynamic_cast(window); - if (!webWindow) - continue; - if (!webWindow->Lock()) - continue; - if (webWindow->QuitRequested()) { - fLastWindowFrame = webWindow->WindowFrame(); - webWindow->Quit(); - i--; - } else { - webWindow->Unlock(); - return false; + fSession->MakeEmpty(); + + /* See if we got here because the last window is already closed. + * In that case we only need to save that one, which is already archived */ + BMessage* message = CurrentMessage(); + BMessage windowMessage; + + status_t ret = message->FindMessage("window", &windowMessage); + if (ret == B_OK) { + fSession->AddMessage("window", &windowMessage); + } else { + for (int i = 0; BWindow* window = WindowAt(i); i++) { + BrowserWindow* webWindow = dynamic_cast(window); + if (!webWindow) + continue; + if (!webWindow->Lock()) + continue; + + BMessage windowArchive; + webWindow->Archive(&windowArchive, true); + fSession->AddMessage("window", &windowArchive); + + if (webWindow->QuitRequested()) { + fLastWindowFrame = webWindow->WindowFrame(); + webWindow->Quit(); + i--; + } else { + webWindow->Unlock(); + return false; + } } } diff --git a/src/apps/webpositive/BrowserApp.h b/src/apps/webpositive/BrowserApp.h index 2764fac6e2..50b67255cd 100644 --- a/src/apps/webpositive/BrowserApp.h +++ b/src/apps/webpositive/BrowserApp.h @@ -79,6 +79,7 @@ private: SettingsMessage* fSettings; SettingsMessage* fCookies; + SettingsMessage* fSession; BUrlContext* fContext; DownloadWindow* fDownloadWindow; diff --git a/src/apps/webpositive/BrowserWindow.cpp b/src/apps/webpositive/BrowserWindow.cpp index 8d59503f6f..a251b40fbd 100644 --- a/src/apps/webpositive/BrowserWindow.cpp +++ b/src/apps/webpositive/BrowserWindow.cpp @@ -1186,18 +1186,39 @@ BrowserWindow::MessageReceived(BMessage* message) } +status_t +BrowserWindow::Archive(BMessage* archive, bool deep) const +{ + status_t ret = archive->AddRect("window frame", Frame()); + + for (int i = 0; i < fTabManager->CountTabs(); i++) { + BWebView* view = dynamic_cast(fTabManager->ViewForTab(i)); + if (view == NULL) { + continue; + } + + if (ret == B_OK) + ret = archive->AddString("tab", view->MainFrameURL()); + } + + return ret; +} + + bool BrowserWindow::QuitRequested() { // TODO: Check for modified form data and ask user for confirmation, etc. + BMessage message(WINDOW_CLOSED); + Archive(&message); + // Iterate over all tabs to delete all BWebViews. // Do this here, so WebKit tear down happens earlier. SetCurrentWebView(NULL); while (fTabManager->CountTabs() > 0) _ShutdownTab(0); - BMessage message(WINDOW_CLOSED); message.AddRect("window frame", WindowFrame()); be_app->PostMessage(&message); return true; diff --git a/src/apps/webpositive/BrowserWindow.h b/src/apps/webpositive/BrowserWindow.h index e3030e098d..dcc85f2133 100644 --- a/src/apps/webpositive/BrowserWindow.h +++ b/src/apps/webpositive/BrowserWindow.h @@ -104,6 +104,7 @@ public: virtual void DispatchMessage(BMessage* message, BHandler* target); virtual void MessageReceived(BMessage* message); + virtual status_t Archive(BMessage* archive, bool deep =true) const; virtual bool QuitRequested(); virtual void MenusBeginning(); virtual void MenusEnded();