POD MFD bring-up: BT_POD_SURFACES bare-panel mode + placement receipts + probe

Nick's crash cart is the first shot at driving the real MFD panels, so the
pieces the cab needs that the desktop glass path lacked:

- BT_POD_SURFACES=1 (L4GLASSWIN): crop every display window to its SURFACE
  (MFDs exactly 640x480, radar 480x640 portrait), drop the on-screen RIO
  button banks -- the cab's buttons are PHYSICAL, so drawing fake ones onto a
  real panel is exactly wrong -- go frameless, and skip the Flight Controls
  pad entirely (6 windows, not 7).  Per-window ",bare" in glass_layout.cfg
  for mixed rigs (idempotent with the global mode).
- Placement receipts: each window logs which PHYSICAL monitor it landed on
  ("[glasswin] 'Heat MFD' surface=Heat at X,Y 640x480 bare -> monitor
  \.\DISPLAYn (...)").  Nobody can see 7 surfaces at once on a cab, and over
  Chrome Remote Desktop you cannot see the panels at all -- the log is the
  only confirmation the map is right.
- tools/podprobe.ps1: run-on-the-pod topology probe (no install/admin) --
  GPUs, every monitor's virtual-desktop rect, EDID make/model, serial ports
  (the RIO board), session type, plus a PROPOSED glass_layout.cfg assigning
  the six surfaces to the non-primary monitors.  Self-tested here (correctly
  reports a single-monitor laptop and declines to map).

Local verify: 5 MFDs at 640x480 bare + portrait radar + Flight Controls
dropped, receipts printed.  KB: pod-hardware §MFD PANELS ON REAL HARDWARE
(incl. WHY the 1995 path is not the route -- NVIDIA Horizontal Span is gone
from post-XP drivers and per-adapter exclusive fullscreen is fragile over a
remote session) + glass-cockpit env table.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Joe DiPrima
2026-08-06 11:31:49 -05:00
co-authored by Claude Fable 5
parent bf39b81b9d
commit 67a4f09e86
4 changed files with 281 additions and 4 deletions
+92 -4
View File
@@ -407,6 +407,52 @@ enum { LayoutOff = 0, LayoutLoad = 1, LayoutSave = 2 };
static const char *layoutFileName = "glass_layout.cfg";
// POD SURFACE MODE (BT_POD_SURFACES=1, 2026-08-06) -- the REAL pod bring-up
// shape. On the actual cab each MFD is its own 640x480 panel with PHYSICAL
// buttons and lamps around it, so the desktop chrome the glass windows draw
// (the RIO button bank + the frame) is exactly wrong there: it would paint
// fake buttons onto a panel that has real ones behind glass. In pod mode a
// window is cropped to its SURFACE, frameless, and the bank is dropped:
// one clean picture per physical panel, positioned by glass_layout.cfg.
// The Flight Controls window (no surface at all) is not created.
// BT_POD_SURFACES=1 -> every display window goes bare
// glass_layout.cfg "<title>=x,y,bare" -> just that one (mixed rigs)
static int
PodSurfaceMode()
{
static int m = -1;
if (m < 0)
{
const char *e = getenv("BT_POD_SURFACES");
m = (e != NULL && *e != '\0' && *e != '0') ? 1 : 0;
if (m)
DEBUG_STREAM << "[glasswin] POD SURFACE MODE: bare surfaces, no "
"button banks (physical pod buttons assumed)\n" << std::flush;
}
return m;
}
// Crop a built window to its surface: drop the bank, move the picture to the
// client origin, go frameless. Called at the end of each Build* when pod mode
// is on (and from LoadLayout for a per-window ",bare").
static void
MakeBareSurface(GWin &w)
{
if (w.portPrimary == NULL) // Flight Controls -- nothing to show
{
w.clientW = w.clientH = 0;
w.buttonCount = 0;
return;
}
const int sw = w.surfaceRect.right - w.surfaceRect.left;
const int sh = w.surfaceRect.bottom - w.surfaceRect.top;
w.buttonCount = 0; // the pod's buttons are real
SetRect(&w.surfaceRect, 0, 0, sw, sh);
w.clientW = sw;
w.clientH = sh;
w.noFrame = 1;
}
// A framed window is a normal tool window; ",noframe" makes it a bare
// WS_POPUP -- no caption, no border, nothing but the display and its buttons.
static DWORD
@@ -580,16 +626,15 @@ static void
// Trailing options after the numbers, comma-separated. Unknown ones
// are ignored (so an older build reading a newer file just loses the
// option, never the line) -- the bindings.txt grammar rule.
int noframe = 0;
int noframe = 0, bare = 0;
for (const char *opt = strchr(eq + 1, ','); opt != NULL; opt = strchr(opt + 1, ','))
{
const char *t = opt + 1;
while (*t == ' ' || *t == '\t') ++t;
if (_strnicmp(t, "noframe", 7) == 0)
{
noframe = 1;
break;
}
else if (_strnicmp(t, "bare", 4) == 0)
bare = 1; // pod panel: surface only (see PodSurfaceMode)
}
GWin *gw = FindGWinByTitle(s);
@@ -598,6 +643,8 @@ static void
gw->wantX = x;
gw->wantY = y;
gw->noFrame = noframe;
if (bare && gw->buttonCount > 0)
MakeBareSurface(*gw); // per-window pod panel (mixed rigs)
gw->restored = 1;
++restored;
}
@@ -1090,6 +1137,16 @@ void
BuildFlight(gWins[6]); // 0x38-0x47
gWinCount = 7;
// POD SURFACE MODE: crop every display to its picture and drop the Flight
// Controls pad (it is pure desktop chrome -- the cab has a real stick).
if (PodSurfaceMode())
{
for (int i = 0; i < gWinCount; ++i)
MakeBareSurface(gWins[i]);
if (gWins[6].portPrimary == NULL)
gWinCount = 6; // drop Flight Controls
}
titleFont = CreateFontW(-11, 0, 0, 0, FW_BOLD, 0, 0, 0,
DEFAULT_CHARSET, 0, 0, CLEARTYPE_QUALITY, 0, L"Segoe UI");
buttonFont = CreateFontW(-10, 0, 0, 0, FW_NORMAL, 0, 0, 0,
@@ -1145,6 +1202,37 @@ void
SetLayeredWindowAttributes(w.hwnd, 0, 255, LWA_ALPHA);
SetTimer(w.hwnd, RepaintTimerId, RepaintMilliseconds, NULL);
ShowWindow(w.hwnd, SW_SHOWNOACTIVATE);
// PLACEMENT RECEIPT (pod bring-up, 2026-08-06): which PHYSICAL monitor
// each display actually landed on. On a real cab -- or any remote
// session -- nobody can see all seven surfaces at once, so the log is
// the only way to confirm the map without walking around the pod.
{
RECT wr = { 0, 0, 0, 0 };
GetWindowRect(w.hwnd, &wr);
HMONITOR mon = MonitorFromWindow(w.hwnd, MONITOR_DEFAULTTONEAREST);
MONITORINFOEXA mi;
memset(&mi, 0, sizeof(mi));
mi.cbSize = sizeof(mi);
const char *devName = "?";
int mx = 0, my = 0, mw = 0, mh = 0, primary = 0;
if (mon != NULL && GetMonitorInfoA(mon, (MONITORINFO *)&mi))
{
devName = mi.szDevice;
mx = mi.rcMonitor.left; my = mi.rcMonitor.top;
mw = mi.rcMonitor.right - mi.rcMonitor.left;
mh = mi.rcMonitor.bottom - mi.rcMonitor.top;
primary = (mi.dwFlags & MONITORINFOF_PRIMARY) ? 1 : 0;
}
DEBUG_STREAM << "[glasswin] '" << w.title << "' surface="
<< (w.portPrimary ? w.portPrimary : "-")
<< " at " << wr.left << "," << wr.top
<< " " << (wr.right - wr.left) << "x" << (wr.bottom - wr.top)
<< (w.noFrame ? " bare" : " framed")
<< " -> monitor " << devName
<< " (" << mx << "," << my << " " << mw << "x" << mh
<< (primary ? ", PRIMARY)" : ")") << "\n" << std::flush;
}
}
DEBUG_STREAM << "[glasswin] per-display cockpit up (" << gWinCount