Bug 603903 - Part 2: restore session when restarted by Windows draft
authorAdam Gashlin <agashlin@mozilla.com>
Wed, 25 Apr 2018 14:46:57 -0700
changeset 788096 20e8cf846db1fb87ad3f2338ccd5e41de145e2fa
parent 788095 ff05ad3857869f463c6e0966e68623358edfe3b3
child 788097 38f2b5ea6b482f3fd6d4a78624c009d57193cf6f
push id107902
push userbmo:agashlin@mozilla.com
push dateWed, 25 Apr 2018 22:34:25 +0000
bugs603903
milestone61.0a1
Bug 603903 - Part 2: restore session when restarted by Windows MozReview-Commit-ID: LYLGywL9tHc
browser/app/profile/firefox.js
toolkit/xre/nsAppRunner.cpp
widget/windows/nsWindow.cpp
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -853,16 +853,22 @@ 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);
+#if defined(XP_WIN)
+// True if browser.sessionstore.resume_session_once was set expecting us to be
+// restarted through RegisterApplicationRestart, and therefore it should be
+// cleared early if we're not started that way.
+pref("browser.sessionstore.resumed_for_rar", false);
+#endif
 
 // 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/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -4772,16 +4772,27 @@ XREMain::XRE_mainRun()
   SaveToEnv("XUL_APP_FILE=");
   SaveToEnv("XRE_BINARY_PATH=");
 
   if (!mShuttingDown) {
     rv = appStartup->CreateHiddenWindow();
     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
 
 #ifdef XP_WIN
+    if (Preferences::GetBool("browser.sessionstore.resumed_for_rar", false)) {
+      if (!gRARRestarted) {
+        // We had set resume_session_once in order to resume after a Windows
+        // restart, but we aren't started by the restart service (or else the
+        // gRARRestarted flag would have been set). Therefore we should clear
+        // resume_session_once to avoid forcing a resume for a normal startup.
+        Preferences::SetBool("browser.sessionstore.resume_session_once", false);
+      }
+      Preferences::SetBool("browser.sessionstore.resumed_for_rar", false);
+    }
+
     Preferences::RegisterCallbackAndCall(RegisterApplicationRestartChanged,
                                          PREF_WIN_REGISTER_APPLICATION_RESTART);
 #endif
 
 #if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_WIDGET_GTK)
     nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit();
     if (toolkit && !mDesktopStartupID.IsEmpty()) {
       toolkit->SetDesktopStartupID(mDesktopStartupID);
--- 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>
@@ -5152,16 +5153,33 @@ ExitThisProcessSafely()
   HANDLE process = GetCurrentProcess();
   if (TerminateProcess(GetCurrentProcess(), 0)) {
     // TerminateProcess is asynchronous, so we wait on our own process handle
     WaitForSingleObject(process, INFINITE);
   }
   MOZ_CRASH("Just in case extremis crash in ExitThisProcessSafely.");
 }
 
+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"restart";
+    } else {
+      return nullptr;
+    }
+  } else {
+    return nullptr;
+  }
+}
+
 // The main windows message processing method.
 bool
 nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
                          LRESULT *aRetValue)
 {
 #if defined(EVENT_DEBUG_OUTPUT)
   // First param shows all events, second param indicates whether
   // to show mouse move events. See nsWindowDbg for details.
@@ -5197,17 +5215,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 +5248,25 @@ 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();
+        if (quitType &&
+            !Preferences::GetBool("browser.sessionstore.resume_session_once", false)) {
+          Preferences::SetBool("browser.sessionstore.resumed_for_rar", true);
+        }
+
         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;