From ce47546a7e70f9ba8636f659939ee9de6b70ee33 Mon Sep 17 00:00:00 2001 From: Christian Meinerding Date: Sat, 21 Feb 2026 22:55:57 +0100 Subject: [PATCH] Fix app freeze by removing nested CFRunLoopRun() from main thread The app became unresponsive ("Not Responding") because startEventSession called CFRunLoopRun() which blocked the main thread in a nested run loop, preventing NSApplication from processing UI events. In a Cocoa app the main run loop is already running via [NSApp run], so only adding/removing the event tap source is needed. Also adds disableAutomaticTermination/disableSuddenTermination to prevent macOS from killing this windowless menu bar app. Co-Authored-By: Claude Opus 4.6 --- MacMediaKeyForwarder/AppDelegate.m | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/MacMediaKeyForwarder/AppDelegate.m b/MacMediaKeyForwarder/AppDelegate.m index 3dc5afb..a93388c 100755 --- a/MacMediaKeyForwarder/AppDelegate.m +++ b/MacMediaKeyForwarder/AppDelegate.m @@ -285,8 +285,12 @@ - (void)applicationDidBecomeActive:(NSNotification *)notification - ( void ) applicationDidFinishLaunching : ( NSNotification*) theNotification { + // Prevent macOS Automatic Termination from killing this windowless menu bar app + [[NSProcessInfo processInfo] disableAutomaticTermination:@"Media key forwarding active"]; + [[NSProcessInfo processInfo] disableSuddenTermination]; + // init containers - + priorityOptionItems = [[NSMutableArray alloc] init]; pauseOptionItems = [[NSMutableArray alloc] init]; @@ -422,7 +426,6 @@ - ( void ) startEventSession { if (pauseState != PauseStatePause && !CFRunLoopContainsSource(CFRunLoopGetCurrent(), eventPortSource, kCFRunLoopCommonModes)) { CFRunLoopAddSource( CFRunLoopGetCurrent(), eventPortSource, kCFRunLoopCommonModes ); - CFRunLoopRun(); } } @@ -430,7 +433,6 @@ - ( void ) stopEventSession { if (CFRunLoopContainsSource(CFRunLoopGetCurrent(), eventPortSource, kCFRunLoopCommonModes)) { CFRunLoopRemoveSource( CFRunLoopGetCurrent(), eventPortSource, kCFRunLoopCommonModes ); - CFRunLoopStop(CFRunLoopGetCurrent()); } }