noframe: drop the drag-by-surface -- it is a finishing step, not a mode
Author's correction to the shape of yesterday's option. The intended workflow is: place the displays where you want them WITH their frames, quit, then edit glass_layout.cfg to turn the frame off. So a ,noframe window should be pinned, not draggable -- removed the WM_NCHITTEST -> HTCAPTION handler that made the surface a drag handle. The arrangement being finished is the point: with no caption there is nothing to drag it by, which is exactly what you want on a wall of monitors. Delete the flag to get the frame (and the dragging) back. Unchanged and still needed: SaveLayout writes the flag back, because any later drag of a FRAMED window rewrites the whole file and would otherwise strip it. Re-verified live: - Heat MFD comes up with WS_CAPTION clear and answers WM_NCHITTEST on its surface with HTCLIENT (pinned) -- no window reports HTCAPTION any more. - Comm MFD (unflagged) keeps its caption. - A framed window's WM_EXITSIZEMOVE rewrote the file and BOTH ,noframe flags survived, with the new header explaining the arrange-first workflow. - surround / exploded / pod / dev boot and simulate clean. Docs updated to describe the two-stage workflow rather than surface dragging: the file's own header, environ.ini's BT_GLASS_LAYOUT block, context/ glass-cockpit.md and the ledger (which records the removed behaviour so the next reader does not re-add it). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+16
-14
@@ -141,27 +141,29 @@ analogue of TeslaRel410 `emulator/pod-launch`'s per-rig `--bridge-pos`/`--layout
|
|||||||
|
|
||||||
### `,noframe` — per-window chrome removal (2026-07-29) [T2 live]
|
### `,noframe` — per-window chrome removal (2026-07-29) [T2 live]
|
||||||
|
|
||||||
Append it to a window's line and that window loses its title bar and border (`WS_POPUP`) — for a
|
Append it to a window's line and that window comes up with no title bar or border (`WS_POPUP`) —
|
||||||
multi-monitor wall where the chrome is just noise:
|
for a multi-monitor wall where the chrome is just noise:
|
||||||
|
|
||||||
```
|
```
|
||||||
Heat MFD=1920,0,657,539,noframe
|
Heat MFD=1920,0,657,539,noframe
|
||||||
```
|
```
|
||||||
|
|
||||||
Hand-edited (the file is otherwise machine-written). Options are comma-separated after the
|
**The workflow is deliberately two-stage, and this is the last step:** run with
|
||||||
numbers and **unknown ones are ignored**, so an older build reading a newer file loses the option
|
`BT_GLASS_LAYOUT=save` and drag the windows where you want them (they have title bars, so it is
|
||||||
but never the line — the `bindings.txt` grammar rule applied here.
|
the normal sticky-layout flow) → quit → hand-edit the cfg and append `,noframe` to the ones you
|
||||||
|
want bare. From then on those windows are frameless **and pinned** — with no caption there is
|
||||||
|
nothing to drag them by, which is the point: the arrangement is finished. Delete the flag to get
|
||||||
|
the frame back.
|
||||||
|
|
||||||
Two consequences it has to carry, or the option would be a trap:
|
Options are comma-separated after the numbers and **unknown ones are ignored**, so an older build
|
||||||
- **A frameless window has no title bar to drag** — which is the entire sticky-layout workflow.
|
reading a newer file loses the option but never the line — the `bindings.txt` grammar rule
|
||||||
So a `noframe` window is dragged **by its surface**: `WM_NCHITTEST` returns `HTCAPTION`
|
applied here.
|
||||||
anywhere that is not a button and `HTCLIENT` over one, so buttons stay clickable and the drag
|
|
||||||
still ends in `WM_EXITSIZEMOVE` and still saves.
|
|
||||||
- **`SaveLayout` rewrites the whole file**, so it writes the flag back — otherwise the first save
|
|
||||||
after a drag would silently strip it.
|
|
||||||
|
|
||||||
The flag is read BEFORE frame sizing (a `LoadLayout(quiet)` pre-pass), because `AdjustWindowRect`
|
The one thing it must not do is eat itself: **`SaveLayout` rewrites the WHOLE file** (any later
|
||||||
and therefore `ComputeLayout`'s ring placement depend on whether a window carries chrome.
|
drag of a framed window triggers it), so it writes the flag back for every window carrying it.
|
||||||
|
And the flag is read BEFORE frame sizing (a `LoadLayout(quiet)` pre-pass), because
|
||||||
|
`AdjustWindowRect` — and therefore `ComputeLayout`'s ring placement — depends on whether a window
|
||||||
|
carries chrome.
|
||||||
|
|
||||||
Verified live: two flagged windows came up caption-less while the other five kept theirs, a click
|
Verified live: two flagged windows came up caption-less while the other five kept theirs, a click
|
||||||
still dispatched on the frameless radar (`CLICK 'Secondary / Radar' addr=0x18`), and a
|
still dispatched on the frameless radar (`CLICK 'Secondary / Radar' addr=0x18`), and a
|
||||||
|
|||||||
+16
-7
@@ -777,13 +777,22 @@ Options are comma-separated after the four numbers and unknown ones are IGNORED,
|
|||||||
reading a newer file loses the option but never the line (the bindings.txt grammar rule applied
|
reading a newer file loses the option but never the line (the bindings.txt grammar rule applied
|
||||||
here). Hand-edited; the file is otherwise machine-written.
|
here). Hand-edited; the file is otherwise machine-written.
|
||||||
|
|
||||||
### The two things that would have made it a trap
|
### The workflow is two-stage, on purpose
|
||||||
1. **A frameless window has no title bar to drag** -- which is the entire point of the sticky
|
Arrange FIRST, strip chrome LAST:
|
||||||
layout. So a noframe window is dragged BY ITS SURFACE: `WM_NCHITTEST` returns `HTCAPTION`
|
1. run with `BT_GLASS_LAYOUT=save` and drag the windows where you want them (they have title
|
||||||
anywhere that is not a button and `HTCLIENT` over one. Buttons stay clickable, and because
|
bars -- this is just the normal sticky-layout flow),
|
||||||
Windows drives the move, the drag still ends in `WM_EXITSIZEMOVE` -- so it still SAVES.
|
2. quit,
|
||||||
2. **SaveLayout rewrites the whole file**, so it writes the flag back. Without that the first
|
3. hand-edit the cfg and append `,noframe` to the ones you want bare.
|
||||||
finished-drag after adding the option would have silently stripped it.
|
|
||||||
|
From then on those windows come up frameless AND PINNED -- with no caption there is nothing to
|
||||||
|
drag them by, which is the point: the arrangement is finished. Delete the flag to re-frame.
|
||||||
|
|
||||||
|
(An earlier cut made noframe windows draggable by their surface via `WM_NCHITTEST`->`HTCAPTION`.
|
||||||
|
Removed at the author's direction: it is not an interactive mode, it is the finishing step.)
|
||||||
|
|
||||||
|
The one thing it must not do is eat itself: **SaveLayout rewrites the WHOLE file** -- any later
|
||||||
|
drag of a FRAMED window triggers it -- so it writes the flag back for every window that carries
|
||||||
|
one. Without that, the first drag after adding the option would silently strip it.
|
||||||
|
|
||||||
### Ordering
|
### Ordering
|
||||||
The flag is read BEFORE frame sizing (`LoadLayout(quiet)` pre-pass, then the normal pass after
|
The flag is read BEFORE frame sizing (`LoadLayout(quiet)` pre-pass, then the normal pass after
|
||||||
|
|||||||
@@ -383,19 +383,22 @@ static void
|
|||||||
//
|
//
|
||||||
// PER-LINE OPTION ",noframe" (2026-07-29): append it to a window's line and
|
// PER-LINE OPTION ",noframe" (2026-07-29): append it to a window's line and
|
||||||
// that window loses its title bar and border (WS_POPUP) -- for a clean
|
// that window loses its title bar and border (WS_POPUP) -- for a clean
|
||||||
// multi-monitor wall where the chrome is just noise. Hand-edited; the file
|
// multi-monitor wall where the chrome is just noise.
|
||||||
// is otherwise machine-written.
|
|
||||||
//
|
//
|
||||||
// Heat MFD=1920,0,657,539,noframe
|
// Heat MFD=1920,0,657,539,noframe
|
||||||
//
|
//
|
||||||
// Two consequences it has to carry, or the option would be a trap:
|
// THE WORKFLOW IS DELIBERATELY TWO-STAGE, and the option is the last step:
|
||||||
// - a frameless window has NO TITLE BAR TO DRAG, which is how the whole
|
// 1. run with BT_GLASS_LAYOUT=save and DRAG the windows where you want them
|
||||||
// sticky-layout workflow works. So a noframe window is draggable BY ITS
|
// (they have title bars, so this is the normal sticky-layout flow),
|
||||||
// SURFACE (WM_NCHITTEST -> HTCAPTION anywhere that is not a button); the
|
// 2. quit,
|
||||||
// buttons stay clickable, and the drag still ends in WM_EXITSIZEMOVE so it
|
// 3. hand-edit the cfg and append ,noframe to the ones you want bare.
|
||||||
// still saves.
|
// From then on those windows come up frameless AND PINNED -- with no caption
|
||||||
// - SaveLayout rewrites the whole file, so it must WRITE THE FLAG BACK or the
|
// there is nothing to drag them by, which is the point: the arrangement is
|
||||||
// first save after a drag would silently strip it.
|
// finished. Re-frame a window by deleting the flag.
|
||||||
|
//
|
||||||
|
// The one thing it must not do is eat itself: SaveLayout rewrites the WHOLE
|
||||||
|
// file (any later drag of a FRAMED window triggers it), so it writes the flag
|
||||||
|
// back for every window that carries it.
|
||||||
//###########################################################################
|
//###########################################################################
|
||||||
|
|
||||||
enum { LayoutOff = 0, LayoutLoad = 1, LayoutSave = 2 };
|
enum { LayoutOff = 0, LayoutLoad = 1, LayoutSave = 2 };
|
||||||
@@ -536,9 +539,13 @@ static void
|
|||||||
|
|
||||||
fputs("# BT411 glass cockpit window layout (BT_GLASS_LAYOUT=save writes this\n"
|
fputs("# BT411 glass cockpit window layout (BT_GLASS_LAYOUT=save writes this\n"
|
||||||
"# on finished-drag/exit; =load restores it). <title>=<x>,<y>,<w>,<h>\n"
|
"# on finished-drag/exit; =load restores it). <title>=<x>,<y>,<w>,<h>\n"
|
||||||
"# Append ,noframe to a line to drop that window's title bar and border;\n"
|
"#\n"
|
||||||
"# a frameless window is dragged by its SURFACE instead (buttons still\n"
|
"# Happy with where everything sits? Quit, then append ,noframe to any\n"
|
||||||
"# click). Hand-edit to add it -- saves preserve it.\n",
|
"# line to bring that window up with no title bar or border:\n"
|
||||||
|
"# Heat MFD=1920,0,657,539,noframe\n"
|
||||||
|
"# A frameless window is also PINNED (no caption = nothing to drag it\n"
|
||||||
|
"# by), so do the arranging first. Delete the flag to get the frame\n"
|
||||||
|
"# back. Saves preserve it.\n",
|
||||||
f);
|
f);
|
||||||
int wrote = 0;
|
int wrote = 0;
|
||||||
for (int i = 0; i < gWinCount; ++i)
|
for (int i = 0; i < gWinCount; ++i)
|
||||||
@@ -842,23 +849,6 @@ static LRESULT CALLBACK
|
|||||||
case WM_ERASEBKGND:
|
case WM_ERASEBKGND:
|
||||||
return 1; // PaintGlass fills the frame (double-buffered)
|
return 1; // PaintGlass fills the frame (double-buffered)
|
||||||
|
|
||||||
//
|
|
||||||
// ",noframe" windows have no title bar, so the SURFACE is the drag handle:
|
|
||||||
// report HTCAPTION anywhere that is not a button and Windows moves the
|
|
||||||
// window for us -- including the WM_EXITSIZEMOVE at the end, so a drag
|
|
||||||
// still sticks in save mode. Over a button we report HTCLIENT so the
|
|
||||||
// press reaches WM_LBUTTONDOWN as usual.
|
|
||||||
//
|
|
||||||
case WM_NCHITTEST:
|
|
||||||
if (w != NULL && w->noFrame)
|
|
||||||
{
|
|
||||||
POINT p;
|
|
||||||
p.x = (int)(short)LOWORD(lparam);
|
|
||||||
p.y = (int)(short)HIWORD(lparam);
|
|
||||||
ScreenToClient(window, &p);
|
|
||||||
return (HitTest(w, p.x, p.y) >= 0) ? HTCLIENT : HTCAPTION;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_TIMER:
|
case WM_TIMER:
|
||||||
if (wparam == RepaintTimerId)
|
if (wparam == RepaintTimerId)
|
||||||
|
|||||||
+5
-4
@@ -298,11 +298,12 @@ static const char *kEnvironIniDefault =
|
|||||||
"# The positions live in glass_layout.cfg beside this file -- delete it to go\n"
|
"# The positions live in glass_layout.cfg beside this file -- delete it to go\n"
|
||||||
"# back to the pod ring. Windows not in the file keep their computed spot.\n"
|
"# back to the pod ring. Windows not in the file keep their computed spot.\n"
|
||||||
"#\n"
|
"#\n"
|
||||||
"# In that file you can also append ,noframe to a window's line to strip its\n"
|
"# Once everything is where you want it, quit and append ,noframe to any line\n"
|
||||||
"# title bar and border -- handy on a multi-monitor wall where the chrome is\n"
|
"# in that file to bring that window up with no title bar or border -- handy\n"
|
||||||
"# just noise. A frameless window is dragged by its SURFACE instead (the\n"
|
"# on a multi-monitor wall where the chrome is just noise:\n"
|
||||||
"# buttons still click), and saves keep the flag:\n"
|
|
||||||
"# Heat MFD=1920,0,657,539,noframe\n"
|
"# Heat MFD=1920,0,657,539,noframe\n"
|
||||||
|
"# Arrange FIRST: a frameless window is also pinned (no caption means nothing\n"
|
||||||
|
"# to drag it by). Delete the flag to get the frame back.\n"
|
||||||
"#BT_GLASS_LAYOUT=save\n"
|
"#BT_GLASS_LAYOUT=save\n"
|
||||||
"\n"
|
"\n"
|
||||||
"# Size of the secondary displays in the cockpit surround, as a percentage of\n"
|
"# Size of the secondary displays in the cockpit surround, as a percentage of\n"
|
||||||
|
|||||||
Reference in New Issue
Block a user