| 1 | import SwiftUI |
| 2 | import AppKit |
| 3 | |
| 4 | // The within-window material glass Messages.app uses for its chat header and |
| 5 | // composer footer: an NSVisualEffectView blending within the window, frosting |
| 6 | // whatever scrolls behind it. Deliberately NO colour of its own — a tint can |
| 7 | // only ever mismatch the feed (it did: windowBackgroundColor isn't what the |
| 8 | // pane actually sits on). A blur of a solid is that solid, so the glass |
| 9 | // matches the transcript at rest and frosts what passes beneath. |
| 10 | // |
| 11 | // ⚠️ Two dead ends, so nobody re-walks them: |
| 12 | // - alphaValue < 1 on an NSVisualEffectView silently DISABLES its backdrop |
| 13 | // blur — you get a faded plate with sharp content bleeding through, not a |
| 14 | // lighter frost. The band must run at exactly 1. |
| 15 | // - A true CSS-style backdrop-filter (pure gaussian via public |
| 16 | // CALayer.backgroundFilters, no material plate) is compositor-ignored in |
| 17 | // this window tree; only the private CABackdropLayer gets backdrop |
| 18 | // sampling, and we don't ship private API. |
| 19 | struct FrostedBand: View { |
| 20 | var body: some View { WithinWindowBlur() } |
| 21 | } |
| 22 | |
| 23 | private struct WithinWindowBlur: NSViewRepresentable { |
| 24 | // Decoration must be transparent to the mouse. This AppKit view lives in |
| 25 | // its own PlatformViewHost, and SwiftUI does not keep representable |
| 26 | // NSViews' z-order in step with the SwiftUI stack — after a composer-row |
| 27 | // re-mount the band's host could land ABOVE the field's scroll view in |
| 28 | // NSView order, and every click on the input died on the glass (and |
| 29 | // resigned the caret to the window): the "composer goes unclickable for |
| 30 | // a while" bug. hitTest nil = clicks always fall through to whatever the |
| 31 | // band is dressing, whatever the subview order. |
| 32 | private final class ClickThroughEffectView: NSVisualEffectView { |
| 33 | override func hitTest(_ point: NSPoint) -> NSView? { nil } |
| 34 | } |
| 35 | |
| 36 | func makeNSView(context: Context) -> NSVisualEffectView { |
| 37 | let v = ClickThroughEffectView() |
| 38 | v.blendingMode = .withinWindow |
| 39 | v.material = .headerView |
| 40 | v.state = .active |
| 41 | return v |
| 42 | } |
| 43 | func updateNSView(_ nsView: NSVisualEffectView, context: Context) {} |
| 44 | } |
| 45 | |