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:
Cyd
2026-07-29 11:26:11 -05:00
co-authored by Claude Opus 5
parent f5f4c6c198
commit aa788bc56d
4 changed files with 57 additions and 55 deletions
+20 -30
View File
@@ -383,19 +383,22 @@ static void
//
// 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
// multi-monitor wall where the chrome is just noise. Hand-edited; the file
// is otherwise machine-written.
// multi-monitor wall where the chrome is just noise.
//
// Heat MFD=1920,0,657,539,noframe
//
// Two consequences it has to carry, or the option would be a trap:
// - a frameless window has NO TITLE BAR TO DRAG, which is how the whole
// sticky-layout workflow works. So a noframe window is draggable BY ITS
// SURFACE (WM_NCHITTEST -> HTCAPTION anywhere that is not a button); the
// buttons stay clickable, and the drag still ends in WM_EXITSIZEMOVE so it
// still saves.
// - SaveLayout rewrites the whole file, so it must WRITE THE FLAG BACK or the
// first save after a drag would silently strip it.
// THE WORKFLOW IS DELIBERATELY TWO-STAGE, and the option is the last step:
// 1. run with BT_GLASS_LAYOUT=save and DRAG the windows where you want them
// (they have title bars, so this is the normal sticky-layout flow),
// 2. quit,
// 3. hand-edit the cfg and append ,noframe to the ones you want bare.
// 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. 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 };
@@ -536,9 +539,13 @@ static void
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"
"# Append ,noframe to a line to drop that window's title bar and border;\n"
"# a frameless window is dragged by its SURFACE instead (buttons still\n"
"# click). Hand-edit to add it -- saves preserve it.\n",
"#\n"
"# Happy with where everything sits? Quit, then append ,noframe to any\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);
int wrote = 0;
for (int i = 0; i < gWinCount; ++i)
@@ -842,23 +849,6 @@ static LRESULT CALLBACK
case WM_ERASEBKGND:
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:
if (wparam == RepaintTimerId)