The game window remembers where you put it too

RP412MFDLAYOUT already kept the exploded view's display panes where they
were dragged. The main window is the one people move most, and it was
still being placed fresh every launch, so it joins them.

MFDSplitView_LoadLayout/SaveLayout become RPWindowLayout_Load/Save, with
Register/Forget taking any HWND rather than the module reaching into a
pane registry. Same file, same format, one more line in it.

What comes back depends on the window, so Register takes it as a flag:

  display panes    position only, as before. A pane's size follows its
                   content and its button banks, so an old size from a
                   different build must not distort it.
  the game window  position and size in the cockpit view. Nothing
                   derives that size - the cockpit fits itself to
                   whatever client area it is given - so a window sized
                   to suit a monitor should come back that way, and
                   half-restoring it would be the strange behaviour. In
                   the exploded view its size IS the render resolution
                   -res asked for, so there only the position returns.

Registered after the CockpitShellProc subclass is installed, on purpose:
the restore's WM_SIZE then runs LayoutCockpit again and the canvas
re-fits the restored client area. -fit does not register at all - it
owns the whole monitor, so there is no placement of the player's to
keep.

CockpitShellProc gained the WM_EXITSIZEMOVE hook the panes already had,
so dragging or resizing the shell writes the file immediately rather
than waiting for teardown.

Two hazards the panes were small enough to get away with and the game
window is not:

  - Save reads rcNormalPosition rather than GetWindowRect. A minimised
    window reports a nonsense rect and a maximised one reports the
    screen; since the file is rewritten whole, either would have
    replaced a good line with a useless one. rcNormalPosition is the
    restored placement whatever state the window is in.
  - Load drops any placement that intersects none of the monitors
    currently plugged in. Restoring the game window onto a display that
    is no longer there would leave nothing to drag back.

Verified by round trip in both views. Cockpit: dragged and resized to
240,120 1000x620, the file took it, a fresh launch in load mode came up
exactly there with a 984x581 client - and a screenshot confirms the
canvas re-fit it, displays at the corners and the map centred at the
bottom, nothing spilling. Exploded: the shell came back at 60,60 still
1280x720 from -res while Map came back at 777,333, which is the
size-flag split doing its job.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-29 09:00:33 -05:00
co-authored by Claude Opus 5
parent 16ce4dfbea
commit 40b00ddde1
5 changed files with 250 additions and 85 deletions
+47 -8
View File
@@ -3839,6 +3839,15 @@ static LRESULT CALLBACK
cockpit->LayoutCockpit(LOWORD(lParam), HIWORD(lParam));
}
}
else if (message == WM_EXITSIZEMOVE)
{
//
// The shell was just dragged or resized. Write the arrangement now
// rather than trusting teardown, so a hard kill still leaves what
// was on screen. No-op unless RP412MFDLAYOUT is save.
//
RPWindowLayout_Save();
}
return CallWindowProcA(gCockpitBaseProc, hwnd, message, wParam, lParam);
}
@@ -4459,11 +4468,24 @@ SVGA16::SVGA16(
splitView[SplitMap]->SetPosition(work.left + map_x, work.top + map_y);
//
// ...and then let RP412MFDLAYOUT put back anywhere they were
// dragged to last time. Panes the file does not mention keep the
// The game window joins them, position only: here its size is the
// render resolution -res asked for, so restoring an old one would
// leave a stretched back buffer in a window the wrong size.
//
{
HWND shell = ApplicationManager::GetCurrentManager()->GetHWnd();
if (shell != NULL)
{
RPWindowLayout_Register(shell, "RPL4", False);
}
}
//
// ...and then let RP412MFDLAYOUT put everything back where it was
// dragged to last time. Windows the file does not mention keep the
// arrangement just computed above.
//
MFDSplitView_LoadLayout();
RPWindowLayout_Load();
}
else if (splitViews)
{
@@ -4675,6 +4697,23 @@ SVGA16::SVGA16(
// catch maximise / restore / drag-resize and re-fit
gCockpitBaseProc = (WNDPROC) SetWindowLongPtrA(
cockpit, GWLP_WNDPROC, (LONG_PTR) CockpitShellProc);
//
// Sticky placement for the shell. Position AND size: nothing
// derives that size here - -res only decides how sharp the
// scene is - so a window sized to suit a monitor should come
// back that way. Registered after the subclass on purpose, so
// the restore's WM_SIZE runs LayoutCockpit again and the
// canvas re-fits the restored client area.
//
// -fit sits it borderless over the whole monitor, so there is
// no placement of the player's to remember.
//
if (!fit_display)
{
RPWindowLayout_Register(cockpit, "RPL4", True);
RPWindowLayout_Load();
}
}
else
{
@@ -4871,12 +4910,12 @@ SVGA16::~SVGA16()
//SVGASetSplitterClock(False);
//
// Backstop for the sticky exploded-view placement: every finished drag
// has already been written, but a pane moved and then closed straight
// away would otherwise be missed. Must run before the panes go - it
// reads their live window rects.
// Backstop for the sticky placement: every finished drag has already
// been written, but a window moved and then closed straight away would
// otherwise be missed. Must run before the panes go - it reads their
// live window rects, and the game window's.
//
MFDSplitView_SaveLayout();
RPWindowLayout_Save();
for (int view = 0; view < SplitViewCount; ++view)
{