Last active
May 5, 2024 03:54
-
-
Save brianmed/27ffcddac1f08d76e3f76e0d2be4229e to your computer and use it in GitHub Desktop.
C# Hello World gui app with slight SharpMetal modifications
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Runtime.Versioning; | |
using SharpMetal.ObjectiveCCore; | |
namespace SharpMetal.Examples.Common | |
{ | |
[SupportedOSPlatform("macos")] | |
public class NSApplication | |
{ | |
public IntPtr NativePtr; | |
public NSApplication(IntPtr ptr) | |
{ | |
NativePtr = ptr; | |
} | |
public NSApplication() | |
{ | |
NativePtr = ObjectiveC.IntPtr_objc_msgSend(new ObjectiveCClass("NSApplication"), "sharedApplication"); | |
} | |
public void Run() | |
{ | |
ObjectiveC.objc_msgSend(NativePtr, "run"); | |
} | |
public void Stop() | |
{ | |
ObjectiveC.objc_msgSend(NativePtr, "stop:", IntPtr.Zero); | |
} | |
public void ActivateIgnoringOtherApps(bool flag) | |
{ | |
ObjectiveC.objc_msgSend(NativePtr, "activateIgnoringOtherApps:", flag); | |
} | |
public bool SetActivationPolicy(NSApplicationActivationPolicy activationPolicy) | |
{ | |
return ObjectiveC.bool_objc_msgSend(NativePtr, "setActivationPolicy:", (long)activationPolicy); | |
} | |
public void SetDelegate(NSApplicationDelegate appDelegate) | |
{ | |
ObjectiveC.objc_msgSend(NativePtr, "setDelegate:", appDelegate.NativePtr); | |
} | |
} | |
public enum NSApplicationActivationPolicy : long | |
{ | |
Regular = 0, | |
Accessory = 1, | |
Prohibited = 2 | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Runtime.InteropServices; | |
using System.Runtime.Versioning; | |
using SharpMetal.Foundation; | |
using SharpMetal.ObjectiveCCore; | |
namespace SharpMetal.Examples.Common | |
{ | |
[SupportedOSPlatform("macos")] | |
public class NSApplicationDelegate | |
{ | |
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] | |
private delegate void OnApplicationWillFinishLaunchingDelegate(IntPtr id, IntPtr cmd, IntPtr notification); | |
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] | |
private delegate void OnApplicationDidFinishLaunchingDelegate(IntPtr id, IntPtr cmd, IntPtr notification); | |
private OnApplicationWillFinishLaunchingDelegate _onApplicationWillFinishLaunching; | |
private OnApplicationDidFinishLaunchingDelegate _onApplicationDidFinishLaunching; | |
public Action<NSNotification> OnApplicationWillFinishLaunching; | |
public Action<NSNotification> OnApplicationDidFinishLaunching; | |
public IntPtr NativePtr; | |
public unsafe NSApplicationDelegate(NSApplication application) | |
{ | |
char[] name = "AppDelegate".ToCharArray(); | |
char[] types = "v@:#".ToCharArray(); | |
fixed (char* pName = name) | |
{ | |
fixed (char* pTypes = types) | |
{ | |
_onApplicationWillFinishLaunching = (_, _, notif) => OnApplicationWillFinishLaunching?.Invoke(new NSNotification(notif)); | |
var onApplicationWillFinishLaunchingPtr = Marshal.GetFunctionPointerForDelegate(_onApplicationWillFinishLaunching); | |
_onApplicationDidFinishLaunching = (_, _, notif) => OnApplicationDidFinishLaunching?.Invoke(new NSNotification(notif)); | |
var onDidFinishLaunchingPtr = Marshal.GetFunctionPointerForDelegate(_onApplicationDidFinishLaunching); | |
var appDelegateClass = ObjectiveC.objc_allocateClassPair(new ObjectiveCClass("NSObject"), pName, 0); | |
ObjectiveC.class_addMethod(appDelegateClass, "applicationWillFinishLaunching:", onApplicationWillFinishLaunchingPtr, pTypes); | |
ObjectiveC.class_addMethod(appDelegateClass, "applicationDidFinishLaunching:", onDidFinishLaunchingPtr, pTypes); | |
ObjectiveC.objc_registerClassPair(appDelegateClass); | |
NativePtr = new ObjectiveCClass(appDelegateClass).AllocInit(); | |
} | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Runtime.InteropServices; | |
using System.Runtime.Versioning; | |
using SharpMetal.Foundation; | |
using Joy.ObjectiveCCore; | |
namespace SharpMetal.Examples.Common | |
{ | |
[SupportedOSPlatform("macos")] | |
public class NSWindow | |
{ | |
public IntPtr NativePtr; | |
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] | |
private delegate void OnWindowWillCloseDelegate(IntPtr id, IntPtr cmd, IntPtr notification); | |
private OnWindowWillCloseDelegate _onWindowWillClose; | |
public Action<NSNotification> OnWindowWillClose; | |
public unsafe NSWindow(NSRect rect, ulong styleMask) | |
{ | |
// NativePtr = new ObjectiveCClass("NSWindow").Alloc(); | |
// ObjectiveC.objc_msgSend(NativePtr, "initWithContentRect:styleMask:backing:defer:", rect, styleMask, 2, false); | |
char[] name = "WindowDelegate".ToCharArray(); | |
char[] types = "v@:@".ToCharArray(); | |
fixed (char* pName = name) | |
fixed (char* pTypes = types) | |
{ | |
// ObjectiveC.objc_registerClassPair(nsWindowClass); | |
IntPtr joy = ObjectiveC.objc_getClass("NSWindow"); | |
NativePtr = new ObjectiveCClass(joy).Alloc(); | |
ObjectiveC.objc_msgSend(NativePtr, "initWithContentRect:styleMask:backing:defer:", rect, styleMask, 2, false); | |
IntPtr windowDelegateClass = ObjectiveC.objc_allocateClassPair(new ObjectiveCClass("NSObject"), pName, 0); | |
IntPtr yay = ObjectiveC.objc_getProtocol("NSWindowDelegate"); | |
ObjectiveC.class_addProtocol(windowDelegateClass, yay); | |
_onWindowWillClose = (_, _, notif) => | |
{ | |
OnWindowWillClose?.Invoke(new NSNotification(notif)); | |
}; | |
IntPtr onWindowWillClosePtr = Marshal.GetFunctionPointerForDelegate(_onWindowWillClose); | |
ObjectiveC.class_addMethod(windowDelegateClass, "windowWillClose:", onWindowWillClosePtr, pTypes); | |
ObjectiveC.objc_msgSend(NativePtr, "setDelegate:", new ObjectiveCClass(windowDelegateClass).AllocInit()); | |
} | |
} | |
public NSString Title | |
{ | |
get => new(ObjectiveC.IntPtr_objc_msgSend(NativePtr, "title")); | |
set => ObjectiveC.objc_msgSend(NativePtr, "setTitle:", value); | |
} | |
public void SetContentView(IntPtr ptr) | |
{ | |
ObjectiveC.objc_msgSend(NativePtr, "setContentView:", ptr); | |
} | |
public void MakeKeyAndOrderFront() | |
{ | |
ObjectiveC.objc_msgSend(NativePtr, "makeKeyAndOrderFront:", IntPtr.Zero); | |
} | |
} | |
[SupportedOSPlatform("macos")] | |
[Flags] | |
public enum NSStyleMask : ulong | |
{ | |
Borderless = 0, | |
Titled = 1 << 0, | |
Closable = 1 << 1, | |
Miniaturizable = 1 << 2, | |
Resizable = 1 << 3, | |
FullScreen = 1 << 14, | |
FullSizeContentView = 1 << 15, | |
UtilityWindow = 1 << 4, | |
DocModalWindow = 1 << 6, | |
NonactivatingPanel = 1 << 7, | |
HUDWindow = 1 << 13 | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Runtime.InteropServices; | |
using System.Runtime.Versioning; | |
namespace Joy.ObjectiveCCore | |
{ | |
[SupportedOSPlatform("macos")] | |
public static partial class ObjectiveC | |
{ | |
public const string ObjCRuntime = "/usr/lib/libobjc.A.dylib"; | |
public const string MetalFramework = "/System/Library/Frameworks/Metal.framework/Metal"; | |
[LibraryImport(ObjCRuntime, StringMarshalling = StringMarshalling.Utf8)] | |
public static partial IntPtr objc_getClass(string name); | |
[LibraryImport(ObjCRuntime, StringMarshalling = StringMarshalling.Utf8)] | |
public static partial IntPtr objc_getProtocol(string name); | |
[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 unsafe partial IntPtr class_replaceMethod(IntPtr cls, Selector selector, IntPtr imp, char* types); | |
[LibraryImport(ObjCRuntime)] | |
[return: MarshalAs(UnmanagedType.Bool)] | |
public static unsafe partial bool class_addProtocol(IntPtr cls, IntPtr protocol); | |
[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); | |
[LibraryImport(ObjCRuntime, EntryPoint = "objc_msgSend")] | |
public static partial void objc_msgSend(IntPtr receiver, Selector selector, NSRect rect); | |
[LibraryImport(ObjCRuntime, EntryPoint = "objc_msgSend")] | |
public static partial void objc_msgSend(IntPtr receiver, Selector selector, byte value); | |
[LibraryImport(ObjCRuntime, EntryPoint = "objc_msgSend")] | |
public static partial void objc_msgSend(IntPtr receiver, Selector selector, double value); | |
[LibraryImport(ObjCRuntime, EntryPoint = "objc_msgSend")] | |
public static partial void objc_msgSend(IntPtr receiver, Selector selector, IntPtr ptr); | |
[LibraryImport(ObjCRuntime, EntryPoint = "objc_msgSend")] | |
[return: MarshalAs(UnmanagedType.Bool)] | |
public static unsafe partial bool bool_objc_msgSend(IntPtr receiver, Selector selector, char* buffer, ulong maxBufferCount, ulong encoding); | |
[LibraryImport(ObjCRuntime, EntryPoint = "objc_msgSend")] | |
[return: MarshalAs(UnmanagedType.Bool)] | |
public static partial bool bool_objc_msgSend(IntPtr receiver, Selector selector, long activationPolicy); | |
[LibraryImport(ObjCRuntime, EntryPoint = "objc_msgSend")] | |
public static partial void objc_msgSend(IntPtr receiver, Selector selector, ulong format, ulong index); | |
[LibraryImport(ObjCRuntime, EntryPoint = "objc_msgSend")] | |
public static partial void objc_msgSend(IntPtr receiver, Selector selector, NSRect rect, byte value); | |
[LibraryImport(ObjCRuntime, EntryPoint = "objc_msgSend")] | |
public static partial IntPtr IntPtr_objc_msgSend(IntPtr receiver, Selector selector, NSRect rect, IntPtr value); | |
[LibraryImport(ObjCRuntime, EntryPoint = "objc_msgSend")] | |
public static partial void objc_msgSend(IntPtr receiver, Selector selector, [MarshalAs(UnmanagedType.Bool)] bool value); | |
[LibraryImport(ObjCRuntime, EntryPoint = "objc_msgSend")] | |
public static partial void objc_msgSend(IntPtr receiver, Selector selector, NSRect contentRect, ulong style, ulong backingStoreType, [MarshalAs(UnmanagedType.Bool)] bool flag); | |
[LibraryImport(ObjCRuntime, EntryPoint = "objc_msgSend")] | |
public static partial IntPtr IntPtr_objc_msgSend(IntPtr receiver, Selector selector); | |
[LibraryImport(ObjCRuntime, EntryPoint = "objc_msgSend", StringMarshalling = StringMarshalling.Utf8)] | |
public static partial IntPtr IntPtr_objc_msgSend(IntPtr receiver, Selector selector, string param); | |
[LibraryImport(ObjCRuntime, EntryPoint = "objc_msgSend", StringMarshalling = StringMarshalling.Utf8)] | |
public static partial string string_objc_msgSend(IntPtr receiver, Selector selector); | |
[LibraryImport(ObjCRuntime, EntryPoint = "objc_msgSend")] | |
[return: MarshalAs(UnmanagedType.Bool)] | |
public static partial bool bool_objc_msgSend(IntPtr receiver, Selector selector); | |
[LibraryImport(ObjCRuntime, EntryPoint = "objc_msgSend")] | |
public static partial ulong ulong_objc_msgSend(IntPtr receiver, Selector selector); | |
public static void LinkMetal() | |
{ | |
dlopen("/System/Library/Frameworks/Metal.framework/Metal", 0); | |
} | |
public static void LinkCoreGraphics() | |
{ | |
dlopen("/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics", 0); | |
} | |
public static void LinkAppKit() | |
{ | |
dlopen("/System/Library/Frameworks/AppKit.framework/AppKit", 0); | |
} | |
public static void LinkMetalKit() | |
{ | |
dlopen("/System/Library/Frameworks/MetalKit.framework/MetalKit", 0); | |
} | |
} | |
public readonly struct NSPoint | |
{ | |
public readonly double X; | |
public readonly double Y; | |
public NSPoint(double x, double y) | |
{ | |
X = x; | |
Y = y; | |
} | |
} | |
public readonly struct NSRect | |
{ | |
public readonly NSPoint Pos; | |
public readonly NSPoint Size; | |
public NSRect(double x, double y, double width, double height) | |
{ | |
Pos = new NSPoint(x, y); | |
Size = new NSPoint(width, height); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Runtime.Versioning; | |
namespace Joy.ObjectiveCCore | |
{ | |
[SupportedOSPlatform("macos")] | |
public struct ObjectiveCClass | |
{ | |
public readonly IntPtr NativePtr; | |
public static implicit operator IntPtr(ObjectiveCClass c) => c.NativePtr; | |
public ObjectiveCClass(IntPtr ptr) | |
{ | |
NativePtr = ptr; | |
} | |
public ObjectiveCClass(string name) | |
{ | |
var ptr = ObjectiveC.objc_getClass(name); | |
if (ptr == IntPtr.Zero) | |
{ | |
Console.WriteLine($"Failed to get class {name}!"); | |
} | |
NativePtr = ptr; | |
} | |
public ObjectiveCClass AllocInit() | |
{ | |
var value = ObjectiveC.IntPtr_objc_msgSend(NativePtr, "alloc"); | |
ObjectiveC.objc_msgSend(value, "init"); | |
return new ObjectiveCClass(value); | |
} | |
public ObjectiveCClass Alloc() | |
{ | |
var value = ObjectiveC.IntPtr_objc_msgSend(NativePtr, "alloc"); | |
return new ObjectiveCClass(value); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Project Sdk="Microsoft.NET.Sdk"> | |
<PropertyGroup> | |
<OutputType>Exe</OutputType> | |
<TargetFramework>net8.0</TargetFramework> | |
<ImplicitUsings>enable</ImplicitUsings> | |
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> | |
<Nullable>enable</Nullable> | |
</PropertyGroup> | |
<ItemGroup> | |
<PackageReference Include="SharpMetal" Version="1.0.0-preview12" /> | |
</ItemGroup> | |
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Runtime.Versioning; | |
using SharpMetal.Foundation; | |
using Joy.ObjectiveCCore; | |
using SharpMetal.Examples.Common; | |
// OMG!! | |
// | |
// https://github.com/IsaacMarovitz/SharpMetal | |
namespace ObjectiveCHelloWorld; | |
[SupportedOSPlatform("macos")] | |
public class Program | |
{ | |
private const int X = 100; | |
private const int Y = 100; | |
private const int Width = 800; | |
private const int Height = 600; | |
private const string WindowTitle = "Hello World"; | |
public static void Main() | |
{ | |
ObjectiveC.LinkAppKit(); | |
// Create NSApplication | |
var nsApplication = new NSApplication(); | |
var appDelegate = new NSApplicationDelegate(nsApplication); | |
nsApplication.SetDelegate(appDelegate); | |
appDelegate.OnApplicationDidFinishLaunching += OnApplicationDidFinishLaunching; | |
appDelegate.OnApplicationWillFinishLaunching += OnApplicationWillFinishLaunching; | |
nsApplication.Run(); | |
} | |
private static void OnWindowWillClose(NSNotification notification) | |
{ | |
Environment.Exit(0); | |
} | |
private static void OnApplicationWillFinishLaunching(NSNotification notification) | |
{ | |
var app = new NSApplication(notification.Object); | |
app.SetActivationPolicy(NSApplicationActivationPolicy.Regular); | |
} | |
private static void OnApplicationDidFinishLaunching(NSNotification notification) | |
{ | |
NSRect rect = new NSRect(X, Y, Width, Height); | |
NSWindow window = new NSWindow(rect, (ulong)(NSStyleMask.Titled | NSStyleMask.Resizable | NSStyleMask.Closable | NSStyleMask.Miniaturizable)); | |
window.OnWindowWillClose += OnWindowWillClose; | |
IntPtr nsView = ObjectiveC.objc_getClass("NSView"); | |
IntPtr joy = new ObjectiveCClass(nsView).Alloc(); | |
ObjectiveC.objc_msgSend(joy, "initWithFrame:", rect); | |
IntPtr textFieldClass = ObjectiveC.objc_getClass("NSTextField"); | |
IntPtr textField = new ObjectiveCClass(textFieldClass).Alloc(); | |
ObjectiveC.objc_msgSend(textField, "initWithFrame:", new NSRect(Width/2.0f, Height/2.0f, 200, 17)); | |
ObjectiveC.objc_msgSend(textField, "setStringValue:", StringHelper.NSString("Hello World")); | |
ObjectiveC.objc_msgSend(textField, "setEditable:", false); | |
ObjectiveC.objc_msgSend(textField, "setBezeled:", false); | |
ObjectiveC.objc_msgSend(textField, "setDrawsBackground:", false); | |
ObjectiveC.objc_msgSend(joy, "addSubview:", textField); | |
window.SetContentView(joy); | |
window.Title = StringHelper.NSString(WindowTitle); | |
// ObjectiveC.objc_msgSend(window.NativePtr, "becomeFirstResponder"); | |
window.MakeKeyAndOrderFront(); | |
NSApplication app = new NSApplication(notification.Object); | |
app.ActivateIgnoringOtherApps(true); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Runtime.InteropServices; | |
namespace Joy.ObjectiveCCore | |
{ | |
public partial struct Selector | |
{ | |
[LibraryImport("/usr/lib/libobjc.A.dylib", StringMarshalling = StringMarshalling.Utf8)] | |
private static unsafe partial IntPtr sel_getUid(string name); | |
[LibraryImport("/usr/lib/libobjc.A.dylib")] | |
private static unsafe partial IntPtr sel_getName(IntPtr sel); | |
public readonly IntPtr SelPtr; | |
public Selector(string name) | |
{ | |
var ptr = sel_getUid(name); | |
if (ptr == IntPtr.Zero) | |
{ | |
Console.WriteLine($"Failed to get selector {name}!"); | |
} | |
SelPtr = ptr; | |
} | |
public string Name | |
{ | |
get | |
{ | |
var ptr = sel_getName(SelPtr); | |
return Marshal.PtrToStringAnsi(ptr) ?? string.Empty; | |
} | |
} | |
public static implicit operator Selector(string value) => new(value); | |
public static implicit operator IntPtr(Selector sel) => sel.SelPtr; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Runtime.Versioning; | |
using SharpMetal.Foundation; | |
using SharpMetal.ObjectiveCCore; | |
namespace SharpMetal.Examples.Common | |
{ | |
[SupportedOSPlatform("macos")] | |
public static class StringHelper | |
{ | |
public static NSString NSString(string source) | |
{ | |
return new(ObjectiveC.IntPtr_objc_msgSend(new ObjectiveCClass("NSString"), "stringWithUTF8String:", source)); | |
} | |
public static unsafe string String(NSString source) | |
{ | |
char[] sourceBuffer = new char[source.Length]; | |
fixed (char* pSourceBuffer = sourceBuffer) | |
{ | |
ObjectiveC.bool_objc_msgSend(source, | |
"getCString:maxLength:encoding:", | |
pSourceBuffer, | |
source.MaximumLengthOfBytes(NSStringEncoding.UTF16) + 1, | |
(ulong)NSStringEncoding.UTF16); | |
} | |
return new string(sourceBuffer); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment