Skip to content

Commit

Permalink
Fix NSApplication blocking main thread
Browse files Browse the repository at this point in the history
  • Loading branch information
IsaacMarovitz committed Jul 27, 2023
1 parent 44fee38 commit 3a5c05f
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 0 deletions.
13 changes: 13 additions & 0 deletions src/SharpMetal.Examples.Animation/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ public static void Main()

// Create NSApplication
var nsApplication = new NSApplication();
var appDelegate = new NSApplicationDelegate(nsApplication);
nsApplication.SetDelegate(appDelegate);
appDelegate.OnDidFinishLaunching += OnDidFinishLaunching;

// Create and show NSWindow
var window = new NSWindow(rect, (ulong)(NSStyleMask.Titled | NSStyleMask.Resizable));
Expand Down Expand Up @@ -242,9 +245,19 @@ public static void Main()

nsApplication.Run();

while (true)
{
// Do stuff
}

// Release pool
autoreleasePool.Drain();
}

private static void OnDidFinishLaunching(NSApplication application)
{
application.Stop();
}
}

[StructLayout(LayoutKind.Sequential)]
Expand Down
10 changes: 10 additions & 0 deletions src/SharpMetal.Examples.Common/NSApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,15 @@ public void Run()
{
ObjectiveC.objc_msgSend(NativePtr, "run");
}

public void Stop()
{
ObjectiveC.objc_msgSend(NativePtr, "stop:", IntPtr.Zero);
}

public void SetDelegate(NSApplicationDelegate appDelegate)
{
ObjectiveC.objc_msgSend(NativePtr, "setDelegate:", appDelegate.NativePtr);
}
}
}
41 changes: 41 additions & 0 deletions src/SharpMetal.Examples.Common/NSApplicationDelegate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using SharpMetal.ObjectiveCCore;

namespace SharpMetal.Examples.Common
{
[SupportedOSPlatform("macos")]
public class NSApplicationDelegate
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void OnDidFinishLaunchingDelegate(IntPtr id, IntPtr cmd, IntPtr notification);

private OnDidFinishLaunchingDelegate _onDidFinishLaunching;
private NSApplication _application;

public Action<NSApplication> OnDidFinishLaunching;
public IntPtr NativePtr;

public unsafe NSApplicationDelegate(NSApplication application)
{
_application = application;
char[] name = "AppDelegate".ToCharArray();
char[] types = "v@:#".ToCharArray();

fixed (char* pName = name)
{
fixed (char* pTypes = types)
{
_onDidFinishLaunching = (_, _, _) => OnDidFinishLaunching?.Invoke(_application);
var delegatePtr = Marshal.GetFunctionPointerForDelegate(_onDidFinishLaunching);

var appDelegateClass = ObjectiveC.objc_allocateClassPair(new ObjectiveCClass("NSObject"), pName, 0);
var test = ObjectiveC.class_addMethod(appDelegateClass, "applicationDidFinishLaunching:", delegatePtr, pTypes);
ObjectiveC.objc_registerClassPair(appDelegateClass);

NativePtr = new ObjectiveCClass(appDelegateClass).AllocInit();
}
}
}
}
}
10 changes: 10 additions & 0 deletions src/SharpMetal.ObjectiveCCore/ObjectiveC.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ public static partial class ObjectiveC
[LibraryImport("libdl.dylib", StringMarshalling = StringMarshalling.Utf8)]
private static partial void dlopen(string path, int mode);

[LibraryImport(ObjCRuntime)]
public static unsafe partial IntPtr objc_allocateClassPair(IntPtr superclass, char* name, int extraBytes);

[LibraryImport(ObjCRuntime)]
[return: MarshalAs(UnmanagedType.Bool)]
public static unsafe partial bool class_addMethod(IntPtr cls, Selector selector, IntPtr imp, char* types);

[LibraryImport(ObjCRuntime)]
public static partial void objc_registerClassPair(IntPtr cls);

[LibraryImport(ObjCRuntime, EntryPoint = "objc_msgSend")]
public static partial void objc_msgSend(IntPtr receiver, Selector selector);

Expand Down

0 comments on commit 3a5c05f

Please sign in to comment.