Bug 603903 - Part 2: restore session when restarted by Windows draft
authorAdam Gashlin <agashlin@mozilla.com>
Tue, 15 May 2018 18:28:08 -0700
changeset 795928 26ef37bebe39c42e34ff1346ebb8d00936029f0b
parent 795927 106ae0e237b290fda09c0c752a7dfa2ac718ed16
child 795929 e0d7e872980a2fd3366460029ec165a896548e91
push id110121
push userbmo:agashlin@mozilla.com
push dateWed, 16 May 2018 19:33:58 +0000
bugs603903
milestone62.0a1
Bug 603903 - Part 2: restore session when restarted by Windows MozReview-Commit-ID: EEKZAZZ9E98
browser/app/profile/firefox.js
browser/components/nsBrowserGlue.js
browser/components/sessionstore/SessionStore.jsm
browser/components/sessionstore/nsSessionStartup.js
widget/windows/nsWindow.cpp
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -851,16 +851,17 @@ pref("browser.rights.3.shown", false);
 
 #ifdef DEBUG
 // Don't show the about:rights notification in debug builds.
 pref("browser.rights.override", true);
 #endif
 
 pref("browser.sessionstore.resume_from_crash", true);
 pref("browser.sessionstore.resume_session_once", false);
+pref("browser.sessionstore.resuming_after_os_restart", false);
 
 // Minimal interval between two save operations in milliseconds (while the user is active).
 pref("browser.sessionstore.interval", 15000); // 15 seconds
 
 // Minimal interval between two save operations in milliseconds (while the user is idle).
 pref("browser.sessionstore.interval.idle", 3600000); // 1h
 
 // Time (ms) before we assume that the user is idle and that we don't need to
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -1319,17 +1319,17 @@ BrowserGlue.prototype = {
     //    - The quit dialog will be shown
     // 2. aQuitType == "lastwindow" && browser.tabs.warnOnClose == true
     //    - The "closing multiple tabs" dialog will be shown
     //
     // aQuitType == "lastwindow" is overloaded. "lastwindow" is used to indicate
     // "the last window is closing but we're not quitting (a non-browser window is open)"
     // and also "we're quitting by closing the last window".
 
-    if (aQuitType == "restart")
+    if (aQuitType == "restart" || aQuitType == "os-restart")
       return;
 
     var windowcount = 0;
     var pagecount = 0;
     var browserEnum = Services.wm.getEnumerator("navigator:browser");
     let allWindowsPrivate = true;
     while (browserEnum.hasMoreElements()) {
       // XXXbz should we skip closed windows here?
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -1722,18 +1722,22 @@ var SessionStoreInternal = {
   },
 
   /**
    * On quitting application
    * @param aData
    *        String type of quitting
    */
   onQuitApplication: function ssi_onQuitApplication(aData) {
-    if (aData == "restart") {
+    if (aData == "restart" || aData == "os-restart") {
       if (!PrivateBrowsingUtils.permanentPrivateBrowsing) {
+        if (aData == "os-restart" &&
+            !this._prefBranch.getBoolPref("sessionstore.resume_session_once")) {
+          this._prefBranch.setBoolPref("sessionstore.resuming_after_os_restart", true);
+        }
         this._prefBranch.setBoolPref("sessionstore.resume_session_once", true);
       }
 
       // The browser:purge-session-history notification fires after the
       // quit-application notification so unregister the
       // browser:purge-session-history notification to prevent clearing
       // session data on disk on a restart.  It is also unnecessary to
       // perform any other sanitization processing on a restart as the
--- a/browser/components/sessionstore/nsSessionStartup.js
+++ b/browser/components/sessionstore/nsSessionStartup.js
@@ -97,16 +97,27 @@ SessionStartup.prototype = {
 
     // do not need to initialize anything in auto-started private browsing sessions
     if (PrivateBrowsingUtils.permanentPrivateBrowsing) {
       this._initialized = true;
       gOnceInitializedDeferred.resolve();
       return;
     }
 
+    if (Services.prefs.getBoolPref("browser.sessionstore.resuming_after_os_restart")) {
+      if (!Services.appinfo.restartedByOS) {
+        // We had set resume_session_once in order to resume after an OS restart,
+        // but we aren't automatically started by the OS (or else appinfo.restartedByOS
+        // would have been set). Therefore we should clear resume_session_once
+        // to avoid forcing a resume for a normal startup.
+        Services.prefs.setBoolPref("browser.sessionstore.resume_session_once", false);
+      }
+      Services.prefs.setBoolPref("browser.sessionstore.resuming_after_os_restart", false);
+    }
+
     this._resumeSessionEnabled =
       Services.prefs.getBoolPref("browser.sessionstore.resume_session_once") ||
       Services.prefs.getIntPref("browser.startup.page") == BROWSER_STARTUP_RESUME_SESSION;
 
     SessionFile.read().then(
       this._onSessionFileRead.bind(this),
       console.error
     );
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -65,16 +65,17 @@
 #include "mozilla/MouseEvents.h"
 #include "mozilla/TouchEvents.h"
 
 #include "mozilla/ipc/MessageChannel.h"
 #include <algorithm>
 #include <limits>
 
 #include "nsWindow.h"
+#include "nsAppRunner.h"
 
 #include <shellapi.h>
 #include <windows.h>
 #include <wtsapi32.h>
 #include <process.h>
 #include <commctrl.h>
 #include <unknwn.h>
 #include <psapi.h>
@@ -5025,16 +5026,30 @@ LRESULT CALLBACK nsWindow::WindowProcInt
   }
 
   LRESULT res = ::CallWindowProcW(targetWindow->GetPrevWindowProc(),
                                   hWnd, msg, wParam, lParam);
 
   return res;
 }
 
+const char16_t*
+GetQuitType()
+{
+  if (Preferences::GetBool(PREF_WIN_REGISTER_APPLICATION_RESTART, false)) {
+    DWORD cchCmdLine = 0;
+    HRESULT rc =
+      ::GetApplicationRestartSettings(::GetCurrentProcess(), nullptr, &cchCmdLine, nullptr);
+    if (rc == S_OK) {
+      return u"os-restart";
+    }
+  }
+  return nullptr;
+}
+
 // The main windows message processing method for plugins.
 // The result means whether this method processed the native
 // event for plugin. If false, the native event should be
 // processed by the caller self.
 bool
 nsWindow::ProcessMessageForPlugin(const MSG &aMsg,
                                   MSGResult& aResult)
 {
@@ -5197,17 +5212,19 @@ nsWindow::ProcessMessage(UINT msg, WPARA
       {
         // Ask if it's ok to quit, and store the answer until we
         // get WM_ENDSESSION signaling the round is complete.
         nsCOMPtr<nsIObserverService> obsServ =
           mozilla::services::GetObserverService();
         nsCOMPtr<nsISupportsPRBool> cancelQuit =
           do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
         cancelQuit->SetData(false);
-        obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nullptr);
+
+        const char16_t* quitType = GetQuitType();
+        obsServ->NotifyObservers(cancelQuit, "quit-application-requested", quitType);
 
         bool abortQuit;
         cancelQuit->GetData(&abortQuit);
         sCanQuit = abortQuit ? TRI_FALSE : TRI_TRUE;
       }
       *aRetValue = sCanQuit ? TRUE : FALSE;
       result = true;
       break;
@@ -5228,19 +5245,21 @@ nsWindow::ProcessMessage(UINT msg, WPARA
         // Let's fake a shutdown sequence without actually closing windows etc.
         // to avoid Windows killing us in the middle. A proper shutdown would
         // require having a chance to pump some messages. Unfortunately
         // Windows won't let us do that. Bug 212316.
         nsCOMPtr<nsIObserverService> obsServ =
           mozilla::services::GetObserverService();
         const char16_t* context = u"shutdown-persist";
         const char16_t* syncShutdown = u"syncShutdown";
+        const char16_t* quitType = GetQuitType();
+
         obsServ->NotifyObservers(nullptr, "quit-application-granted", syncShutdown);
         obsServ->NotifyObservers(nullptr, "quit-application-forced", nullptr);
-        obsServ->NotifyObservers(nullptr, "quit-application", nullptr);
+        obsServ->NotifyObservers(nullptr, "quit-application", quitType);
         obsServ->NotifyObservers(nullptr, "profile-change-net-teardown", context);
         obsServ->NotifyObservers(nullptr, "profile-change-teardown", context);
         obsServ->NotifyObservers(nullptr, "profile-before-change", context);
         obsServ->NotifyObservers(nullptr, "profile-before-change-qm", context);
         obsServ->NotifyObservers(nullptr, "profile-before-change-telemetry", context);
         ExitThisProcessSafely();
       }
       sCanQuit = TRI_UNKNOWN;