From bfd5fa163e42d4b4f9b06bfff90bd21bcc429ef8 Mon Sep 17 00:00:00 2001 From: Cyd Date: Wed, 29 Jul 2026 10:01:16 -0500 Subject: [PATCH] EXIT GAME on the console screen ,noframe takes the title bar away, and with it the only way out of the game. The console screen now offers its own, bottom left: half width and diagonally opposite LAUNCH GAME, because it is the one button on that screen you cannot undo and it should not sit next to the one everybody is aiming for. It goes through the same door as closing the window - fe.closed, so RPL4FrontEnd_Run returns False and the race loop breaks - rather than opening a second shutdown path. Two things had to move for it to make sense. The saved placement now loads in RPL4.CPP, right after the main window is shown, instead of only when SVGA16 builds the cockpit. That was not until a mission started, so the console screen came up at the default rect with its title bar still on and the window only jumped to the saved placement once a race began - which, for a flag whose whole purpose is to take the title bar off, meant it did nothing on the screen you land on. RPL4.CPP now owns the main window's registration outright and SVGA16's branches only reload; the reload after CockpitShellProc goes on still matters, since its WM_SIZE is what re-fits the canvas. That in turn made the exploded view's position-only registration incoherent - the startup load had already applied the size - so the game window is simply position and size everywhere now. The earlier reasoning that its exploded size IS the -res render size does not hold: the back buffer stretches to the window in either view, exactly as it does for the cockpit. WM_EXITSIZEMOVE moves from the cockpit subclass to RPL4.CPP's own WndProc, which the subclass chains to anyway. In its old home it only existed once a cockpit had been built, so dragging the window on the console screen - the obvious moment to put it where you want it - saved nothing. There is also a save on the way out of WinMain, for a session that never started a race and so never ran SVGA16's teardown save. Verified: on a bare-framed window the console screen comes up at the saved 1280x760 with client == window rect, EXIT GAME ends the process with code 0, and a screenshot shows it clear of the column content. A console-only session dragged to 333,222 900x640 wrote that on the drag, kept it through the exit, and came back to exactly it on relaunch - without a race anywhere in the round trip. The noframe and cockpit round trips still pass unchanged. Co-Authored-By: Claude Opus 5 (1M context) --- MUNGA_L4/L4MFDVIEW.h | 15 ++++++++------- MUNGA_L4/L4VB16.cpp | 39 ++++++++++++--------------------------- RP_L4/RPL4.CPP | 38 ++++++++++++++++++++++++++++++++++++++ RP_L4/RPL4FE.cpp | 25 +++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 34 deletions(-) diff --git a/MUNGA_L4/L4MFDVIEW.h b/MUNGA_L4/L4MFDVIEW.h index 27666cc..d85fd1f 100644 --- a/MUNGA_L4/L4MFDVIEW.h +++ b/MUNGA_L4/L4MFDVIEW.h @@ -195,13 +195,14 @@ protected: // display panes position only. 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. +// the game window position and size. Nothing derives that size - -res +// only decides how sharp the scene is, and 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. RPL4.CPP registers it before the console +// screen, so the saved placement is there from the +// first frame rather than arriving when a race starts. // // A placement that lands on none of the monitors currently plugged in is // ignored rather than applied - restoring the game window off screen diff --git a/MUNGA_L4/L4VB16.cpp b/MUNGA_L4/L4VB16.cpp index d34d1a8..89c9ebb 100644 --- a/MUNGA_L4/L4VB16.cpp +++ b/MUNGA_L4/L4VB16.cpp @@ -3839,15 +3839,11 @@ 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(); - } + // + // WM_EXITSIZEMOVE is not handled here: RPL4.CPP's own WndProc takes + // it, and this chains straight through to that, so the shell saves on + // every finished drag whether or not a cockpit has been built. + // return CallWindowProcA(gCockpitBaseProc, hwnd, message, wParam, lParam); } @@ -4467,23 +4463,12 @@ SVGA16::SVGA16( work.left + right_x, work.top + bottom_y); splitView[SplitMap]->SetPosition(work.left + map_x, work.top + map_y); - // - // 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. + // arrangement just computed above. The game window is registered + // already - RPL4.CPP does that before the console screen ever + // shows - so this picks it up alongside the panes. // RPWindowLayout_Load(); } @@ -4702,16 +4687,16 @@ SVGA16::SVGA16( // 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. + // back that way. RPL4.CPP registered it before the console + // screen; this reload undoes the sizing just done above, and + // runs after the subclass on purpose so its WM_SIZE puts + // LayoutCockpit over 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(); } } diff --git a/RP_L4/RPL4.CPP b/RP_L4/RPL4.CPP index 828b99e..86ffa97 100644 --- a/RP_L4/RPL4.CPP +++ b/RP_L4/RPL4.CPP @@ -26,6 +26,7 @@ #include "rpl4lobby.h" #include "..\munga_l4\l4steamtransport.h" #include "..\munga_l4\l4splr.h" +#include "..\munga_l4\l4mfdview.h" // RPWindowLayout_* #include "rpl4ver.h" #include "..\munga\resver.h" #include "..\munga\resource.h" @@ -123,6 +124,15 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) return 0; } break; + case WM_EXITSIZEMOVE: + // + // A drag or resize just finished. Here rather than in the + // cockpit's subclass so it also covers the console screen, which + // is where the window gets moved before there is any cockpit to + // subclass. No-op unless RP412MFDLAYOUT is save. + // + RPWindowLayout_Save(); + return 0; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } @@ -254,6 +264,21 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine return FALSE; ShowWindow(hWnd, nShowCmd); + + // + // Sticky placement, from the first frame the player sees. SVGA16 also + // registers and reloads when it builds the cockpit, but that is not + // until a mission starts - without this the console screen would come + // up at the default rect with its title bar still on, and only jump + // to the saved placement once a race began. -fit takes the whole + // monitor and has no placement of the player's to restore. + // + if (!L4Application::GetFitDisplay() && !L4Application::GetFullscreen()) + { + RPWindowLayout_Register(hWnd, "RPL4", True); + RPWindowLayout_Load(); + } + #if !_DEBUG // Arcade pods have no mouse - but desktop/windowed play needs the // cursor for the on-screen cockpit buttons, so hide it only when @@ -475,6 +500,19 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine } } + // + // Last word on the window's placement. Every finished drag has already + // written it and SVGA16 writes again as the cockpit comes down, but a + // session that never started a race has neither - and quitting from + // the console screen is exactly how somebody would leave after moving + // the window to where they want it. No-op unless the mode is save. + // + if (IsWindow(hWnd)) + { + RPWindowLayout_Save(); + } + RPWindowLayout_Forget(hWnd); + #if !_DEBUG // symmetric with the fullscreen-only hide at startup if (L4Application::GetFullscreen()) diff --git a/RP_L4/RPL4FE.cpp b/RP_L4/RPL4FE.cpp index 2c07399..1a382ad 100644 --- a/RP_L4/RPL4FE.cpp +++ b/RP_L4/RPL4FE.cpp @@ -177,6 +177,7 @@ namespace GroupLaunch, GroupSteamHost, // buttons, not selections (Steam builds only) GroupSteamJoin, + GroupExit, GroupCount }; @@ -434,6 +435,23 @@ namespace join->rect.bottom = client_h - (7 * row_h) / 2; } + // + // Exit, bottom left. Diagonally opposite LAUNCH on purpose: it is + // the one button on this screen you cannot undo, so it does not go + // next to the one people are aiming for. Half width for the same + // reason - it is a way out, not a peer of LAUNCH. + // + // The window frame used to be the way out, and mfd_layout.cfg's + // ,noframe takes it away, so the screen has to offer its own. + // + FEItem *quit = &fe->items[fe->itemCount++]; + quit->group = GroupExit; + quit->index = 0; + quit->rect.left = col1; + quit->rect.top = client_h - 2 * row_h; + quit->rect.right = col1 + col_w / 2; + quit->rect.bottom = client_h - row_h; + // pilot name edit sits at the top of column 3 if (fe->nameEdit != NULL) { @@ -485,6 +503,7 @@ namespace case GroupLaunch: return "L A U N C H G A M E"; case GroupSteamHost: return "HOST STEAM GAME"; case GroupSteamJoin: return "JOIN STEAM GAME"; + case GroupExit: return "EXIT GAME"; } return ""; } @@ -647,6 +666,12 @@ namespace PostMessageA(fe->menuWindow, WM_NULL, 0, 0); } } + else if (item->group == GroupExit) + { + // the same door closing the window goes through + fe->closed = True; + PostMessageA(fe->menuWindow, WM_NULL, 0, 0); + } else { fe->selection[item->group] = item->index;