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:
co-authored by
Claude Fable 5
parent
bf39b81b9d
commit
67a4f09e86
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user