Bug 1666874 - Support maximized windows for skeleton UI r=agashlin
authorDoug Thayer <dothayer@mozilla.com>
Thu, 29 Oct 2020 19:04:02 +0000
changeset 555144 23c5d0a4118e891744c4978c78b79f8aac5939ce
parent 555143 7e7a708a999720f8fccf5b33525484bd9d0fd5a6
child 555145 8587dd1eeb5cc1a34117d9b31cb1adb10c2f5845
push id37903
push userapavel@mozilla.com
push dateFri, 30 Oct 2020 03:48:30 +0000
treeherdermozilla-central@9a7e5873fac5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersagashlin
bugs1666874
milestone84.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1666874 - Support maximized windows for skeleton UI r=agashlin Most of this patch is a dance to avoid size flickering of the skeleton UI window. We change all Resize/Move/SetSizeMode calls from before the first nsWindow::Show call. Normally those have no effect, since the window isn't shown yet, and if the window is not maximized, they typically match the sizes we've gotten out of the registry anyway. However, if we are maximized, then they produce a lot of visual noise. We can however achieve the desired effect by just calling SetWindowPlacement. Similarly, we switch the window styles of the skeleton UI window to match those of the toplevel Windows window, and adjust the client rect from our window proc in a way that matches the adjustments in nsWindow in the WM_NCCALCSIZE handler. We do this because otherwise we get a flicker as soon as we change the styles and nonclient margins as the fake chrome pops up and then back down. Lastly we also change the extended window styles so that they match. We historically added WS_EX_TOOLWINDOW here to hide the toolbar entry, because it would otherwise switch out to a new toolbar entry when we changed the window styles. However since our new styles match, we no longer need to do this. It was also causing the maximized window to paint over the Windows taskbar. Differential Revision: https://phabricator.services.mozilla.com/D93534
mozglue/misc/PreXULSkeletonUI.cpp
mozglue/misc/PreXULSkeletonUI.h
widget/windows/WinUtils.cpp
widget/windows/nsWindow.cpp
widget/windows/nsWindow.h
xpfe/appshell/AppWindow.cpp
--- a/mozglue/misc/PreXULSkeletonUI.cpp
+++ b/mozglue/misc/PreXULSkeletonUI.cpp
@@ -66,16 +66,20 @@ static HWND sPreXULSkeletonUIWindow;
 static LPWSTR const gStockApplicationIcon = MAKEINTRESOURCEW(32512);
 static LPWSTR const gIDCWait = MAKEINTRESOURCEW(32514);
 static HANDLE sPreXULSKeletonUIAnimationThread;
 
 static uint32_t* sPixelBuffer = nullptr;
 static Vector<ColorRect>* sAnimatedRects = nullptr;
 static int sTotalChromeHeight = 0;
 static volatile LONG sAnimationControlFlag = 0;
+static bool sMaximized = false;
+static int sNonClientVerticalMargins = 0;
+static int sNonClientHorizontalMargins = 0;
+static uint32_t sDpi = 0;
 
 // Color values needed by the animation loop
 static uint32_t sBackgroundColor;
 static uint32_t sToolbarForegroundColor;
 
 typedef BOOL(WINAPI* EnableNonClientDpiScalingProc)(HWND);
 static EnableNonClientDpiScalingProc sEnableNonClientDpiScaling = NULL;
 typedef int(WINAPI* GetSystemMetricsForDpiProc)(int, UINT);
@@ -91,54 +95,41 @@ LoadCursorWProc sLoadCursorW = NULL;
 typedef HWND(WINAPI* CreateWindowExWProc)(DWORD, LPCWSTR, LPCWSTR, DWORD, int,
                                           int, int, int, HWND, HMENU, HINSTANCE,
                                           LPVOID);
 CreateWindowExWProc sCreateWindowExW = NULL;
 typedef BOOL(WINAPI* ShowWindowProc)(HWND, int);
 ShowWindowProc sShowWindow = NULL;
 typedef BOOL(WINAPI* SetWindowPosProc)(HWND, HWND, int, int, int, int, UINT);
 SetWindowPosProc sSetWindowPos = NULL;
-typedef BOOL(WINAPI* RedrawWindowProc)(HWND, const RECT*, HRGN, UINT);
-RedrawWindowProc sRedrawWindow = NULL;
 typedef HDC(WINAPI* GetWindowDCProc)(HWND);
 GetWindowDCProc sGetWindowDC = NULL;
 typedef int(WINAPI* FillRectProc)(HDC, const RECT*, HBRUSH);
 FillRectProc sFillRect = NULL;
 typedef BOOL(WINAPI* DeleteObjectProc)(HGDIOBJ);
 DeleteObjectProc sDeleteObject = NULL;
 typedef int(WINAPI* ReleaseDCProc)(HWND, HDC);
 ReleaseDCProc sReleaseDC = NULL;
+typedef HMONITOR(WINAPI* MonitorFromWindowProc)(HWND, DWORD);
+MonitorFromWindowProc sMonitorFromWindow = NULL;
+typedef BOOL(WINAPI* GetMonitorInfoWProc)(HMONITOR, LPMONITORINFO);
+GetMonitorInfoWProc sGetMonitorInfoW = NULL;
+typedef LONG_PTR(WINAPI* SetWindowLongPtrWProc)(HWND, int, LONG_PTR);
+SetWindowLongPtrWProc sSetWindowLongPtrW = NULL;
 typedef int(WINAPI* StretchDIBitsProc)(HDC, int, int, int, int, int, int, int,
                                        int, const VOID*, const BITMAPINFO*,
                                        UINT, DWORD);
 StretchDIBitsProc sStretchDIBits = NULL;
 typedef HBRUSH(WINAPI* CreateSolidBrushProc)(COLORREF);
 CreateSolidBrushProc sCreateSolidBrush = NULL;
 
 static uint32_t sWindowWidth;
 static uint32_t sWindowHeight;
 static double sCSSToDevPixelScaling;
 
