Fix glass frame: title-bar fused to frame, no black around buttons, sane shadow

Three defects reported from the real window, each with a distinct cause:

1. "Top and sides do not connect" — 7.css couples the glass treatment to the
   title bar with a DIRECT-child selector (.window.glass > .title-bar), and our
   .title-bar lived inside an inner div of <app-title-bar>, so the rule never
   matched: the title bar fell back to the opaque base style with its own
   border and radius, a blue slab sitting on the frame. The .title-bar class
   (and the drag region + dblclick-maximize) moved onto the component HOST, so
   the selector now matches and the title bar is the translucent streaked glass
   fused with the frame.

2. "Black background near the window buttons" — .window.glass::after is
   backdrop-filter: blur(4px). CSS cannot sample the DESKTOP behind a
   transparent native window (there is no backdrop to read) and WebKitGTK
   paints the unsampleable layer BLACK, so every see-through part of the glass
   — the ring, the area around the controls — composited over black.
   Neutralized in skinfix; the glass tint now shows the real desktop through
   the transparent window, which is closer to Aero than a blur we cannot have.
   (True blur-behind needs compositor support; GNOME exposes none to
   X11/XWayland clients.)

3. "Shadow way too strong" — the 6px gutter hard-clipped 7.css's
   2px 2px 10px 1px #000000b3 shadow into a solid dark band. The gutter now
   matches the shadow's extents exactly: blur+spread-offset = 9px up/left,
   offset+blur+spread = 13px down/right, so it falls off to nothing.

Verified on the REAL window this time: captured the running app with
ImageMagick import (the app runs on XWayland, so X11 capture works) before and
after. Before: black block around min/max/close, murky dark ring, detached blue
title strip. After: streaks span the top, controls hang from the frame edge as
on real Win7, ring is glass-blue, no black anywhere.

Known remaining (pre-existing, next stages): the tab-bar/toolbar row overlaps
itself top-left (tabs conversion, Stage 4); maximized windows should drop
radius/shadow/gutter.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-08-16 02:51:24 +02:00
co-authored by Claude
parent fe75904872
commit 1f773261a8
2 changed files with 44 additions and 19 deletions
+11 -2
View File
@@ -11,6 +11,13 @@ import { RpcService } from '../rpc.service';
* Restore / Close each get their own glyph). Nothing here is styled with
* Tailwind on purpose — the whole row comes from @layer skin.
*
* `.title-bar` lives on the HOST element, not on an inner div. 7.css couples
* the glass treatment with a DIRECT-child selector — `.window.glass >
* .title-bar` — and an inner div puts <app-title-bar> in between, so the rule
* never matched: the title bar rendered as the opaque fallback with its own
* border, visibly disconnected from the frame, instead of the translucent
* streaked glass that fuses with it.
*
* Dragging rides on electrobun's preload drag-region classes. Two things
* electrobun does NOT provide and this component implements:
* - double-click to maximize (it only wires mousedown/mouseup)
@@ -19,8 +26,11 @@ import { RpcService } from '../rpc.service';
*/
@Component({
selector: 'app-title-bar',
host: {
class: 'title-bar electrobun-webkit-app-region-drag',
'(dblclick)': 'toggle()',
},
template: `
<div class="title-bar electrobun-webkit-app-region-drag" (dblclick)="toggle()">
<div class="title-bar-text">{{ title() }}</div>
<div class="title-bar-controls electrobun-webkit-app-region-no-drag">
@if (resizable()) {
@@ -32,7 +42,6 @@ import { RpcService } from '../rpc.service';
}
<button aria-label="Close" (click)="closeRequested.emit()"></button>
</div>
</div>
`,
})
export class TitleBar {
+22 -6
View File
@@ -641,13 +641,29 @@ body {
/* ---- Window frame ----
The native window is transparent (chromeOptions in src/bun/windows.ts), so
nothing but .window paints an opaque surface. The margin is the gutter the
drop shadow falls into — without it the shadow has no room and the frame
reads as square. h-screen (100vh) has to shrink by the same amount or the
window overflows into a scrollbar. */
nothing but .window paints an opaque surface. The margins are the gutter
the drop shadow falls into, sized to the shadow's exact extents —
`2px 2px 10px 1px` reaches blur+spread-offset = 9px up/left and
offset+blur+spread = 13px down/right. An undersized gutter hard-clips a
70%-black shadow into a solid dark band around the window ("way too
strong"); matched to the extents it falls off to nothing. h-screen (100vh)
shrinks by the same totals or the gutter produces a scrollbar. */
.win7 .window {
margin: 6px;
height: calc(100vh - 12px);
margin: 9px 13px 13px 9px;
height: calc(100vh - 22px);
}
/* 7.css's glass layer is `backdrop-filter: blur(4px)` on .window::after —
but CSS cannot sample the DESKTOP behind a transparent native window
(there is no backdrop to read), and WebKitGTK paints the unsampleable
layer BLACK: every see-through part of the glass — the frame ring, the
area around the title-bar buttons — composited over black instead of over
the desktop. With it off, the real desktop shows through the glass tint,
which is closer to Aero than a blur we cannot have. (True blur-behind
needs compositor support; GNOME offers none to X11/XWayland clients.) */
.win7 .window.glass::after {
-webkit-backdrop-filter: none;
backdrop-filter: none;
}
/* Constant row geometry. 7.css gives ONLY tr.highlighted a 1px border, and