A silence worth chasing

When you’re tracing a fault on a board, the two things you want side by side are the board and its schematic. OpenBoardView does the first half — open a .brd file, tap a part, see its pins and nets and neighbours. It’s the free replacement for the old Test_Link and Landrex tools, and it lives open next to my microscope.

Its best trick is cross-probing: click a designator on the board and the schematic PDF jumps to that part. Click a part in the schematic and it lights up on the board. Once you’ve worked that way, going back to scrolling a PDF by hand feels like doing arithmetic on paper.

On my Mac, that button did nothing at all. No error, no beep, no log line. Click, nothing.

Not broken — never built

The instinct with a silent failure is to assume something’s crashing quietly. It wasn’t. I went looking and found the dispatch in BoardView.h: an #ifdef chain with a branch for Linux, a branch for Windows, and no branch for macOS. Falling off the end landed on the base PDFBridge class, whose methods are all empty.

So the click was calling into a function that does nothing and returning successfully. It wasn’t a bug, it was an unimplemented platform backend — which is a much better thing to find, because it means nobody has to be wrong for you to fix it.

Linux drives Evince, Windows drives SumatraPDF. Neither reimplements a PDF viewer; they just script one that already exists. macOS needed the same thing, and Skim is the obvious candidate — open source, still maintained, and scriptable out of the box. find, selection, go, and obtain cover everything the bridge needs, so there’s nothing to patch upstream of the patch.

Three things that weren’t obvious

Forward search was easy: build an AppleScript, run it, Skim jumps. The other direction took some learning.

Skim can’t tell you when the selection changes. There’s no cross-process signal for it, so the bridge polls on a background thread. That’s not elegant, but it’s what’s available, and it stays off the render loop — it writes to a mutex-guarded value the UI only ever compares against, so nothing blocks waiting on a PDF viewer.

Polling alone still wasn’t enough. OpenBoardView stops calling Update() once it’s been idle for a while, which is the right call for a desktop app that shouldn’t spin your fans. But it means a selection you make over in Skim doesn’t get noticed until you touch the mouse. The poll now pushes an SDL_PushEvent to wake the loop when something actually changed.

And the entitlement reproduced the original symptom exactly. Without NSAppleEventsUsageDescription in the bundle plist, macOS refuses the automation events — silently. Button does nothing. Same non-event as before, completely different cause. I lost a while to that one before the plist occurred to me.

Where it stands

It’s up as PR #363, everything macOS-specific behind a build guard so the Linux and Windows builds are untouched. Tested on an M4 Pro against a real board and its matching schematic — click a part, Skim jumps to the designator; select text in Skim, the part lights up on the board. Hands free.

It’s open upstream and I’m not going to pretend I know when it lands. In the meantime it’s running on my bench every day, which is the whole reason it exists. If you’re doing board-level work on a Mac and you’ve been wondering why that button never did anything — now you know, and there’s a fix waiting.