diff --git a/context/pod-hardware.md b/context/pod-hardware.md index c525d5e..7e41158 100644 --- a/context/pod-hardware.md +++ b/context/pod-hardware.md @@ -371,6 +371,17 @@ input device changes, which is what the glass/PadRIO seam was built for. Do NOT pedals `0..470`). A mismatch shows up as drift or short travel, not as an error. - The boot banner names the resolved device — `GLASS (hardware RIO; plasma off [L4PLASMA])`. It used to hardcode "PadRIO", which is a lie on a wired cab and exactly the line you read to check. +- ⚠ **THE COUPLING BUG this exposed (fixed 2026-08-06) [T2].** `BTGlassPanels_Create()` was called + ONLY from the end of the **PadRIO constructor** — the panels began life as the frames around the + on-screen RIO button banks, so "the buttons ride the device". Selecting the hardware RIO means + PadRIO is never constructed, so **every MFD window silently failed to appear**: the mission came + up on the main view with all the pod glass dark, and not one `[glasswin]` line in the log. The + MFD panels are a DISPLAY concern, so creation moved to `LBE4ControlsManager` after the + `L4CONTROLS` parse, where every device branch converges — plus a symmetric `BTGlassPanels_Destroy()` + in its destructor, because `~PadRIO` tore them down and `~RIO` knows nothing about them (windows + outliving the surfaces they blit would crash on the next mission cycle). Both calls are + idempotent (`Create` returns on `gWinCount != 0`), so the PadRIO path is unchanged and simply + arrives first. **Working on the cart, remotely.** SSH over Tailscale lands in **session 0**, which has a dummy "WinDisc" display and CANNOT see or enumerate session 1's windows — GUI work must go through diff --git a/engine/MUNGA_L4/L4CTRL.cpp b/engine/MUNGA_L4/L4CTRL.cpp index 28924c9..49a31b4 100644 --- a/engine/MUNGA_L4/L4CTRL.cpp +++ b/engine/MUNGA_L4/L4CTRL.cpp @@ -9,6 +9,10 @@ #include "dxutils.h" #ifdef BT_GLASS #include "l4padrio.h" +#ifdef BT_GLASS +#include "l4glasswin.h" // the per-display MFD windows -- created below for + // EITHER RIO (they used to ride the PadRIO ctor) +#endif #endif // @@ -865,6 +869,29 @@ LBE4ControlsManager::LBE4ControlsManager(): while (temp[0] != '\0'); } + //-------------------------------------------------- + // The per-display MFD windows (2026-08-06) + //-------------------------------------------------- + // These used to be created ONLY at the end of the PadRIO constructor, + // because they began life as the frames around the on-screen RIO button + // banks -- "the buttons ride the device". On a real cab that coupling is + // backwards: selecting the HARDWARE RIO means PadRIO is never built, so + // the MFD panels never appeared at all. Found on the crash cart, where + // the mission came up on the main view with every MFD dark. + // + // The windows are a DISPLAY concern, so create them here -- after the + // L4CONTROLS parse, where every device branch converges -- and let them + // exist whichever RIO won. In pod surface mode there are no on-screen + // buttons on them at all. Create() is idempotent (`gWinCount != 0` + // returns), so the PadRIO call site stays valid and simply arrives first. + // +#ifdef BT_GLASS + if (rioPointer != NULL && BTGlassPanelsActive()) + { + BTGlassPanels_Create(); + } +#endif + //-------------------------------------------------- // Clear all lamps (and reset analog I/O) //-------------------------------------------------- @@ -1089,6 +1116,17 @@ LBE4ControlsManager::~LBE4ControlsManager() rioPointer = NULL; } +#ifdef BT_GLASS + // + // Symmetric with the Create above (2026-08-06). ~PadRIO tears the panels + // down itself, so this is a no-op there -- but the HARDWARE RIO's dtor + // knows nothing about them, and windows that outlive the surfaces they + // blit are a crash waiting for the next mission cycle. Destroy is safe + // if they were never created. + // + BTGlassPanels_Destroy(); +#endif + Check_Fpu(); }