-// We style our initial blank window as a WS_POPUP to eliminate the window
-// caption and all that jazz. Alternatively, we could do a big dance in our
-// window proc to paint into the nonclient area similarly to what we do in
-// nsWindow, but it would be nontrivial code duplication, and the added
-// complexity would not be worth it, given that we can just change the
-// window style to our liking when we consume sPreXULSkeletonUIWindow from
-// nsWindow.
-static DWORD sWindowStyle = WS_POPUP;
-
-// We add WS_EX_TOOLWINDOW here so that we do not produce a toolbar entry.
-// We were not able to avoid flickering in the toolbar without this change,
-// as the call to ::SetWindowLongPtrW to restyle the window inside
-// nsWindow causes the toolbar entry to momentarily disappear. Not sure of
-// the cause of this, but it doesn't feel too wrong to be missing a toolbar
-// entry only so long as we are displaying a skeleton UI.
-static DWORD sWindowStyleEx = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW;
-
 static const int kAnimationCSSPixelsPerFrame = 21;
 static const int kAnimationCSSExtraWindowSize = 300;
 
 // We could use nsAutoRegKey, but including nsWindowsHelpers.h causes build
 // failures in random places because we're in mozglue. Overall it should be
 // simpler and cleaner to just step around that issue with this class:
 class MOZ_RAII AutoCloseRegKey {
  public:
@@ -193,32 +184,36 @@ void DrawSkeletonUI(HWND hWnd, double ur
   // --chrome-content-separator-color in browser.css
   uint32_t chromeContentDividerColor = 0xe2e1e3;
   // controlled by css variable --tab-line-color
   uint32_t tabLineColor = 0x0a75d3;
   // controlled by css variable --toolbar-color
   uint32_t urlbarColor = 0xffffff;
 
   int chromeHorMargin = CSSToDevPixels(2, sCSSToDevPixelScaling);
-  int dpi = sGetDpiForWindow(hWnd);
-  int verticalOffset = sGetSystemMetricsForDpi(SM_CYBORDER, dpi);
-  int nonClientHorMargins = sGetSystemMetricsForDpi(SM_CXFRAME, dpi) +
-                            sGetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
-  int horizontalOffset = nonClientHorMargins - chromeHorMargin;
+  int verticalOffset = sMaximized ? sNonClientVerticalMargins : 0;
+  int horizontalOffset =
+      sNonClientHorizontalMargins - (sMaximized ? 0 : chromeHorMargin);
 
+  // found in browser-aero.css, ":root[sizemode=normal][tabsintitlebar]"
+  int topBorderHeight =
+      sMaximized ? 0 : CSSToDevPixels(1, sCSSToDevPixelScaling);
   // found in tabs.inc.css, "--tab-min-height" - depends on uidensity variable
   int tabBarHeight = CSSToDevPixels(33, sCSSToDevPixelScaling) + verticalOffset;
   // found in tabs.inc.css, ".titlebar-spacer"
   int titlebarSpacerWidth =
-      CSSToDevPixels(40, sCSSToDevPixelScaling) + horizontalOffset;
+      (sMaximized ? 0 : CSSToDevPixels(40, sCSSToDevPixelScaling)) +
+      horizontalOffset;
   // found in tabs.inc.css, ".tab-line"
   int tabLineHeight = CSSToDevPixels(2, sCSSToDevPixelScaling) + verticalOffset;
   int selectedTabWidth = CSSToDevPixels(224, sCSSToDevPixelScaling);
-
   int toolbarHeight = CSSToDevPixels(39, sCSSToDevPixelScaling);
+  // found in urlbar-searchbar.inc.css, "#urlbar[breakout]"
+  int urlbarTopOffset = CSSToDevPixels(5, sCSSToDevPixelScaling);
+  int urlbarHeight = CSSToDevPixels(30, sCSSToDevPixelScaling);
 
   int tabPlaceholderBarMarginTop = CSSToDevPixels(13, sCSSToDevPixelScaling);
   int tabPlaceholderBarMarginLeft = CSSToDevPixels(10, sCSSToDevPixelScaling);
   int tabPlaceholderBarHeight = CSSToDevPixels(8, sCSSToDevPixelScaling);
   int tabPlaceholderBarWidth = CSSToDevPixels(120, sCSSToDevPixelScaling);
 
   int toolbarPlaceholderMarginTop = CSSToDevPixels(16, sCSSToDevPixelScaling);
   int toolbarPlaceholderMarginLeft = CSSToDevPixels(9, sCSSToDevPixelScaling);
@@ -229,53 +224,60 @@ void DrawSkeletonUI(HWND hWnd, double ur
   int urlbarTextPlaceholderMarginTop =
       CSSToDevPixels(10, sCSSToDevPixelScaling);
   int urlbarTextPlaceholderMarginLeft =
       CSSToDevPixels(10, sCSSToDevPixelScaling);
   int urlbarTextPlaceHolderWidth = CSSToDevPixels(
       std::min((int)urlbarWidthCSS - 10, 260), sCSSToDevPixelScaling);
   int urlbarTextPlaceholderHeight = CSSToDevPixels(10, sCSSToDevPixelScaling);
 
+  ColorRect topBorder = {};
+  topBorder.color = 0x00000000;
+  topBorder.x = 0;
+  topBorder.y = 0;
+  topBorder.width = sWindowWidth;
+  topBorder.height = topBorderHeight;
+
   // The (traditionally dark blue on Windows) background of the tab bar.
   ColorRect tabBar = {};
   tabBar.color = tabBarColor;
   tabBar.x = 0;
-  tabBar.y = 0;
+  tabBar.y = topBorder.height;
   tabBar.width = sWindowWidth;
   tabBar.height = tabBarHeight;
 
   // The blue highlight at the top of the initial selected tab
   ColorRect tabLine = {};
   tabLine.color = tabLineColor;
   tabLine.x = titlebarSpacerWidth;
-  tabLine.y = 0;
+  tabLine.y = topBorder.height;
   tabLine.width = selectedTabWidth;
   tabLine.height = tabLineHeight;
 
   // The initial selected tab
   ColorRect selectedTab = {};
   selectedTab.color = sBackgroundColor;
   selectedTab.x = titlebarSpacerWidth;
-  selectedTab.y = tabLineHeight;
+  selectedTab.y = tabLine.y + tabLineHeight;
   selectedTab.width = selectedTabWidth;
-  selectedTab.height = tabBarHeight;
+  selectedTab.height = tabBar.y + tabBar.height - selectedTab.y;
 
   // A placeholder rect representing text that will fill the selected tab title
   ColorRect tabTextPlaceholder = {};
   tabTextPlaceholder.color = sToolbarForegroundColor;
   tabTextPlaceholder.x = selectedTab.x + tabPlaceholderBarMarginLeft;
   tabTextPlaceholder.y = selectedTab.y + tabPlaceholderBarMarginTop;
   tabTextPlaceholder.width = tabPlaceholderBarWidth;
   tabTextPlaceholder.height = tabPlaceholderBarHeight;
 
   // The toolbar background
   ColorRect toolbar = {};
   toolbar.color = sBackgroundColor;
   toolbar.x = 0;
-  toolbar.y = tabBarHeight;
+  toolbar.y = tabBar.y + tabBarHeight;
   toolbar.width = sWindowWidth;
   toolbar.height = toolbarHeight;
 
   // A placeholder rect representing UI elements that will fill the left part
   // of the toolbar
   ColorRect leftToolbarPlaceholder = {};
   leftToolbarPlaceholder.color = sToolbarForegroundColor;
   leftToolbarPlaceholder.x =
@@ -303,55 +305,60 @@ void DrawSkeletonUI(HWND hWnd, double ur
   chromeContentDivider.width = sWindowWidth;
   chromeContentDivider.height = 1;
 
   // The urlbar
   ColorRect urlbar = {};
   urlbar.color = urlbarColor;
   urlbar.x = CSSToDevPixels(urlbarHorizontalOffsetCSS, sCSSToDevPixelScaling) +
              horizontalOffset;
-  urlbar.y = CSSToDevPixels(39, sCSSToDevPixelScaling);
+  urlbar.y = tabBar.y + tabBarHeight + urlbarTopOffset;
   urlbar.width = CSSToDevPixels(urlbarWidthCSS, sCSSToDevPixelScaling);
-  urlbar.height = CSSToDevPixels(30, sCSSToDevPixelScaling);
+  urlbar.height = urlbarHeight;
 
   // The urlbar placeholder rect representating text that will fill the urlbar
   // The placeholder rects should all be y-aligned.
   ColorRect urlbarTextPlaceholder = {};
   urlbarTextPlaceholder.color = sToolbarForegroundColor;
   urlbarTextPlaceholder.x = urlbar.x + urlbarTextPlaceholderMarginLeft;
   // This is equivalent to rightToolbarPlaceholder.y and
   // leftToolbarPlaceholder.y
   urlbarTextPlaceholder.y = urlbar.y + urlbarTextPlaceholderMarginTop;
   urlbarTextPlaceholder.width = urlbarTextPlaceHolderWidth;
   urlbarTextPlaceholder.height = urlbarTextPlaceholderHeight;
 
   ColorRect rects[] = {
+      topBorder,
       tabBar,
       tabLine,
       selectedTab,
       tabTextPlaceholder,
       toolbar,
       leftToolbarPlaceholder,
       rightToolbarPlaceholder,
       chromeContentDivider,
       urlbar,
       urlbarTextPlaceholder,
   };
 
+  sTotalChromeHeight = chromeContentDivider.y + chromeContentDivider.height;
+  if (sTotalChromeHeight > sWindowHeight) {
+    printf_stderr("Exiting drawing skeleton UI because window is too small.\n");
+    return;
+  }
+
   if (!sAnimatedRects->append(tabTextPlaceholder) ||
       !sAnimatedRects->append(leftToolbarPlaceholder) ||
       !sAnimatedRects->append(rightToolbarPlaceholder) ||
       !sAnimatedRects->append(urlbarTextPlaceholder)) {
     delete sAnimatedRects;
     sAnimatedRects = nullptr;
     return;
   }
 
-  sTotalChromeHeight = chromeContentDivider.y + chromeContentDivider.height;
-
   sPixelBuffer =
       (uint32_t*)calloc(sWindowWidth * sTotalChromeHeight, sizeof(uint32_t));
 
   for (int i = 0; i < sizeof(rects) / sizeof(rects[0]); ++i) {
     ColorRect rect = rects[i];
     for (int y = rect.y; y < rect.y + rect.height; ++y) {
       uint32_t* lineStart = &sPixelBuffer[y * sWindowWidth];
       uint32_t* dataStart = lineStart + rect.x;
@@ -550,20 +557,45 @@ DWORD WINAPI AnimateSkeletonUI(void* aUn
     }
   }
 
   return 0;
 }
 
 LRESULT WINAPI PreXULSkeletonUIProc(HWND hWnd, UINT msg, WPARAM wParam,
                                     LPARAM lParam) {
+  // NOTE: this block was copied from WinUtils.cpp, and needs to be kept in
+  // sync.
   if (msg == WM_NCCREATE && sEnableNonClientDpiScaling) {
     sEnableNonClientDpiScaling(hWnd);
   }
 
+  // NOTE: this block was paraphrased from the WM_NCCALCSIZE handler in
+  // nsWindow.cpp, and will need to be kept in sync.
+  if (msg == WM_NCCALCSIZE) {
+    RECT* clientRect =
+        wParam ? &(reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam))->rgrc[0]
+               : (reinterpret_cast<RECT*>(lParam));
+
+    // These match the margins set in browser-tabsintitlebar.js with
+    // default prefs on Windows. Bug 1673092 tracks lining this up with
+    // that more correctly instead of hard-coding it.
+    int horizontalOffset =
+        sNonClientHorizontalMargins -
+        (sMaximized ? 0 : CSSToDevPixels(2, sCSSToDevPixelScaling));
+    int verticalOffset =
+        sNonClientHorizontalMargins -
+        (sMaximized ? 0 : CSSToDevPixels(2, sCSSToDevPixelScaling));
+    clientRect->top = clientRect->top;
+    clientRect->left += horizontalOffset;
+    clientRect->right -= horizontalOffset;
+    clientRect->bottom -= verticalOffset;
+    return 0;
+  }
+
   return ::DefWindowProcW(hWnd, msg, wParam, lParam);
 }
 
 bool OpenPreXULSkeletonUIRegKey(HKEY& key) {
   DWORD disposition;
   LSTATUS result =
       ::RegCreateKeyExW(HKEY_CURRENT_USER, kPreXULSkeletonUIKeyPath, 0, nullptr,
                         0, KEY_ALL_ACCESS, nullptr, &key, &disposition);
@@ -630,20 +662,16 @@ bool LoadGdi32AndUser32Procedures() {
   sShowWindow = (ShowWindowProc)::GetProcAddress(user32Dll, "ShowWindow");
   if (!sShowWindow) {
     return false;
   }
   sSetWindowPos = (SetWindowPosProc)::GetProcAddress(user32Dll, "SetWindowPos");
   if (!sSetWindowPos) {
     return false;
   }
-  sRedrawWindow = (RedrawWindowProc)::GetProcAddress(user32Dll, "RedrawWindow");
-  if (!sRedrawWindow) {
-    return false;
-  }
   sGetWindowDC = (GetWindowDCProc)::GetProcAddress(user32Dll, "GetWindowDC");
   if (!sGetWindowDC) {
     return false;
   }
   sFillRect = (FillRectProc)::GetProcAddress(user32Dll, "FillRect");
   if (!sFillRect) {
     return false;
   }
@@ -654,17 +682,31 @@ bool LoadGdi32AndUser32Procedures() {
   sLoadIconW = (LoadIconWProc)::GetProcAddress(user32Dll, "LoadIconW");
   if (!sLoadIconW) {
     return false;
   }
   sLoadCursorW = (LoadCursorWProc)::GetProcAddress(user32Dll, "LoadCursorW");
   if (!sLoadCursorW) {
     return false;
   }
-
+  sMonitorFromWindow =
+      (MonitorFromWindowProc)::GetProcAddress(user32Dll, "MonitorFromWindow");
+  if (!sMonitorFromWindow) {
+    return false;
+  }
+  sGetMonitorInfoW =
+      (GetMonitorInfoWProc)::GetProcAddress(user32Dll, "GetMonitorInfoW");
+  if (!sGetMonitorInfoW) {
+    return false;
+  }
+  sSetWindowLongPtrW =
+      (SetWindowLongPtrWProc)::GetProcAddress(user32Dll, "SetWindowLongPtrW");
+  if (!sSetWindowLongPtrW) {
+    return false;
+  }
   sStretchDIBits =
       (StretchDIBitsProc)::GetProcAddress(gdi32Dll, "StretchDIBits");
   if (!sStretchDIBits) {
     return false;
   }
   sCreateSolidBrush =
       (CreateSolidBrushProc)::GetProcAddress(gdi32Dll, "CreateSolidBrush");
   if (!sCreateSolidBrush) {
@@ -732,30 +774,42 @@ void CreateAndStorePreXULSkeletonUI(HINS
   uint32_t screenY;
   result = ::RegGetValueW(regKey, nullptr, L"screenY", RRF_RT_REG_DWORD,
                           nullptr, reinterpret_cast<PBYTE>(&screenY), &dataLen);
   if (result != ERROR_SUCCESS) {
     printf_stderr("Error reading screenY %lu\n", GetLastError());
     return;
   }
 
+  uint32_t windowWidth;
   result = ::RegGetValueW(regKey, nullptr, L"width", RRF_RT_REG_DWORD, nullptr,
-                          reinterpret_cast<PBYTE>(&sWindowWidth), &dataLen);
+                          reinterpret_cast<PBYTE>(&windowWidth), &dataLen);
   if (result != ERROR_SUCCESS) {
     printf_stderr("Error reading width %lu\n", GetLastError());
     return;
   }
 
+  uint32_t windowHeight;
   result = ::RegGetValueW(regKey, nullptr, L"height", RRF_RT_REG_DWORD, nullptr,
-                          reinterpret_cast<PBYTE>(&sWindowHeight), &dataLen);
+                          reinterpret_cast<PBYTE>(&windowHeight), &dataLen);
   if (result != ERROR_SUCCESS) {
     printf_stderr("Error reading height %lu\n", GetLastError());
     return;
   }
 
+  uint32_t maximized;
+  result =
+      ::RegGetValueW(regKey, nullptr, L"maximized", RRF_RT_REG_DWORD, nullptr,
+                     reinterpret_cast<PBYTE>(&maximized), &dataLen);
+  if (result != ERROR_SUCCESS) {
+    printf_stderr("Error reading maximized %lu\n", GetLastError());
+    return;
+  }
+  sMaximized = maximized != 0;
+
   dataLen = sizeof(double);
   double urlbarHorizontalOffsetCSS;
   result = ::RegGetValueW(
       regKey, nullptr, L"urlbarHorizontalOffsetCSS", RRF_RT_REG_BINARY, nullptr,
       reinterpret_cast<PBYTE>(&urlbarHorizontalOffsetCSS), &dataLen);
   if (result != ERROR_SUCCESS || dataLen != sizeof(double)) {
     printf_stderr("Error reading urlbarHorizontalOffsetCSS %lu\n",
                   GetLastError());
@@ -774,35 +828,74 @@ void CreateAndStorePreXULSkeletonUI(HINS
   result = ::RegGetValueW(
       regKey, nullptr, L"cssToDevPixelScaling", RRF_RT_REG_BINARY, nullptr,
       reinterpret_cast<PBYTE>(&sCSSToDevPixelScaling), &dataLen);
   if (result != ERROR_SUCCESS || dataLen != sizeof(double)) {
     printf_stderr("Error reading cssToDevPixelScaling %lu\n", GetLastError());
     return;
   }
 
+  int showCmd = SW_SHOWNORMAL;
+  DWORD windowStyle = kPreXULSkeletonUIWindowStyle;
+  if (sMaximized) {
+    showCmd = SW_SHOWMAXIMIZED;
+    windowStyle |= WS_MAXIMIZE;
+  }
+
   sPreXULSkeletonUIWindow =
-      sCreateWindowExW(sWindowStyleEx, L"MozillaWindowClass", L"", sWindowStyle,
-                       screenX, screenY, sWindowWidth, sWindowHeight, nullptr,
-                       nullptr, hInstance, nullptr);
+      sCreateWindowExW(kPreXULSkeletonUIWindowStyleEx, L"MozillaWindowClass",
+                       L"", windowStyle, screenX, screenY, windowWidth,
+                       windowHeight, nullptr, nullptr, hInstance, nullptr);
+  sShowWindow(sPreXULSkeletonUIWindow, showCmd);
+
+  sDpi = sGetDpiForWindow(sPreXULSkeletonUIWindow);
+  sNonClientHorizontalMargins =
+      sGetSystemMetricsForDpi(SM_CXFRAME, sDpi) +
+      sGetSystemMetricsForDpi(SM_CXPADDEDBORDER, sDpi);
+  sNonClientVerticalMargins = sGetSystemMetricsForDpi(SM_CYFRAME, sDpi) +
+                              sGetSystemMetricsForDpi(SM_CXPADDEDBORDER, sDpi);
 
-  sShowWindow(sPreXULSkeletonUIWindow, SW_SHOWNORMAL);
+  if (sMaximized) {
+    HMONITOR monitor =
+        sMonitorFromWindow(sPreXULSkeletonUIWindow, MONITOR_DEFAULTTONULL);
+    if (!monitor) {
+      // NOTE: we specifically don't clean up the window here. If we're unable
+      // to finish setting up the window how we want it, we still need to keep
+      // it around and consume it with the first real toplevel window we
+      // create, to avoid flickering.
+      return;
+    }
+    MONITORINFO mi = {sizeof(MONITORINFO)};
+    if (!sGetMonitorInfoW(monitor, &mi)) {
+      return;
+    }
+
+    sWindowWidth =
+        mi.rcWork.right - mi.rcWork.left + sNonClientHorizontalMargins * 2;
+    sWindowHeight =
+        mi.rcWork.bottom - mi.rcWork.top + sNonClientVerticalMargins * 2;
+  } else {
+    sWindowWidth = windowWidth;
+    sWindowHeight = windowHeight;
+  }
+
   sSetWindowPos(sPreXULSkeletonUIWindow, 0, 0, 0, 0, 0,
                 SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE |
                     SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
   DrawSkeletonUI(sPreXULSkeletonUIWindow, urlbarHorizontalOffsetCSS,
                  urlbarWidthCSS);
-  sRedrawWindow(sPreXULSkeletonUIWindow, NULL, NULL, RDW_INVALIDATE);
 
   if (sAnimatedRects) {
     sPreXULSKeletonUIAnimationThread = ::CreateThread(
         nullptr, 256 * 1024, AnimateSkeletonUI, nullptr, 0, nullptr);
   }
 }
 
+bool WasPreXULSkeletonUIMaximized() { return sMaximized; }
+
 HWND ConsumePreXULSkeletonUIHandle() {
   // NOTE: we need to make sure that everything that runs here is a no-op if
   // it failed to be set, which is a possibility. If anything fails to be set
   // we don't want to clean everything up right away, because if we have a
   // blank window up, we want that to stick around and get consumed by nsWindow
   // as normal, otherwise the window will flicker in and out, which we imagine
   // is unpleasant.
 
@@ -820,17 +913,18 @@ HWND ConsumePreXULSkeletonUIHandle() {
   free(sPixelBuffer);
   sPixelBuffer = nullptr;
   delete sAnimatedRects;
   sAnimatedRects = nullptr;
   return result;
 }
 
 void PersistPreXULSkeletonUIValues(int screenX, int screenY, int width,
-                                   int height, double urlbarHorizontalOffsetCSS,
+                                   int height, bool maximized,
+                                   double urlbarHorizontalOffsetCSS,
                                    double urlbarWidthCSS,
                                    double cssToDevPixelScaling) {
   if (!sPreXULSkeletonUIEnabled) {
     return;
   }
 
   HKEY regKey;
   if (!OpenPreXULSkeletonUIRegKey(regKey)) {
@@ -862,16 +956,24 @@ void PersistPreXULSkeletonUIValues(int s
 
   result = ::RegSetValueExW(regKey, L"height", 0, REG_DWORD,
                             reinterpret_cast<PBYTE>(&height), sizeof(height));
   if (result != ERROR_SUCCESS) {
     printf_stderr("Failed persisting height to Windows registry\n");
     return;
   }
 
+  DWORD maximizedDword = maximized ? 1 : 0;
+  result = ::RegSetValueExW(regKey, L"maximized", 0, REG_DWORD,
+                            reinterpret_cast<PBYTE>(&maximizedDword),
+                            sizeof(maximizedDword));
+  if (result != ERROR_SUCCESS) {
+    printf_stderr("Failed persisting maximized to Windows registry\n");
+  }
+
   result = ::RegSetValueExW(regKey, L"urlbarHorizontalOffsetCSS", 0, REG_BINARY,
                             reinterpret_cast<PBYTE>(&urlbarHorizontalOffsetCSS),
                             sizeof(urlbarHorizontalOffsetCSS));
   if (result != ERROR_SUCCESS) {
     printf_stderr(
         "Failed persisting urlbarHorizontalOffsetCSS to Windows registry\n");
     return;
   }
--- a/mozglue/misc/PreXULSkeletonUI.h
+++ b/mozglue/misc/PreXULSkeletonUI.h
@@ -7,20 +7,30 @@
 #ifndef PreXULSkeletonUI_h_
 #define PreXULSkeletonUI_h_
 
 #include <windows.h>
 #include "mozilla/Types.h"
 
 namespace mozilla {
 
+// These unfortunately need to be kept in sync with the window style and
+// extended window style computations in nsWindow. Luckily those styles seem
+// to not vary based off of any user settings for the initial toplevel window,
+// so we're safe here for now.
+static const DWORD kPreXULSkeletonUIWindowStyle =
+    WS_CLIPCHILDREN | WS_DLGFRAME | WS_BORDER | WS_MAXIMIZEBOX |
+    WS_MINIMIZEBOX | WS_SIZEBOX | WS_SYSMENU;
+static const DWORD kPreXULSkeletonUIWindowStyleEx = WS_EX_WINDOWEDGE;
+
 MFBT_API void CreateAndStorePreXULSkeletonUI(HINSTANCE hInstance);
 MFBT_API HWND ConsumePreXULSkeletonUIHandle();
+MFBT_API bool WasPreXULSkeletonUIMaximized();
 MFBT_API void PersistPreXULSkeletonUIValues(int screenX, int screenY, int width,
-                                            int height,
+                                            int height, bool maximized,
                                             double urlbarHorizontalOffsetCSS,
                                             double urlbarWidthCSS,
                                             double cssToDevPixelScaling);
 MFBT_API bool GetPreXULSkeletonUIEnabled();
 MFBT_API void SetPreXULSkeletonUIEnabled(bool value);
 MFBT_API void PollPreXULSkeletonUIEvents();
 
 }  // namespace mozilla
--- a/widget/windows/WinUtils.cpp
+++ b/widget/windows/WinUtils.cpp
@@ -458,16 +458,19 @@ void WinUtils::Initialize() {
     }
   }
 }
 
 // static
 LRESULT WINAPI WinUtils::NonClientDpiScalingDefWindowProcW(HWND hWnd, UINT msg,
                                                            WPARAM wParam,
                                                            LPARAM lParam) {
+  // NOTE: this function was copied out into the body of the pre-XUL skeleton
+  // UI window proc (PreXULSkeletonUI.cpp). If this function changes at any
+  // point, we should probably factor this out and use it from both locations.
   if (msg == WM_NCCREATE && sEnableNonClientDpiScaling) {
     sEnableNonClientDpiScaling(hWnd);
   }
   return ::DefWindowProcW(hWnd, msg, wParam, lParam);
 }
 
 // static
 void WinUtils::LogW(const wchar_t* fmt, ...) {
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -597,17 +597,17 @@ nsWindow::nsWindow(bool aIsChildWindow)
   mFutureMarginsToUse = false;
   mCustomNonClient = false;
   mHideChrome = false;
   mFullscreenMode = false;
   mMousePresent = false;
   mMouseInDraggableArea = false;
   mDestroyCalled = false;
   mIsEarlyBlankWindow = false;
-  mWasPreXulSkeletonUI = false;
+  mIsShowingPreXULSkeletonUI = false;
   mResizable = false;
   mHasTaskbarIconBeenCreated = false;
   mMouseTransparent = false;
   mPickerDisplayCount = 0;
   mWindowType = eWindowType_child;
   mBorderStyle = eBorderStyle_default;
   mOldSizeMode = nsSizeMode_Normal;
   mLastSizeMode = nsSizeMode_Normal;
@@ -891,19 +891,44 @@ nsresult nsWindow::Create(nsIWidget* aPa
       aInitData->mWindowType == eWindowType_plugin_ipc_chrome ||
       aInitData->mWindowType == eWindowType_plugin_ipc_content) {
     style |= WS_DISABLED;
   }
 
   if (aInitData->mWindowType == eWindowType_toplevel && !aParent) {
     mWnd = ConsumePreXULSkeletonUIHandle();
     if (mWnd) {
-      mWasPreXulSkeletonUI = true;
-      ::SetWindowLongPtrW(mWnd, GWL_STYLE, style);
-      ::SetWindowLongPtrW(mWnd, GWL_EXSTYLE, extendedStyle);
+      MOZ_ASSERT(style == kPreXULSkeletonUIWindowStyle,
+                 "The skeleton UI window style should match the expected "
+                 "style for the first window created");
+      MOZ_ASSERT(extendedStyle == kPreXULSkeletonUIWindowStyleEx,
+                 "The skeleton UI window extended style should match the "
+                 "expected extended style for the first window created");
+      mIsShowingPreXULSkeletonUI = true;
+
+      // If we successfully consumed the pre-XUL skeleton UI, just update
+      // our internal state to match what is currently being displayed.
+      mIsVisible = true;
+      mSizeMode = WasPreXULSkeletonUIMaximized() ? nsSizeMode_Maximized
+                                                 : nsSizeMode_Normal;
+
+      // These match the margins set in browser-tabsintitlebar.js with
+      // default prefs on Windows. Bug 1673092 tracks lining this up with
+      // that more correctly instead of hard-coding it.
+      LayoutDeviceIntMargin margins(0, 2, 2, 2);
+      SetNonClientMargins(margins);
+
+      // Reset the WNDPROC for this window and its whole class, as we had
+      // to use our own WNDPROC when creating the the skeleton UI window.
+      ::SetWindowLongPtrW(mWnd, GWLP_WNDPROC,
+                          reinterpret_cast<LONG_PTR>(
+                              WinUtils::NonClientDpiScalingDefWindowProcW));
+      ::SetClassLongPtrW(mWnd, GCLP_WNDPROC,
+                         reinterpret_cast<LONG_PTR>(
+                             WinUtils::NonClientDpiScalingDefWindowProcW));
     }
   }
 
   if (!mWnd) {
     mWnd =
         ::CreateWindowExW(extendedStyle, className, L"", style, aRect.X(),
                           aRect.Y(), aRect.Width(), GetHeight(aRect.Height()),
                           parent, nullptr, nsToolkit::mDllInstance, nullptr);
@@ -1564,16 +1589,23 @@ already_AddRefed<SourceSurface> nsWindow
  *
  * SECTION: nsIWidget::Show
  *
  * Hide or show this component.
  *
  **************************************************************/
 
 void nsWindow::Show(bool bState) {
+  if (bState) {
+    // The first time we decide to actually show the window is when we decide
+    // that we've taken over the window from the skeleton UI, and we should
+    // no longer treat resizes / moves specially.
+    mIsShowingPreXULSkeletonUI = false;
+  }
+
   if (mWindowType == eWindowType_popup) {
     // See bug 603793. When we try to draw D3D9/10 windows with a drop shadow
     // without the DWM on a secondary monitor, windows fails to composite
     // our windows correctly. We therefor switch off the drop shadow for
     // pop-up windows when the DWM is disabled and two monitors are
     // connected.
     if (HasBogusPopupsDropShadowOnMultiMonitor() &&
         WinUtils::GetMonitorCount() > 1 &&
@@ -1912,34 +1944,66 @@ void nsWindow::Move(double aX, double aY
             MOZ_LOG(gWindowsLog, LogLevel::Info,
                     ("window moved to offscreen position\n"));
           }
         }
         ::ReleaseDC(mWnd, dc);
       }
     }
 #endif
-    ClearThemeRegion();
-
-    UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE;
-    // Workaround SetWindowPos bug with D3D9. If our window has a clip
-    // region, some drivers or OSes may incorrectly copy into the clipped-out
-    // area.
-    if (IsPlugin() && !mLayerManager && mClipRects &&
-        (mClipRectCount != 1 ||
-         !mClipRects[0].IsEqualInterior(
-             LayoutDeviceIntRect(0, 0, mBounds.Width(), mBounds.Height())))) {
-      flags |= SWP_NOCOPYBITS;
-    }
-    double oldScale = mDefaultScale;
-    mResizeState = IN_SIZEMOVE;
-    VERIFY(::SetWindowPos(mWnd, nullptr, x, y, 0, 0, flags));
-    mResizeState = NOT_RESIZING;
-    if (WinUtils::LogToPhysFactor(mWnd) != oldScale) {
-      ChangedDPI();
+
+    // Normally, when the skeleton UI is disabled, we resize+move the window
+    // before showing it in order to ensure that it restores to the correct
+    // position when the user un-maximizes it. However, when we are using the
+    // skeleton UI, this results in the skeleton UI window being moved around
+    // undesirably before being locked back into the maximized position. To
+    // avoid this, we simply set the placement to restore to via
+    // SetWindowPlacement. It's a little bit more of a dance, though, since we
+    // need to convert the workspace coords that SetWindowPlacement uses to the
+    // screen space coordinates we normally use with SetWindowPos.
+    if (mIsShowingPreXULSkeletonUI && WasPreXULSkeletonUIMaximized()) {
+      WINDOWPLACEMENT pl = {sizeof(WINDOWPLACEMENT)};
+      VERIFY(::GetWindowPlacement(mWnd, &pl));
+
+      HMONITOR monitor = ::MonitorFromWindow(mWnd, MONITOR_DEFAULTTONULL);
+      if (NS_WARN_IF(!monitor)) {
+        return;
+      }
+      MONITORINFO mi = {sizeof(MONITORINFO)};
+      VERIFY(::GetMonitorInfo(monitor, &mi));
+
+      int32_t deltaX =
+          x + mi.rcWork.left - mi.rcMonitor.left - pl.rcNormalPosition.left;
+      int32_t deltaY =
+          y + mi.rcWork.top - mi.rcMonitor.top - pl.rcNormalPosition.top;
+      pl.rcNormalPosition.left += deltaX;
+      pl.rcNormalPosition.right += deltaX;
+      pl.rcNormalPosition.top += deltaY;
+      pl.rcNormalPosition.bottom += deltaY;
+      VERIFY(::SetWindowPlacement(mWnd, &pl));
+    } else {
+      ClearThemeRegion();
+
+      UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE;
+      // Workaround SetWindowPos bug with D3D9. If our window has a clip
+      // region, some drivers or OSes may incorrectly copy into the clipped-out
+      // area.
+      if (IsPlugin() && !mLayerManager && mClipRects &&
+          (mClipRectCount != 1 ||
+           !mClipRects[0].IsEqualInterior(
+               LayoutDeviceIntRect(0, 0, mBounds.Width(), mBounds.Height())))) {
+        flags |= SWP_NOCOPYBITS;
+      }
+      double oldScale = mDefaultScale;
+      mResizeState = IN_SIZEMOVE;
+      VERIFY(::SetWindowPos(mWnd, nullptr, x, y, 0, 0, flags));
+      mResizeState = NOT_RESIZING;
+      if (WinUtils::LogToPhysFactor(mWnd) != oldScale) {
+        ChangedDPI();
+      }
     }
 
     SetThemeRegion();
 
     ResizeDirectManipulationViewport();
   }
   NotifyRollupGeometryChange();
 }
@@ -1965,34 +2029,46 @@ void nsWindow::Resize(double aWidth, dou
     }
     return;
   }
 
   // Set cached value for lightweight and printing
   mBounds.SizeTo(width, height);
 
   if (mWnd) {
-    UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE;
-
-    if (!aRepaint) {
-      flags |= SWP_NOREDRAW;
-    }
-
-    ClearThemeRegion();
-    double oldScale = mDefaultScale;
-    mResizeState = RESIZING;
-    VERIFY(
-        ::SetWindowPos(mWnd, nullptr, 0, 0, width, GetHeight(height), flags));
-    mResizeState = NOT_RESIZING;
-    if (WinUtils::LogToPhysFactor(mWnd) != oldScale) {
-      ChangedDPI();
-    }
-    SetThemeRegion();
-
-    ResizeDirectManipulationViewport();
+    // Refer to the comment above a similar check in nsWindow::Move
+    if (mIsShowingPreXULSkeletonUI && WasPreXULSkeletonUIMaximized()) {
+      WINDOWPLACEMENT pl = {sizeof(WINDOWPLACEMENT)};
+      VERIFY(::GetWindowPlacement(mWnd, &pl));
+      pl.rcNormalPosition.right = pl.rcNormalPosition.left + width;
+      pl.rcNormalPosition.bottom = pl.rcNormalPosition.top + GetHeight(height);
+      mResizeState = RESIZING;
+      VERIFY(::SetWindowPlacement(mWnd, &pl));
+      mResizeState = NOT_RESIZING;
+    } else {
+      UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE;
+
+      if (!aRepaint) {
+        flags |= SWP_NOREDRAW;
+      }
+
+      ClearThemeRegion();
+      double oldScale = mDefaultScale;
+      mResizeState = RESIZING;
+      VERIFY(
+          ::SetWindowPos(mWnd, nullptr, 0, 0, width, GetHeight(height), flags));
+
+      mResizeState = NOT_RESIZING;
+      if (WinUtils::LogToPhysFactor(mWnd) != oldScale) {
+        ChangedDPI();
+      }
+      SetThemeRegion();
+
+      ResizeDirectManipulationViewport();
+    }
   }
 
   if (aRepaint) Invalidate();
 
   NotifyRollupGeometryChange();
 }
 
 // Resize this component
@@ -2019,40 +2095,65 @@ void nsWindow::Resize(double aX, double 
     }
     return;
   }
 
   // Set cached value for lightweight and printing
   mBounds.SetRect(x, y, width, height);
 
   if (mWnd) {
-    UINT flags = SWP_NOZORDER | SWP_NOACTIVATE;
-    if (!aRepaint) {
-      flags |= SWP_NOREDRAW;
-    }
-
-    ClearThemeRegion();
-    double oldScale = mDefaultScale;
-    mResizeState = RESIZING;
-    VERIFY(
-        ::SetWindowPos(mWnd, nullptr, x, y, width, GetHeight(height), flags));
-    mResizeState = NOT_RESIZING;
-    if (WinUtils::LogToPhysFactor(mWnd) != oldScale) {
-      ChangedDPI();
-    }
-    if (mTransitionWnd) {
-      // If we have a fullscreen transition window, we need to make
-      // it topmost again, otherwise the taskbar may be raised by
-      // the system unexpectedly when we leave fullscreen state.
-      ::SetWindowPos(mTransitionWnd, HWND_TOPMOST, 0, 0, 0, 0,
-                     SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
-    }
-    SetThemeRegion();
-
-    ResizeDirectManipulationViewport();
+    // Refer to the comment above a similar check in nsWindow::Move
+    if (mIsShowingPreXULSkeletonUI && WasPreXULSkeletonUIMaximized()) {
+      WINDOWPLACEMENT pl = {sizeof(WINDOWPLACEMENT)};
+      VERIFY(::GetWindowPlacement(mWnd, &pl));
+
+      HMONITOR monitor = ::MonitorFromWindow(mWnd, MONITOR_DEFAULTTONULL);
+      if (NS_WARN_IF(!monitor)) {
+        return;
+      }
+      MONITORINFO mi = {sizeof(MONITORINFO)};
+      VERIFY(::GetMonitorInfo(monitor, &mi));
+
+      int32_t deltaX =
+          x + mi.rcWork.left - mi.rcMonitor.left - pl.rcNormalPosition.left;
+      int32_t deltaY =
+          y + mi.rcWork.top - mi.rcMonitor.top - pl.rcNormalPosition.top;
+      pl.rcNormalPosition.left += deltaX;
+      pl.rcNormalPosition.right = pl.rcNormalPosition.left + width;
+      pl.rcNormalPosition.top += deltaY;
+      pl.rcNormalPosition.bottom = pl.rcNormalPosition.top + GetHeight(height);
+      VERIFY(::SetWindowPlacement(mWnd, &pl));
+    } else {
+      UINT flags = SWP_NOZORDER | SWP_NOACTIVATE;
+      if (!aRepaint) {
+        flags |= SWP_NOREDRAW;
+      }
+
+      ClearThemeRegion();
+
+      double oldScale = mDefaultScale;
+      mResizeState = RESIZING;
+      VERIFY(
+          ::SetWindowPos(mWnd, nullptr, x, y, width, GetHeight(height), flags));
+      mResizeState = NOT_RESIZING;
+      if (WinUtils::LogToPhysFactor(mWnd) != oldScale) {
+        ChangedDPI();
+      }
+
+      if (mTransitionWnd) {
+        // If we have a fullscreen transition window, we need to make
+        // it topmost again, otherwise the taskbar may be raised by
+        // the system unexpectedly when we leave fullscreen state.
+        ::SetWindowPos(mTransitionWnd, HWND_TOPMOST, 0, 0, 0, 0,
+                       SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+      }
+      SetThemeRegion();
+
+      ResizeDirectManipulationViewport();
+    }
   }
 
   if (aRepaint) Invalidate();
 
   NotifyRollupGeometryChange();
 }
 
 mozilla::Maybe<bool> nsWindow::IsResizingNativeWidget() {
@@ -2162,16 +2263,24 @@ static UINT GetCurrentShowCmd(HWND aWnd)
 
 // Maximize, minimize or restore the window.
 void nsWindow::SetSizeMode(nsSizeMode aMode) {
   // Let's not try and do anything if we're already in that state.
   // (This is needed to prevent problems when calling window.minimize(), which
   // calls us directly, and then the OS triggers another call to us.)
   if (aMode == mSizeMode) return;
 
+  // If we are still displaying a maximized pre-XUL skeleton UI, ignore the
+  // noise of sizemode changes. Once we have "shown" the window for the first
+  // time (called nsWindow::Show(true), even though the window is already
+  // technically displayed), we will again accept sizemode changes.
+  if (mIsShowingPreXULSkeletonUI && WasPreXULSkeletonUIMaximized()) {
+    return;
+  }
+
   // save the requested state
   mLastSizeMode = mSizeMode;
   nsBaseWidget::SetSizeMode(aMode);
   if (mIsVisible) {
     int mode;
 
     switch (aMode) {
       case nsSizeMode_Fullscreen:
@@ -5313,16 +5422,18 @@ bool nsWindow::ProcessMessage(UINT msg, 
         if (hdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
           // This can only change media queries (any-hover/any-pointer).
           NotifyThemeChanged(widget::ThemeChangeKind::MediaQueriesOnly);
         }
       }
     } break;
 
     case WM_NCCALCSIZE: {
+      // NOTE: the following block is mirrored in PreXULSkeletonUI.cpp, and
+      // will need to be kept in sync.
       if (mCustomNonClient) {
         // If `wParam` is `FALSE`, `lParam` points to a `RECT` that contains
         // the proposed window rectangle for our window.  During our
         // processing of the `WM_NCCALCSIZE` message, we are expected to
         // modify the `RECT` that `lParam` points to, so that its value upon
         // our return is the new client area.  We must return 0 if `wParam`
         // is `FALSE`.
         //
@@ -8687,17 +8798,17 @@ void nsWindow::GetCompositorWidgetInitDa
       mTransparencyMode, mSizeMode);
 }
 
 bool nsWindow::SynchronouslyRepaintOnResize() {
   return !gfxWindowsPlatform::GetPlatform()->DwmCompositionEnabled();
 }
 
 void nsWindow::MaybeDispatchInitialFocusEvent() {
-  if (mWasPreXulSkeletonUI && ::GetActiveWindow() == mWnd) {
+  if (mIsShowingPreXULSkeletonUI && ::GetActiveWindow() == mWnd) {
     DispatchFocusToTopLevelWindow(true);
   }
 }
 
 already_AddRefed<nsIWidget> nsIWidget::CreateTopLevelWindow() {
   nsCOMPtr<nsIWidget> window = new nsWindow();
   return window.forget();
 }
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -601,17 +601,17 @@ class nsWindow final : public nsWindowBa
   bool mIsRTL;
   bool mFullscreenMode;
   bool mMousePresent;
   bool mMouseInDraggableArea;
   bool mDestroyCalled;
   bool mOpeningAnimationSuppressed;
   bool mAlwaysOnTop;
   bool mIsEarlyBlankWindow;
-  bool mWasPreXulSkeletonUI;
+  bool mIsShowingPreXULSkeletonUI;
   bool mResizable;
   DWORD_PTR mOldStyle;
   DWORD_PTR mOldExStyle;
   nsNativeDragTarget* mNativeDragTarget;
   HKL mLastKeyboardLayout;
   nsSizeMode mOldSizeMode;
   nsSizeMode mLastSizeMode;
   WindowHook mWindowHook;
--- a/xpfe/appshell/AppWindow.cpp
+++ b/xpfe/appshell/AppWindow.cpp
@@ -1830,19 +1830,20 @@ nsresult AppWindow::MaybeSaveEarlyWindow
     // defined in urlbar-searchbar.inc.css as 5px
     int urlbarMarginInline = 5;
 
     // breakout-extend measurements are defined in urlbar-searchbar.inc.css
     urlbarX += (double)(urlbarBreakoutExtend + urlbarMarginInline);
     urlbarWidth -= (double)(2 * (urlbarBreakoutExtend + urlbarMarginInline));
   }
 
-  PersistPreXULSkeletonUIValues(aRect.X(), aRect.Y(), aRect.Width(),
-                                aRect.Height(), urlbarX, urlbarWidth,
-                                mWindow->GetDefaultScale().scale);
+  PersistPreXULSkeletonUIValues(
+      aRect.X(), aRect.Y(), aRect.Width(), aRect.Height(),
+      mWindow->SizeMode() == nsSizeMode_Maximized, urlbarX, urlbarWidth,
+      mWindow->GetDefaultScale().scale);
 #endif
 
   return NS_OK;
 }
 
 nsresult AppWindow::SetPersistentValue(const nsAtom* aAttr,
                                        const nsAString& aValue) {
   nsAutoString uri;