Releases: Ching367436/spice-mac
Release list
SpiceMac 0.1.8
Added
-
Display zoom (View ▸ Zoom). On a Retina Mac the client asked the guest for
the view's full backing pixel count, so a 1512×982-point window drove the
guest at 3024×1964 — the guest has no idea the Mac is HiDPI, so it rendered
one pixel per pixel and everything came out half size, while the VM pushed
four times the pixels it needed. Zoom is now Z = Mac physical pixels per
guest pixel: the client requestspoints × backing scale ÷ Zand each guest
pixel is drawn as a Z×Z block, so readability and cost improve together.
Shortcuts ⌃⌘+ / ⌃⌘− / ⌃⌘0. -
The zoom level is per-window, and a fixed level is absolute. Each window
is its own session on its own display, so it carries its own level: picking
one in the front window leaves the others alone. The commands live on the
window controller and reach it down the responder chain the wayConnection ▸ Send Ctrl-Alt-Delalready did, so the submenu greys out with no session open;
the preference is only the seed a new window starts from. Nothing but the user
ever changes a level — Automatic is the mode for constant apparent size
across a move. -
A window that changes display re-applies its geometry. At a fixed level
the target guest size ispoints × backing scale ÷ Z, and a move changes the
backing scale out from under it — which is why it used to need a manual nudge
of the window before the guest came out right. All four signals AppKit offers
now drive it, includingNSApplicationDidChangeScreenParametersfor hotplug,
sleep/wake and Displays scaled-mode changes, which resize the window without a
live resize. Requests are coalesced, so four triggers cost at most one guest
mode switch. -
Without
spice-vdagent, zoom and screen changes resize the window
(guest × Z ÷ backing scalepoints) rather than doing nothing — the guest
resolution is fixed, so that is the only side of the equation left. The
geometry is a new dependency-free package,Packages/DisplayScale, with a
21-checkscalecheckrunner wired intomake testand CI.
Changed
- The default zoom is Automatic (Z = the screen's backing scale), which
changes behaviour on upgrade. The guest resolution now tracks the window's
point size instead of its backing-pixel size, so on first connect after
updating a Retina guest drops to roughly half its previous resolution and
everything in it gets twice as big. That is the fix; View ▸ Zoom ▸ 100%
restores the old behaviour. Automatic also means the requested resolution is
the window's point size on any display, so dragging between screens needs no
guest reconfiguration.
Fixed
-
A dead connection no longer hides its own explanation. When a session
ended, the last guest frame stayed frozen over the window (the Metal view is
opaque anddetach()leaves it showing its final texture), so the
"Disconnected — open a fresh .vv file" hint or the failure reason was drawn
invisibly behind it and the window just looked hung. The display view now
hides when the session ends and returns on the next connect, revealing the
centered status message. A specific failure reason (.failed) is also kept
if the generic disconnect callback arrives after the error one, instead of
being downgraded to "Disconnected." -
ISO / French Magic Keyboard
<>key now reaches the guest. The keymap was
ANSI-only and omittedkVK_ISO_Section(0x0A), the key next to Left Shift on
ISO hardware (e.g. French AZERTY</>). Presses produced no guest event.
Map it to PC set-1KEY_102ND(0x56);inputcheckcovers the mapping.
(#4) -
Guest text was blurry at some window sizes and not others, worst on a
normal-DPI monitor. The sampler only went nearest-neighbour at 2× or more, so
a 1:1 presentation — what 100% means on a 1x screen — always took the bilinear
path; and because the requested mode is floored onto the 8-wide/2-high grid
guest drivers want, the centred quad landed on a half-pixel offset
whenever that slack was odd. Nearest now applies at any whole-number
magnification, andviewportOriginnudges the quad onto whole pixels — the
input router subtracts the same origin, so the cursor stays locked. -
Dragging a window between a Retina panel and a 1x monitor did not re-scale
the guest.MTKViewrefreshesdrawableSizelazily, so inside
viewDidChangeBackingProperties— the one moment such a move offers — it
still holds the previous screen's value: on a real 2.0↔1.0 drag the callback
reportsbackingScaleFactor1.0 whiledrawableSizeis still 1800×1200 for a
view that is now 900×600 physical pixels. The fit now measures with
convertToBacking(bounds), which follows the backing store immediately, and
pulls the drawable up to match.
Download
SpiceMac.app.zip — Apple Silicon, macOS 12+. Ad-hoc signed; to open: right-click ▸ Open (macOS 14) or System Settings ▸ Privacy & Security ▸ Open Anyway (macOS 15+), or xattr -dr com.apple.quarantine /Applications/SpiceMac.app.
SHA-256: faeb08e0ef42a4189ed69a4a64cc4c7d3b6e29e511645ccea876eb865551ad76
SpiceMac 0.1.7
Fixed
- Copying a spreadsheet cell in the guest now pastes onto the Mac. A guest
copy offers several clipboard representations at once (a cell = UTF-8 text + a
bitmap image); the guest→host bridge cleared the Mac pasteboard on every write,
so the representations clobbered each other and only the last survived — usually
the image, leaving nothing to paste as text. The bridge now clears once per
guest grab and accumulates the rest, so the cell's text (and image) both land.
Plain-text copy was unaffected because it's a single type. (Fork change — see
ThirdParty/CocoaSpice/FORK-NOTES.md.)
Security
- Hardened the
.vvparser (the one attacker-influenced file the app opens):
a 1 MiB file-size cap + UTF-8 enforcement inVVConfig(contentsOf:),
control-character stripping from values (aNULinhost/proxywould
otherwise survive Swift validation but truncate inside the C SPICE stack — a
smuggle), port-range validation (only 1–65535; junk/negative/overflow become
"absent"), and leading-BOM tolerance. Added a deterministic 20k-iteration
fuzzer + edge-case tests (vvcheck, now 24 checks) proving the parser never
crashes on arbitrary input.
Download
SpiceMac.app.zip — Apple Silicon, macOS 12+. Ad-hoc signed; to open: right-click ▸ Open (macOS 14) or System Settings ▸ Privacy & Security ▸ Open Anyway (macOS 15+), or xattr -dr com.apple.quarantine /Applications/SpiceMac.app.
SHA-256: f2aec8992a339d883638ac84007733c1c7726e9ff3ce3e25283f0eec7994b05a
SpiceMac 0.1.6
Security release: the bundled TLS stack moves off EOL OpenSSL.
Security
- OpenSSL upgraded to 3.5.6 (LTS, maintained to 2030), retiring the EOL 1.1.1 branch — the server-facing TLS stack is now current. Built under the old install names so spice-gtk loads it unchanged; the build verifies all ~72 of spice-gtk's OpenSSL symbols resolve in 3.x, and a real TLS connection to a Proxmox VM was confirmed. (The rest of the native stack is still the older UTM build — see SECURITY.md.)
Download
SpiceMac.app.zip — Apple Silicon, macOS 12+. Ad-hoc signed; to open: right-click ▸ Open (macOS 14) or System Settings ▸ Privacy & Security ▸ Open Anyway (macOS 15+), or xattr -dr com.apple.quarantine /Applications/SpiceMac.app.
SHA-256: 2a3e99a7da123b7b0bc739275358dcab3880b90d8870618e238709f2ccf95c98
Full changelog: CHANGELOG.md.
SpiceMac 0.1.5
USB-hardening + housekeeping release.
Changed
- Hardened
run-as-root.sh(the supported path for redirecting kernel-claimed USB devices): a clear trust-boundary warning + confirmation prompt (-yto skip), and documented honestly in the README/SECURITY.md. A privileged USB helper that would keep the SPICE stack unprivileged was scoped and deferred — macOS forces a design that's only a partial win and needs a Developer ID for the clean path.
Fixed
.vvno longer moved to root's Trash when launched viarun-as-root.sh— the Trash-after-connect preference is skipped under root, so your file stays put.
Download
SpiceMac.app.zip — Apple Silicon, macOS 12+. Ad-hoc signed; to open: right-click ▸ Open (macOS 14) or System Settings ▸ Privacy & Security ▸ Open Anyway (macOS 15+), or xattr -dr com.apple.quarantine /Applications/SpiceMac.app.
SHA-256: 3f4cf75c76b2202b3eddae9a192566e2fa959b3066741b717460d5ae4d697a0e
Full changelog: CHANGELOG.md.
SpiceMac 0.1.4
Security
- Multi-head monitor-config crash (DoS). A guest reporting more than one monitor config on a display channel (a protocol-legal multi-head configuration) tripped an assertion that aborted the whole client. Removed it — the display is now handled gracefully regardless of head count. Same class as a fix already in 0.1.0; this closes the second site.
Download
Grab SpiceMac.app.zip, unzip, move SpiceMac.app to /Applications. Apple Silicon, macOS 12+.
Ad-hoc signed, not notarized. To open: right-click ▸ Open (macOS 14) or System Settings ▸ Privacy & Security ▸ Open Anyway (macOS 15+), or:
xattr -dr com.apple.quarantine /Applications/SpiceMac.app && open /Applications/SpiceMac.app
Verify: shasum -a 256 SpiceMac.app.zip
SHA-256: cbca20cb5f829b678e4d912f1c03d2786a47fe7b78220d6cdef33e9011bd347a
Full changelog: CHANGELOG.md.
SpiceMac 0.1.3
Fixed
- Blank screen on connect. The display no longer stays black until you click — the initial framebuffer is now painted as soon as the connection's renderer attaches (it was being dropped due to a SPICE-thread/Metal-device timing race).
Added
- Move
.vvto Trash after connecting (File menu, default on). Proxmox SPICE tickets are single-use and the file also carries the cluster CA, so the used file goes to the Trash (recoverable — not a hard delete) once it's opened a connection. Toggle in File ▸ Move .vv to Trash After Connecting.
Download
Grab SpiceMac.app.zip, unzip, move SpiceMac.app to /Applications. Apple Silicon, macOS 12+.
Ad-hoc signed, not notarized (needs a paid Apple Developer membership — help via the Sponsor button / ETH
ching367436.eth). To open: right-click ▸ Open (macOS 14) or System Settings ▸ Privacy & Security ▸ Open Anyway (macOS 15+), or:xattr -dr com.apple.quarantine /Applications/SpiceMac.app && open /Applications/SpiceMac.app
Verify: shasum -a 256 SpiceMac.app.zip
SHA-256: fd912b54539cca958d52755563ad46fb6a3019acfda018f17be9d71ac57e5cd7
Full changelog: CHANGELOG.md.
SpiceMac 0.1.2
Adds an app icon — a warm spice-palette squircle with a glowing remote-console screen and signal arcs — shown in the Dock, Finder, and ⌘-Tab. Otherwise identical to 0.1.1.
Download
Grab SpiceMac.app.zip below, unzip, move SpiceMac.app to /Applications. Apple Silicon, macOS 12+.
Ad-hoc signed, not notarized (Apple notarization needs a paid Apple Developer membership the project can't yet fund — help via the Sponsor button / ETH
ching367436.eth). To open: right-click ▸ Open (macOS 14), or System Settings ▸ Privacy & Security ▸ Open Anyway (macOS 15+), or:xattr -dr com.apple.quarantine /Applications/SpiceMac.app && open /Applications/SpiceMac.app
Verify your download:
shasum -a 256 SpiceMac.app.zip
SHA-256: 30ea01c7684426faf79aee997e96acca53173110f32966b939f15736f6aca95d
Bundles only the 26-framework LGPL/MIT/BSD/OpenSSL runtime closure — no GPL; license texts + LGPL §6 offer ship inside the app. Full changelog: CHANGELOG.md.
SpiceMac 0.1.1
Adds a prebuilt SpiceMac.app download alongside the source release. Apple Silicon, macOS 12+.
Download
Grab SpiceMac.app.zip below, unzip, and move SpiceMac.app to /Applications.
This build is ad-hoc signed, not Developer-ID-signed or notarized — Apple notarization needs a paid Apple Developer membership (US$99/yr) the project can't currently fund. It's safe to run; macOS just won't recognize the signer. Want signed + notarized builds? You can help fund the membership via the repo's Sponsor button. Prefer maximum trust? Build from source.
Opening it (Gatekeeper)
- macOS 14: right-click the app ▸ Open ▸ Open.
- macOS 15+: double-click once → Done, then System Settings ▸ Privacy & Security ▸ Open Anyway.
- Terminal (either):
xattr -dr com.apple.quarantine /Applications/SpiceMac.app open /Applications/SpiceMac.app
Verify your download
shasum -a 256 SpiceMac.app.zip
SHA-256: 5af408a0cb245ce51e9ab0a43c8d927af4f51d53494a7f64fc4d193d113c0732
Notes
- Bundles only the 26-framework LGPL/MIT/BSD/OpenSSL runtime closure — no GPL (no QEMU). The verbatim license texts + LGPL §6 written offer ship inside the app at
Contents/Resources/Licenses/. - OpenSSL 1.1.1w (fixes CVE-2022-0778); the rest is an older UTM sysroot — fine for personal use against trusted VMs (SECURITY.md).
Full changelog: CHANGELOG.md.
Prebuilt SPICE sysroot (arm64) v2 — OpenSSL 3.5.6
This is not the app — it's the pinned native dependency stack scripts/fetch-sysroot.sh downloads to build SpiceMac. For the app, see the latest release.
Same as sysroot-arm64-v1 but with OpenSSL upgraded to 3.5.6 (LTS, maintained to 2030) in place of the EOL 1.1.1w — built under the ssl.1.1/crypto.1.1 install names so spice-gtk (compiled against 1.1.1) loads it unchanged. The 26 @rpath frameworks + 19 GStreamer plugin archives (arm64); LGPL/MIT/BSD/OpenSSL only, no GPL.
License notices + LGPL §6 offer: THIRD-PARTY-LICENSES.txt.
SHA-256:
a7435e48731861b6babc6ea7804b9bdc801c7e03e808b460492cb6fab299d03f spice-sysroot-macos-arm64.tgz
Prebuilt SPICE sysroot (arm64) — build dependency
This is not the app — it's the pinned native dependency stack scripts/fetch-sysroot.sh downloads to build SpiceMac. For the app, see the latest release.
spice-sysroot-macos-arm64.tgz contains the 26 @rpath-relocatable .framework bundles + 19 GStreamer static plugin archives (arm64) that SpiceMac links and embeds — the exact runtime/link closure, nothing more. Derived from a UTM Sysroot-macos-arm64 build, with the GPL components (QEMU, spice-server, swtpm, …) excluded: everything here is LGPL-2.1 / MIT / BSD-3 / OpenSSL. OpenSSL is 1.1.1w (already patched; upgrade-openssl.sh not needed when using this tarball).
License notices + the LGPL §6 written offer (corresponding source for these versions): THIRD-PARTY-LICENSES.txt.
SHA-256:
381f76f686c47e99bd347cd086b24096deae4e5d613d0ad1571fab8257f0f4d8 spice-sysroot-macos-arm64.tgz
fetch-sysroot.sh pins this digest and fails closed on mismatch.