Skip to content

Nocturne 1.2.0

Latest

Choose a tag to compare

@dotcomjack dotcomjack released this 09 Aug 19:09
· 1 commit to main since this release

Hover to show

The cover can now hand the bar back on demand. Turn on Hover to show and the strip drops away while the pointer is on the menu bar, then comes back when the pointer leaves. Off by default.

It exists so you can read the time by going to look for it, which is a deliberate act, rather than by changing a mode and then remembering to change it back. The point of the app was always to stop the clock catching your eye when you were not asking. It was never to stop you asking.

Offered in Gone and Hide everything only. Blind hides the time by writing Control Center's own IsAnalog preference, and undoing that costs a Control Center restart, which is a KeepAlive job on a 1s throttle. Half a second and a menu bar blink in each direction is not a hover.

It still asks for no permissions

That was the part worth getting right, because the whole locator is built around never triggering a Screen Recording prompt.

The pointer is read with a global mouse monitor. macOS gates key events behind accessibility and leaves mouse events alone, which is easy to assume and worth measuring. Measured on macOS 26.3.1 from an ad-hoc signed .app launched with open, so with no inherited terminal grant, reporting AXIsProcessTrusted() false:

Global monitor handle created
AXIsProcessTrusted() false
mouseMoved events delivered 131

Polling NSEvent.mouseLocation on a short timer was the alternative and is strictly worse: it wakes the CPU 20 times a second, forever, to notice a pointer that is usually not moving.

Three details that are less obvious than they look

The hover region is the whole menu bar, not the covered rect. In Gone the patch is a 44pt dial in the corner. Requiring the pointer to land on it exactly would read as broken. Moving to the bar at all is the gesture.

The strip goes transparent rather than being ordered out. A 2s tracker re-shows any window that is not visible, so ordering the strip out would put it back within two seconds while the pointer was still resting on the bar.

On more than one display, only the bar you are pointing at uncovers. Strips are matched to bars by intersection rather than by index, because both lists are built from a dictionary keyed by screen and that iteration order is not stable. Verified in a single pass: laptop strip at alpha 0.0, external strip at alpha 1.0.

There is also one more edge that only shows up in testing. CGRect.contains excludes its own max edge, and a menu bar band's top edge is the top of the screen, which is exactly where the pointer sits when you slam it upward to reach the bar. Without a one point expansion, the single most likely pointer position reads as not hovering.

Install

brew install --cask dotcomjack/tap/nocturne, or the DMG below. Universal, signed with a Developer ID and notarized, so it opens on a double click.