Skip to content

Commit 3414f1c

Browse files
committed
fix(wallpaper): keep the system wallpaper in step with the animation
the still behind the menu bar tint, Mission Control and the lock screen was only re-rendered on a setting change, and always at time 0, so it never matched the frame on screen. stills (desktop sync and export) now render on the live clock, and the desktop sync re-runs once a minute while animating, timed on the wall clock since macOS throttles the app timer.
1 parent fc62208 commit 3414f1c

2 files changed

Lines changed: 14 additions & 4 deletions

File tree

‎src/app/delegate.swift‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
1313
var syncWork: DispatchWorkItem?
1414
var lastSync = ""
1515
var ticks = 0
16+
var lastStill = Date()
1617

1718
func applicationDidFinishLaunching(_ n: Notification) {
1819
Pref.register()
@@ -43,6 +44,13 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
4344
// ponytail: polls both config files every 2s; a stat is cheaper than watching a symlink chain nix swaps
4445
ticks += 1
4546
if ticks % 40 == 0 { Config.poll() }
47+
// ponytail: the system wallpaper (menu bar tint, Mission Control, lock screen) follows
48+
// the animation once a minute; finer means a full-screen PNG write every few seconds.
49+
// wall clock, not ticks: macOS throttles the timer when the app is napped
50+
if live, Date().timeIntervalSince(lastStill) > 60 {
51+
lastSync = ""
52+
syncDesktop()
53+
}
4654
}
4755
wall.setPaused(!Pref.d.bool(forKey: "animate"))
4856
wall.refresh()
@@ -235,7 +243,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
235243
var firstOut: URL?
236244
for (i, (r, v)) in zip(wall.renderers, wall.views).enumerated() {
237245
let w = Int(v.drawableSize.width), h = Int(v.drawableSize.height)
238-
guard let px = r.render(makeUniforms(w: w, h: h, time: 0), w: w, h: h),
246+
guard let px = r.render(makeUniforms(w: w, h: h, time: r.now), w: w, h: h),
239247
let img = cgImage(px, w: w, h: h)
240248
else { continue }
241249
let out =
@@ -270,6 +278,7 @@ extension AppDelegate {
270278
.appendingPathComponent("Pixeldish")
271279
else { return }
272280
lastSync = key
281+
lastStill = Date()
273282
try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
274283
// the wallpaper store ignores a URL it already shows, so alternate two names per display
275284
let slot = Pref.d.bool(forKey: "desktopSlot")
@@ -280,7 +289,7 @@ extension AppDelegate {
280289
let sh = Int(screen.frame.height * screen.backingScaleFactor)
281290
// the window is oversized past the screen edges, crop back to what is visible
282291
guard w >= sw, h >= sh,
283-
let px = r.render(makeUniforms(w: w, h: h, time: 0), w: w, h: h),
292+
let px = r.render(makeUniforms(w: w, h: h, time: r.now), w: w, h: h),
284293
let img = cgImage(px, w: w, h: h)?
285294
.cropping(to: CGRect(x: (w - sw) / 2, y: (h - sh) / 2, width: sw, height: sh))
286295
else { continue }

‎src/render/renderer.swift‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ final class DishRenderer: NSObject, MTKViewDelegate {
166166
// `just test-live` to prove the window path draws, since the display itself
167167
// cannot be screenshotted without screen-recording permission
168168
var probeFrames = 0
169+
// the clock the live view draws at; stills use it too so they match the screen
170+
var now: Float { paused ? 0 : Float(Date().timeIntervalSince(start)) * prefValue("speed") }
169171

170172
init?(shader path: String) {
171173
guard let dev = MTLCreateSystemDefaultDevice(),
@@ -258,9 +260,8 @@ final class DishRenderer: NSObject, MTKViewDelegate {
258260
else { return }
259261
rp.colorAttachments[0].clearColor = MTLClearColor(red: 0, green: 0, blue: 0, alpha: 1)
260262

261-
let t = paused ? 0 : Float(Date().timeIntervalSince(start)) * prefValue("speed")
262263
let size = view.drawableSize
263-
encode(enc, makeUniforms(w: Int(size.width), h: Int(size.height), time: t))
264+
encode(enc, makeUniforms(w: Int(size.width), h: Int(size.height), time: now))
264265
if probeFrames > 0 {
265266
probeFrames -= 1
266267
cb.present(rt)

0 commit comments

Comments
 (0)