Repository navigation
fix(macos): register UTV-bin with LaunchServices so its window is AXStandardWindow - #92
alfonsocasadodiez wants to merge 3 commits into
Conversation
…tandardWindow When started through LaunchServices, the launcher execv'd into UTV-bin, leaving LaunchServices with a stale record of the process (NSWorkspace reported pid -1) and hiding the window from System Events. Spawn UTV-bin instead so it registers itself. Terminal and --run launches still execv.
|
Thanks for this, and for tracking it down. I can reproduce it with 2026.11 from One concern before merging. When UTV is launched to open something (double-clicking an I haven't been able to confirm this on a full build, so I may be wrong. Could you try, on a build of this branch, with UTV not running:
If both open the media, great. If not, one way to keep your approach is for the launcher to collect those events before spawning: install Two smaller things worth noting in the PR description: I've approved the CI workflows for this PR. |
LaunchServices delivers odoc/GURL Apple Events to the launcher, not argv. Collect them with a short accessory-mode event loop before posix_spawn and pass them to UTV-bin as arguments.
|
Hey! With posix_spawn alone, opening an .exr or an rvlink:// URL started UTV empty. I've pushed a follow-up where the launcher collects the open/URL events before spawning (short accessory-mode event loop, 0.4s) and passes the paths/URLs to UTV-bin as arguments. Tested on a build of this branch, with UTV not running:
P.S. I needed some help from Claude to get this up and running |
|
Thanks, this works and the testing is thorough. Two small changes before we merge: 1. Stop waiting at I checked the delivery order with a small test app built the same way as the launcher (no ARC, accessory policy,
The launch Apple Event ( - (void)applicationDidFinishLaunching:(NSNotification *)notification {
self.finished = YES;
}
...
NSDate *deadline = [NSDate dateWithTimeIntervalSinceNow:3.0];
while (!collector.finished && [deadline timeIntervalSinceNow] > 0) {
NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:deadline inMode:NSDefaultRunLoopMode dequeue:YES];
if (event) [NSApp sendEvent:event];
}(I tested with a custom scheme rather than 2. Retain the collected array. Our CI doesn't run the full macOS build for pull requests from forks, so once these are in I'll push a copy of the branch to our repo to get one before merging. |
…ching Launch Apple Events are delivered before applicationDidFinishLaunching, so end the event loop there instead of after a fixed 0.4s, with a 3s upper bound. Also retain the collected array, since the launcher is built without ARC.
|
Thanks, both done and pushed.
I rebuilt with Hope this works! |
Summary
Launched from Finder/Dock/
open, UTV's window is invisible to Accessibility. System Events finds no windows forUTV-bin, while RV showsAXWindow, AXStandardWindow, Untitled. That breaks window managers and anything else that relies on AX.The window is fine. The problem is that the launcher
execvs intoUTV-bin, so LaunchServices still thinks the process isUTV(NSWorkspacereports pid -1). RV doesn't have this because itsCFBundleExecutableis the real binary.This PR makes the launcher
posix_spawnUTV-binand exit when started through LaunchServices, soUTV-binregisters itself. Terminal/CLI launches and--runstillexecv. I didn't setCFBundleExecutabletoUTV-binbecause that would drop the dependency-check dialogs.Documents and
rvlink://URLs arrive as Apple Events for the launcher, not in argv. Before spawning, the launcher now runs a short (0.4s) accessory-mode event loop, collects them, and passes them toUTV-binas arguments.Linked Issues
None.
Testing Done
Full
./build.sh --releasebuild of this branch, launched with UTV not running:NSWorkspace,AXWindow/AXStandardWindowopen -a UTV.app file.exr: media opensopen -a UTV.app 'rvlink://...': media opensKnown side effects of the launcher exiting right after the spawn:
open -Wreturns immediately, and the Dock icon may briefly disappear and reappear. Plain launches also take about 0.4s longer because of the event grace period.