summaryrefslogtreecommitdiff
path: root/src/macos
diff options
context:
space:
mode:
Diffstat (limited to 'src/macos')
-rw-r--r--src/macos/Sources/AppDelegate.swift24
-rw-r--r--src/macos/Sources/PardesView.swift16
-rw-r--r--src/macos/pardes.h4
3 files changed, 32 insertions, 12 deletions
diff --git a/src/macos/Sources/AppDelegate.swift b/src/macos/Sources/AppDelegate.swift
index 4e91e407..cbe9cdc9 100644
--- a/src/macos/Sources/AppDelegate.swift
+++ b/src/macos/Sources/AppDelegate.swift
@@ -81,8 +81,8 @@ final class AppDelegate: NSObject, NSApplicationDelegate, PardesViewDelegate {
// The grid and the blur are SIBLINGS in a plain container, not parent
// and child. A transparent theme has to show something through the
// grid, and AppKit will not blur what is behind a window unless an
- // NSVisualEffectView asks it to — but the backdrop is hidden for every
- // theme that brings its own background, and hiding a superview hides
+ // NSVisualEffectView asks it to. The backdrop can be hidden independently
+ // when blur is disabled or the ground is opaque; hiding a superview hides
// its subviews with it. Nested, an opaque theme drew a blank window.
let container = NSView(frame: NSRect(origin: .zero, size: want))
container.autoresizesSubviews = true
@@ -460,6 +460,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, PardesViewDelegate {
/// theme whose background happened to equal the view's starting guess
/// would otherwise leave the window in AppKit's default clothes forever.
private var dressed = false
+ private var appliedBlur: UInt8 = 0
private func applyTheme() {
// Both reads happen every pump, and neither may be short-circuited by
@@ -468,15 +469,17 @@ final class AppDelegate: NSObject, NSApplicationDelegate, PardesViewDelegate {
// tick would leave one of them unworn.
let themeChanged = view.adoptThemeBG(pardes_theme_bg())
let opacityChanged = view.adoptWindowOpacity(pardes_window_opacity())
- guard themeChanged || opacityChanged || !dressed else { return }
+ let blur = pardes_window_blur()
+ let blurChanged = blur != appliedBlur
+ guard themeChanged || opacityChanged || blurChanged || !dressed else { return }
+ appliedBlur = blur
+ backdrop.alphaValue = CGFloat(blur) / 100
+ backdrop.isHidden = blur == 0 || (view.themeBG != nil && view.backgroundAlpha >= 1)
dressed = true
- // A ground short of solid needs the same non-opaque window a
- // background-less theme does — but not the blur behind it. The backdrop
- // answers "this theme brings no background"; WindowOpacity says how
- // much of the one it brings to paint, and what shows through the rest
- // is the desktop, which is what asking for a translucent window means.
+ // Opacity paints the theme ground; blur controls the native material
+ // behind it. An opaque ground hides the backdrop without losing the
+ // requested strength, so lowering opacity restores the effect.
if let rgb = view.themeBG {
- backdrop.isHidden = true
window.isOpaque = view.backgroundAlpha >= 1
window.backgroundColor = view.backgroundAlpha < 1 ? .clear : NSColor(
srgbRed: CGFloat((rgb >> 16) & 0xFF) / 255,
@@ -493,10 +496,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate, PardesViewDelegate {
window.appearance = NSAppearance(named: luma > 0.5 ? .aqua : .darkAqua)
} else {
// Transparent: the window stops painting anything of its own and
- // the blur takes over. isOpaque false is what lets the desktop
+ // the optional blur sits behind it. isOpaque false lets the desktop
// reach the backdrop at all — a titled window is opaque by default
// and would composite over it.
- backdrop.isHidden = false
window.isOpaque = false
window.backgroundColor = .clear
window.appearance = NSAppearance(named: .darkAqua)
diff --git a/src/macos/Sources/PardesView.swift b/src/macos/Sources/PardesView.swift
index 7c537055..7981cf46 100644
--- a/src/macos/Sources/PardesView.swift
+++ b/src/macos/Sources/PardesView.swift
@@ -1446,6 +1446,7 @@ final class PardesView: NSView {
let source: CGRect
let body: CGRect
let destination: CGRect
+ let paperBG: UInt32
}
/// Rasterized attachments, decoded once each. The bytes the core lends are
@@ -1496,7 +1497,7 @@ final class PardesView: NSView {
height: CGFloat(place.dst_h) / scale)
let frozen = FrozenImage(
key: key, image: crop, source: source,
- body: body, destination: dst)
+ body: body, destination: dst, paperBG: place.paper_bg)
frameImages.append(frozen)
drawFrozenImage(ctx, frozen)
}
@@ -1545,11 +1546,24 @@ final class PardesView: NSView {
ctx.clip(to: placed.body)
// isFlipped gives us a y-down CTM and CGImage draws +y up, so flip
// about this destination rather than changing the grid arithmetic.
+ let isPDF = placed.paperBG != UInt32(PARDES_COLOR_DEFAULT)
+ if isPDF {
+ fillBackground(ctx, placed.destination, placed.paperBG, backgroundAlpha)
+ }
ctx.translateBy(x: placed.destination.minX, y: placed.destination.maxY)
ctx.scaleBy(x: 1, y: -1)
ctx.interpolationQuality = .high
let rect = CGRect(x: 0, y: 0,
width: placed.destination.width, height: placed.destination.height)
+ if isPDF {
+ // Paper was painted at WindowOpacity. Content keeps the PDF's own
+ // coverage, so glyphs, photos and paths stay legible at zero opacity.
+ ctx.setAlpha(1)
+ ctx.setBlendMode(.normal)
+ ctx.draw(placed.image, in: rect)
+ ctx.restoreGState()
+ return
+ }
// Match image.frag.glsl/backgroundLayerBlend: source coverage removes
// the destination independently of WindowOpacity, then the source is
// added at that opacity. Ordinary source-over would compound alpha;
diff --git a/src/macos/pardes.h b/src/macos/pardes.h
index a2e34f53..df3ba04f 100644
--- a/src/macos/pardes.h
+++ b/src/macos/pardes.h
@@ -262,6 +262,8 @@ uint32_t pardes_theme_bg(void);
// Read it once per pump beside pardes_theme_bg(): reading also acknowledges
// whatever `WindowOpacity` asked for. 100 is opaque and is the default.
uint8_t pardes_window_opacity(void);
+// Backdrop material strength, 0..100; zero disables blur. Not a pixel radius.
+uint8_t pardes_window_blur(void);
// Pane taglines use this percentage of the current body font size. It is the
// embedded default before init and the live core setting afterwards; the host
@@ -475,6 +477,8 @@ typedef struct {
uint32_t ih;
// iw * ih * 4 bytes, RGBA8, borrowed until the next pardes_frame
const uint8_t *rgba;
+ // PDF paper RGB; PARDES_COLOR_DEFAULT means an ordinary image.
+ uint32_t paper_bg;
} pardes_image_s;
// This frame's attachments, in paint order. Ask after pardes_frame; both are