codesign -d --entitlements - now prefixes a text header line, so the
plist parse hit InvalidFileException; --xml emits clean XML (same
workaround as release.yml). Python 3.14's plistlib.load also rejects a
non-seekable pipe, so buffer stdin first.
Without this the script exits before the dmg step after a successful
build and ad-hoc sign.
The ad-hoc codesign path signed the whole bundle with one --deep pass,
which never carried --entitlements to the QuickLook appex, so PlugInKit
silently rejected it as unsandboxed. Sign nested code individually
instead, matching the Developer ID path.
Separately, ThumbnailProvider drew the extracted preview at its native
pixel size anchored at the CGContext origin (bottom-left) instead of
scaling it to fill request.maximumSize, producing a small thumbnail
stuck in one corner instead of a properly sized, centered icon.
Note: Gatekeeper still rejects an ad-hoc or unnotarized Developer-ID
signature outright, and PlugInKit periodically re-validates and drops
any registered plugin that fails that check — so these fixes are
necessary but not sufficient for thumbnails to render from a build
that isn't both signed and notarized.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The DMG dropped just the bare .app with no indication of where it's
supposed to go, unlike the "drag the icon onto Applications" layout
every other Mac app uses. Stage the .app next to a symlink to
/Applications before building the image, then lay out the Finder
window's icon view (via a temporary read-write DMG, since a compressed
UDZO image can't be mounted for editing afterward) so both items are
visible side by side.
The Finder/AppleScript layout step is best-effort and fails gracefully:
this script mirrors the CI build-macos job, which likely has no
interactive Finder session for AppleScript to reach at all, so the
essential fix (the symlink itself, which doesn't depend on Finder
scripting) still lands even when the cosmetic pass can't run.
Fixes#769.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Ports FreeCAD's planegcs 2D geometric constraint solver to Rust as a new
crates/ocs_gcs workspace member, and wires it into the document/scene model
as a persistent SketchConstraintSet: Coincident, Horizontal/Vertical,
Parallel/Perpendicular, Equal, Tangent, Distance, Angle and Radius
constraints that re-solve live (including mid-drag, not just on release),
render glyphs and a DOF badge, flag conflicts with a one-click resolver
pill, and round-trip through save/load via an XRecord blob.
Also includes docs/command_reference.md (a statically generated reference
of every registered command and its prompt sequence) and
docs/named_parameters_design.md + docs/backlog.md, which hand off the next
queued feature (a named-parameter/expression table) and consolidate every
deliberate scope-down and open gap found along the way, so a fresh session
has a complete starting point.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The previous commit's Apple Event handler only ever catches an open
sent to an already-running process. A cold double-click (app not
running yet) still failed: every registration point tried inside the
real binary — before app::run(), on the Subscription's first poll,
even the literal first statement of main() — reliably caught a warm
open but never the original cold-launch event. A raw
AEInstallEventHandler in a separate, minimal, non-AppKit process (no
winit/iced, just a manual CFRunLoopRunInMode pump) still missed it
too, ruling out "the real binary's heavy dependency graph loading
before main() wins the race" as the explanation.
What does reliably catch a cold launch, verified against real
Finder-equivalent opens: a from-scratch NSApplication with its own
delegate implementing application:openURLs: — in a process where we
own setDelegate: from the start, with no contention over the single
delegate slot winit already claims. That has to be a separate process
from the real GUI binary (only one -[NSApplication run] call can own a
process), so src/bin/ocs_launcher.rs is now the .app's actual
CFBundleExecutable: a small, dependency-light binary (no iced, wgpu,
or cadkernel) whose only job is to catch the open and relay it.
Relaying by replacing this process's image (exec, same PID) or by
spawning a child and exiting turned out to both be dead ends: Launch
Services tracks "the running instance of this bundle" by the
Application Serial Number it handed out to whichever process it
actually launched — this launcher, not whatever it execs into or
spawns. Once the launcher's own ASN stopped pointing at a live,
listening process, every later open Finder tried to deliver silently
went nowhere (measured with lsappinfo against a real second "Open
With", not assumed). So the launcher now stays running for the app's
session — invisible, via NSApplicationActivationPolicyAccessory, since
it owns no window — and relays every open (cold or warm) over the same
channel a second CLI invocation already uses: io::single_instance.
That relay only worked once single_instance's rendezvous key stopped
being computed from the running executable's own path. That was fine
when one binary always did the job, but the launcher and the real
binary are different executables and independently computed different
ports, so they could never find each other. Anchor the key on the
enclosing .app bundle instead, shared by both.
packaging/build_macos_signed.sh and .github/workflows/release.yml now
build ocs_launcher and place it at Contents/MacOS/OpenCADStudio (the
CFBundleExecutable Info.plist already names), with the real GUI binary
renamed to Contents/MacOS/OpenCADStudio-App alongside it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Finder thumbnails and "Open with" registration fail in the field for
three compounding reasons: the app claims com.autodesk.dwg/.dxf but
never declares them (UTImportedTypeDeclarations was missing, so on
systems with no other declarer Launch Services can't bind the
extensions at all); the QuickLook appex only serves com.autodesk.dwg
while machines with AutoCAD installed resolve .dwg to its exported
com.autodesk.autocad.dwg (BricsCAD etc. likewise win with their own
UTIs); and the ad-hoc --deep signature carries no entitlements, but a
QuickLook thumbnail extension must be sandboxed
(com.apple.security.app-sandbox) before macOS will run it.
Import-declare both UTIs, claim and serve the AutoCAD variants too,
add the appex sandbox entitlements, and add
packaging/build_macos_signed.sh — a local mirror of the CI build-macos
job that signs with a Developer ID (hardened runtime, per-component
entitlements), notarizes and staples. DEVELOPER_ID=- reproduces the
CI ad-hoc build.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>