From 327f05a567f5dc9c14b27ce8b32ac7610d4d90d6 Mon Sep 17 00:00:00 2001 From: Kevin Zakka Date: Mon, 2 Mar 2026 12:48:38 -0800 Subject: [PATCH] Fix macOS crash on viewer close (NSScreen main-thread assertion) Hiding the dock icon after the viewer window closes triggers an asynchronous screen/dock reconfiguration via SkyLight. Without draining the main run loop, the resulting NSScreen invalidation notification is dispatched to a GCD worker thread, which hits NSScreen's main-thread assertion and crashes the process. Drain the main NSRunLoop briefly after setActivationPolicy: so the reconfiguration is processed on the main thread. --- python/mujoco/mjpython/mjpython.mm | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/python/mujoco/mjpython/mjpython.mm b/python/mujoco/mjpython/mjpython.mm index db857d04..12f1a6bd 100644 --- a/python/mujoco/mjpython/mjpython.mm +++ b/python/mujoco/mjpython/mjpython.mm @@ -36,6 +36,13 @@ extern char **environ; // for execve // so that we can dlsym and call them from Python via ctypes. __attribute__((used)) void mjpython_hide_dock_icon() { [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory]; + + // Drain pending Cocoa events on the main thread. The activation policy + // change triggers an asynchronous dock/screen reconfiguration via + // SkyLight. If we return before it's processed, the notification lands + // on a GCD worker thread and hits NSScreen's main-thread assertion. + NSDate* soon = [NSDate dateWithTimeIntervalSinceNow:0.01]; + [[NSRunLoop mainRunLoop] runUntilDate:soon]; } __attribute__((used)) void mjpython_show_dock_icon() { [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];