macos: Fix gst_macos_main() terminating whole process before returning a value

Removes the usage of [NSApp terminate] to avoid killing the process and thus never actually returning a value.
The new way is just to use [NSApp stop] and send an event, since stop only happens after an event is processed.
Unlike terminate, stop will only halt the event loop, not the whole process.

This uses an NSApplicationDelegate to listen for NSApp finishing the launch process, and then signals the 'main' thread
to proceed. That makes sure to never call [NSApp stop] before NSApp is actually running, which could happen if the
provided 'main' function finished quickly enough.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6103>
This commit is contained in:
Piotr Brzeziński 2024-01-26 19:12:18 +01:00
parent 2f4e8d14cf
commit 6e59282af2

View file

@ -9,11 +9,37 @@ struct _ThreadArgs {
char **argv;
gpointer user_data;
gboolean is_simple;
GMutex nsapp_mutex;
GCond nsapp_cond;
};
@interface GstCocoaApplicationDelegate : NSObject <NSApplicationDelegate>
@property (assign) GMutex *nsapp_mutex;
@property (assign) GCond *nsapp_cond;
@end
@implementation GstCocoaApplicationDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)notification
{
g_mutex_lock (self.nsapp_mutex);
g_cond_signal (self.nsapp_cond);
g_mutex_unlock (self.nsapp_mutex);
}
@end
int
gst_thread_func (ThreadArgs *args)
{
/* Only proceed once NSApp is running, otherwise we could
* attempt to call [NSApp: stop] before it's even started. */
g_mutex_lock (&args->nsapp_mutex);
while (![[NSRunningApplication currentApplication] isFinishedLaunching]) {
g_cond_wait (&args->nsapp_cond, &args->nsapp_mutex);
}
g_mutex_unlock (&args->nsapp_mutex);
int ret;
if (args->is_simple) {
ret = ((GstMainFuncSimple) args->main_func) (args->user_data);
@ -21,7 +47,20 @@ gst_thread_func (ThreadArgs *args)
ret = ((GstMainFunc) args->main_func) (args->argc, args->argv, args->user_data);
}
[NSApp terminate: nil];
/* Post a message so we'll break out of the message loop */
NSEvent *event = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
location: NSZeroPoint
modifierFlags: 0
timestamp: 0
windowNumber: 0
context: nil
subtype: NSEventSubtypeApplicationActivated
data1: 0
data2: 0];
[NSApp postEvent:event atStart:YES];
[NSApp stop:nil];
return ret;
}
@ -29,15 +68,31 @@ int
run_main_with_nsapp (ThreadArgs args)
{
GThread *gst_thread;
GstCocoaApplicationDelegate* delegate;
int result;
[NSApplication sharedApplication];
g_mutex_init (&args.nsapp_mutex);
g_cond_init (&args.nsapp_cond);
[NSApplication sharedApplication];
delegate = [[GstCocoaApplicationDelegate alloc] init];
delegate.nsapp_mutex = &args.nsapp_mutex;
delegate.nsapp_cond = &args.nsapp_cond;
[NSApp setDelegate:delegate];
/* This lets us show an icon in the dock and correctly focus opened windows */
if ([NSApp activationPolicy] == NSApplicationActivationPolicyProhibited) {
[NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
}
gst_thread = g_thread_new ("macos-gst-thread", (GThreadFunc) gst_thread_func, &args);
[NSApp run];
result = GPOINTER_TO_INT (g_thread_join (gst_thread));
return GPOINTER_TO_INT (g_thread_join (gst_thread));
g_mutex_clear (&args.nsapp_mutex);
g_cond_clear (&args.nsapp_cond);
return result;
}
/**