Plasma window joins the glass_layout.cfg no-frame list

The desktop plasma window (L4PLASMAWIN, "BattleTech - Plasma") is created by a
different TU than the per-display panels, so it couldn't be a gWins[] entry and
sat outside the sticky-layout / ,noframe system.  Add a tiny extern-window
registry to L4GLASSWIN so it rides the same glass_layout.cfg:

  - BTGlassLayout_QueryWindow(title, rect, noframe) -- read a title's saved rect
    and ,noframe flag (used by the plasma on creation, BEFORE sizing, since
    WS_POPUP's frame extent differs from the framed tool window).
  - BTGlassLayout_RegisterExtern(hwnd, title) -- register an externally-created
    window so SaveLayout writes its line (with a last-known-rect cache so a
    teardown before the save still preserves the line).
  - BTGlassLayout_Save() -- public save trigger the plasma WndProc calls on
    WM_EXITSIZEMOVE / teardown.

L4PLASMAWIN now reads its saved rect+flag on create (WS_POPUP when ,noframe,
position restored), registers itself, and saves on finished-drag/teardown.  All
BT_GLASS-gated; the pod is untouched.  The plasma blits directly every frame, so
it has no WM_TIMER focus-throttle.

Verified: Release links clean; drag wrote "BattleTech - Plasma=321,222,528,167",
reload with ,noframe brought it up WS_POPUP (WS_CAPTION absent) at 321,222.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-08-04 19:38:29 -05:00
co-authored by Claude Opus 4.8
parent 7d112ce309
commit 67074c80e2
3 changed files with 172 additions and 12 deletions
+117 -1
View File
@@ -451,6 +451,91 @@ static GWin *
return NULL;
}
//###########################################################################
// External windows that ride glass_layout.cfg (2026-08-04). A window created
// by ANOTHER TU -- the plasma window (L4PLASMAWIN) -- can register here so it
// shares the SAME position + ",noframe" persistence as the per-display windows:
// it queries its saved rect/flag on creation, and Save() writes its line too.
// Tiny (HWND + title + last-known rect); no dynamic state.
//###########################################################################
struct ExternWin
{
HWND hwnd;
char title[64];
int noFrame;
RECT last;
int haveLast;
};
static ExternWin gExtern[4];
static int gExternCount = 0;
// Read the saved rect + ",noframe" flag for a title (glass window OR extern).
// Returns 1 if the title has a line in the cfg. rect / noframe may be NULL.
int
BTGlassLayout_QueryWindow(const char *title, RECT *rect, int *noframe)
{
if (title == NULL || GlassLayoutMode() == LayoutOff)
return 0;
FILE *f = fopen(layoutFileName, "rt");
if (f == NULL)
return 0;
int found = 0;
char line[256];
while (fgets(line, sizeof(line), f) != NULL)
{
char *s = line;
while (*s == ' ' || *s == '\t') ++s;
if (*s == '#' || *s == '\r' || *s == '\n' || *s == '\0')
continue;
char *eq = strchr(s, '=');
if (eq == NULL)
continue;
*eq = '\0';
char *end = eq;
while (end > s && (end[-1] == ' ' || end[-1] == '\t')) --end;
*end = '\0';
if (strcmp(s, title) != 0)
continue;
int x = 0, y = 0, w = 0, h = 0;
if (sscanf(eq + 1, "%d,%d,%d,%d", &x, &y, &w, &h) < 2)
continue;
int nf = 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) { nf = 1; break; }
}
if (rect) { rect->left = x; rect->top = y; rect->right = x + w; rect->bottom = y + h; }
if (noframe) *noframe = nf;
found = 1;
break;
}
fclose(f);
return found;
}
// Register an externally-created window so Save() writes its line. Loads its
// current ",noframe" flag from the cfg so a save round-trips the flag.
void
BTGlassLayout_RegisterExtern(HWND hwnd, const char *title)
{
if (hwnd == NULL || title == NULL)
return;
if (gExternCount >= (int)(sizeof(gExtern) / sizeof(gExtern[0])))
return;
ExternWin &e = gExtern[gExternCount++];
e.hwnd = hwnd;
strncpy(e.title, title, sizeof(e.title) - 1);
e.title[sizeof(e.title) - 1] = '\0';
e.noFrame = 0;
e.haveLast = 0;
BTGlassLayout_QueryWindow(title, NULL, &e.noFrame);
}
// Restore saved positions over the just-computed pod-faithful defaults. Called
// from Create AFTER ComputeLayout, so any window not named in the file keeps its
// computed spot. Restored windows are flagged so the WM_TIMER re-snap (which
@@ -547,7 +632,8 @@ static void
"# 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",
"# back. Saves preserve it. The 'BattleTech - Plasma' window is in\n"
"# this list too -- it can be dragged, remembered and set ,noframe.\n",
f);
int wrote = 0;
for (int i = 0; i < gWinCount; ++i)
@@ -564,11 +650,41 @@ static void
gw.noFrame ? ",noframe" : ""); // keep the hand-added option
++wrote;
}
// External windows (the plasma window) ride the same file. Cache the last
// good rect so a window torn down before this save still keeps its line.
for (int i = 0; i < gExternCount; ++i)
{
ExternWin &e = gExtern[i];
RECT r;
if (e.hwnd != NULL && IsWindow(e.hwnd) && GetWindowRect(e.hwnd, &r))
{
e.last = r; e.haveLast = 1;
}
else if (e.haveLast)
{
r = e.last; // window gone -> preserve its last-known line
}
else
continue;
fprintf(f, "%s=%ld,%ld,%ld,%ld%s\n", e.title,
(long)r.left, (long)r.top,
(long)(r.right - r.left), (long)(r.bottom - r.top),
e.noFrame ? ",noframe" : "");
++wrote;
}
fclose(f);
DEBUG_STREAM << "[glasswin] saved " << wrote << " window position(s) to "
<< layoutFileName << "\n" << std::flush;
}
// Public save trigger for registered external windows -- their WndProc calls
// this on WM_EXITSIZEMOVE / teardown. No-op unless BT_GLASS_LAYOUT=save.
void
BTGlassLayout_Save()
{
SaveLayout();
}
//###########################################################################
// Painting
//###########################################################################