Skip to content

Instantly share code, notes, and snippets.

@xenobrain
Last active June 28, 2023 14:07

Revisions

  1. xenobrain revised this gist Jun 28, 2023. 1 changed file with 57 additions and 46 deletions.
    103 changes: 57 additions & 46 deletions main.cpp
    Original file line number Diff line number Diff line change
    @@ -1,73 +1,84 @@
    #include <objc/objc-runtime.h>
    #include <objc/NSObjCRuntime.h>
    #include <CoreGraphics/CoreGraphics.h>

    auto static constexpr WINDOW_TITLE = "Prototype";
    auto static constexpr WINDOW_WIDTH = 1280;
    auto static constexpr WINDOW_HEIGHT = 720;

    template <typename... Args> auto send(id obj, char const* selector, Args... args) {
    return reinterpret_cast<id (*)(id, SEL, Args...)>(objc_msgSend)(obj, sel_registerName(selector), args...);
    }

    template <typename... Args> auto send(char const* cls, char const* selector, Args... args) {
    return send(reinterpret_cast<id>(objc_getClass(cls)), selector, args...);
    template<typename R, typename... Args> auto send(id obj, const char* selector, Args... args) {
    return reinterpret_cast<R(*)(id, SEL, Args...)>(objc_msgSend)(obj, sel_getUid(selector), args...);
    }
    template<typename T> auto get_class(const char* className) { return reinterpret_cast<T>(objc_getClass(className)); }

    extern id NSApp;
    extern id NSDefaultRunLoopMode;

    id static window;
    id static metalLayer;
    objc_class* windowDelegate;

    auto static running = true;

    class Window {
    public:
    auto run() -> int {
    send(send("NSApplication","sharedApplication"), "setActivationPolicy:", 0);
    namespace xc::platform {
    auto windowWillClose(id self, SEL _cmd, id sender) -> void {
    send<void>(NSApp, "terminate:", nil);
    running = false;
    }

    auto windowDelegate = objc_allocateClassPair(objc_getClass("NSObject"), "WindowDelegate", 0);
    auto create_metal_layer() -> void {
    metalLayer = send<id>(get_class<id>("CAMetalLayer"), "new");
    send<void>(metalLayer, "setDevice:", send<id>(get_class<id>("MTLCreateSystemDefaultDevice"), "new"));
    send<void>(metalLayer, "setPixelFormat:", 70); // MTLPixelFormatBGRA8Unorm
    send<void>(metalLayer, "setFrame:", CGRectMake(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT));

    auto contentView = send<id>(window, "contentView");
    send<void>(contentView, "setWantsLayer:", YES);
    send<void>(contentView, "setLayer:", metalLayer);
    }

    auto initialize() -> bool {
    NSApp = send<id>(get_class<id>("NSApplication"), "sharedApplication");
    send<void>(NSApp, "setActivationPolicy:", 0);
    send<void>(NSApp, "activateIgnoringOtherApps:", YES);

    windowDelegate = objc_allocateClassPair(objc_getClass("NSResponder"), "WindowDelegate", 0);
    class_addMethod(windowDelegate, sel_registerName("windowWillClose:"), reinterpret_cast<IMP>(windowWillClose), "v@:@");
    objc_registerClassPair(windowDelegate);

    _window = send("NSWindow", "alloc");
    send(_window, "initWithContentRect:styleMask:backing:defer:", CGRectMake(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT), 15, 2, NO);
    send(_window, "setTitle:", send("NSString", "stringWithUTF8String:", WINDOW_TITLE));
    send(_window, "center");
    send(_window, "setDelegate:", send("WindowDelegate", "new"));
    send(_window, "makeKeyAndOrderFront:", nil);
    send(send("NSApplication","sharedApplication"), "activateIgnoringOtherApps:", YES);

    createMetalLayer();
    window = send<id>(get_class<id>("NSWindow"), "alloc");
    send<void>(window, "initWithContentRect:styleMask:backing:defer:", CGRectMake(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT), 15, 2, NO);
    send<void>(window, "setTitle:", send<id>(get_class<id>("NSString"), "stringWithUTF8String:", WINDOW_TITLE));
    send<void>(window, "center");
    send<void>(window, "setDelegate:", send<id>(get_class<id>("WindowDelegate"), "new"));
    send<void>(window, "makeKeyAndOrderFront:", nil);

    while (running) {
    send(send(_window, "contentView"), "setNeedsDisplay:", YES);
    id event = send(send("NSApplication","sharedApplication"), "nextEventMatchingMask:untilDate:inMode:dequeue:", ULONG_MAX, nil, NSDefaultRunLoopMode, YES);
    send(send("NSApplication","sharedApplication"), "sendEvent:", event);
    }
    create_metal_layer();
    return true;
    }

    auto uninitialize() -> void {
    objc_disposeClassPair(windowDelegate);
    send(_metalLayer, "release");
    send(_window, "release");
    return 0;
    send<void>(metalLayer, "release");
    send<void>(window, "release");
    }

    private:
    id _window;
    id _metalLayer;
    auto tick() -> void {
    while (running) {
    send<void>(send<id>(window, "contentView"), "setNeedsDisplay:", YES);
    id event = send<id>(NSApp, "nextEventMatchingMask:untilDate:inMode:dequeue:", ULONG_MAX, nil, NSDefaultRunLoopMode, YES);

    auto static windowWillClose(id self, SEL _cmd, id sender) -> void {
    send(send("NSApplication", "sharedApplication"),"terminate:", nil);
    running = false;
    send<void>(NSApp, "sendEvent:", event);
    }
    }
    }

    auto createMetalLayer() -> void {
    _metalLayer = send("CAMetalLayer", "new");
    send(_metalLayer, "setDevice:", send("MTLCreateSystemDefaultDevice", "new"));
    send(_metalLayer, "setPixelFormat:", 70); // MTLPixelFormatBGRA8Unorm
    send(_metalLayer, "setFrame:", CGRectMake(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT));
    extern "C" auto entry() -> void {
    xc::platform::initialize();

    auto contentView = send(_window, "contentView");
    send(contentView, "setWantsLayer:", YES);
    send(contentView, "setLayer:", _metalLayer);
    while (running) {
    xc::platform::tick();
    }
    };

    extern "C" auto entry() -> void {
    Window{}.run();
    }
    xc::platform::uninitialize();
    }
  2. xenobrain revised this gist Jun 27, 2023. 1 changed file with 29 additions and 0 deletions.
    29 changes: 29 additions & 0 deletions CMakeLists.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,29 @@
    cmake_minimum_required(VERSION 3.25)
    project(CocoaWindow)

    set(CMAKE_CXX_STANDARD 20)

    # Install CPM ##########################################################################################################
    set(CPM_VERSION 0.38.1)
    set(CPM_SOURCE_CACHE ${CMAKE_SOURCE_DIR}/libraries)
    set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")

    if(NOT (EXISTS ${CPM_DOWNLOAD_LOCATION}))
    file(DOWNLOAD https://github.com/TheLartians/CPM.cmake/releases/download/v${CPM_VERSION}/CPM.cmake
    ${CPM_DOWNLOAD_LOCATION})
    endif()

    include(${CPM_DOWNLOAD_LOCATION})


    # Build Game Executable ###############################################################################################
    add_executable(CocoaWindow main.cpp)
    target_link_libraries(CocoaWindow PRIVATE "-framework System -framework Cocoa")

    CPMAddPackage("gh:KhronosGroup/Vulkan-Headers@1.3.255")
    CPMAddPackage("gh:bkaradzic/metal-cpp#metal-cpp_macOS13.3_iOS16.4")
    target_include_directories(CocoaWindow PRIVATE ${metal-cpp_SOURCE_DIR})
    target_include_directories(CocoaWindow PRIVATE ${Vulkan-Headers_SOURCE_DIR}/include)
    target_compile_definitions(CocoaWindow PRIVATE VK_NO_PROTOTYPES VK_USE_PLATFORM_METAL_EXT)
    target_compile_options(CocoaWindow PRIVATE -fno-rtti)
    target_link_options(CocoaWindow PRIVATE -e _entry -nostartfiles -nodefaultlibs)
  3. xenobrain revised this gist Jun 27, 2023. 1 changed file with 4 additions and 8 deletions.
    12 changes: 4 additions & 8 deletions main.cpp
    Original file line number Diff line number Diff line change
    @@ -14,16 +14,10 @@ template <typename... Args> auto send(char const* cls, char const* selector, Arg
    }

    extern id NSDefaultRunLoopMode;

    auto static running = true;

    class Window {
    public:
    ~Window() {
    send(_metalLayer, "release");
    send(_window, "release");
    }

    auto run() -> int {
    send(send("NSApplication","sharedApplication"), "setActivationPolicy:", 0);

    @@ -48,6 +42,8 @@ class Window {
    }

    objc_disposeClassPair(windowDelegate);
    send(_metalLayer, "release");
    send(_window, "release");
    return 0;
    }

    @@ -72,6 +68,6 @@ class Window {
    }
    };

    auto main(int, char**) -> int {
    return Window{}.run();
    extern "C" auto entry() -> void {
    Window{}.run();
    }
  4. xenobrain revised this gist Jun 27, 2023. 1 changed file with 4 additions and 5 deletions.
    9 changes: 4 additions & 5 deletions main.cpp
    Original file line number Diff line number Diff line change
    @@ -25,8 +25,7 @@ class Window {
    }

    auto run() -> int {
    auto application = send("NSApplication","sharedApplication");
    send(application, "setActivationPolicy:", 0);
    send(send("NSApplication","sharedApplication"), "setActivationPolicy:", 0);

    auto windowDelegate = objc_allocateClassPair(objc_getClass("NSObject"), "WindowDelegate", 0);
    class_addMethod(windowDelegate, sel_registerName("windowWillClose:"), reinterpret_cast<IMP>(windowWillClose), "v@:@");
    @@ -38,14 +37,14 @@ class Window {
    send(_window, "center");
    send(_window, "setDelegate:", send("WindowDelegate", "new"));
    send(_window, "makeKeyAndOrderFront:", nil);
    send(application, "activateIgnoringOtherApps:", YES);
    send(send("NSApplication","sharedApplication"), "activateIgnoringOtherApps:", YES);

    createMetalLayer();

    while (running) {
    send(send(_window, "contentView"), "setNeedsDisplay:", YES);
    id event = send(application, "nextEventMatchingMask:untilDate:inMode:dequeue:", ULONG_MAX, nil, NSDefaultRunLoopMode, YES);
    send(application, "sendEvent:", event);
    id event = send(send("NSApplication","sharedApplication"), "nextEventMatchingMask:untilDate:inMode:dequeue:", ULONG_MAX, nil, NSDefaultRunLoopMode, YES);
    send(send("NSApplication","sharedApplication"), "sendEvent:", event);
    }

    objc_disposeClassPair(windowDelegate);
  5. xenobrain revised this gist Jun 27, 2023. 1 changed file with 41 additions and 31 deletions.
    72 changes: 41 additions & 31 deletions main.cpp
    Original file line number Diff line number Diff line change
    @@ -1,42 +1,52 @@
    #include <objc/runtime.h>
    #include <objc/message.h>
    #include <objc/objc-runtime.h>
    #include <CoreGraphics/CoreGraphics.h>

    template <typename... Args> auto send(id obj, SEL selector, Args... args) {
    return reinterpret_cast<id (*)(id, SEL, Args...)>(objc_msgSend)(obj, selector, args...);
    auto static constexpr WINDOW_TITLE = "Prototype";
    auto static constexpr WINDOW_WIDTH = 1280;
    auto static constexpr WINDOW_HEIGHT = 720;

    template <typename... Args> auto send(id obj, char const* selector, Args... args) {
    return reinterpret_cast<id (*)(id, SEL, Args...)>(objc_msgSend)(obj, sel_registerName(selector), args...);
    }

    template <typename... Args> auto send(Class cls, SEL selector, Args... args) {
    return reinterpret_cast<id (*)(id, SEL, Args...)>(objc_msgSend)(reinterpret_cast<id>(cls), selector, args...);
    template <typename... Args> auto send(char const* cls, char const* selector, Args... args) {
    return send(reinterpret_cast<id>(objc_getClass(cls)), selector, args...);
    }

    extern id NSDefaultRunLoopMode;

    auto static running = true;

    class Window {
    public:
    ~Window() {
    send(_metalLayer, sel_registerName("release"));
    send(_window, sel_registerName("release"));
    send(_metalLayer, "release");
    send(_window, "release");
    }

    int run() {
    auto application = send(objc_getClass("NSApplication"), sel_registerName("sharedApplication"));
    send(application, sel_registerName("setActivationPolicy:"), 0);
    auto run() -> int {
    auto application = send("NSApplication","sharedApplication");
    send(application, "setActivationPolicy:", 0);

    auto windowDelegate = objc_allocateClassPair(objc_getClass("NSObject"), "WindowDelegate", 0);
    class_addMethod(windowDelegate, sel_registerName("windowWillClose:"), reinterpret_cast<IMP>(windowWillClose), "v@:@");
    objc_registerClassPair(windowDelegate);

    _window = send(objc_getClass("NSWindow"), sel_registerName("alloc"));
    send(_window, sel_registerName("initWithContentRect:styleMask:backing:defer:"), CGRectMake(0, 0, 800, 600), 15, 2, NO);
    send(_window, sel_registerName("setTitle:"), send(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "Cocoa window"));
    send(_window, sel_registerName("center"));
    send(_window, sel_registerName("setDelegate:"), send(windowDelegate, sel_registerName("new")));
    send(_window, sel_registerName("makeKeyAndOrderFront:"), nil);
    send(application, sel_registerName("activateIgnoringOtherApps:"), YES);
    _window = send("NSWindow", "alloc");
    send(_window, "initWithContentRect:styleMask:backing:defer:", CGRectMake(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT), 15, 2, NO);
    send(_window, "setTitle:", send("NSString", "stringWithUTF8String:", WINDOW_TITLE));
    send(_window, "center");
    send(_window, "setDelegate:", send("WindowDelegate", "new"));
    send(_window, "makeKeyAndOrderFront:", nil);
    send(application, "activateIgnoringOtherApps:", YES);

    createMetalLayer();

    send(send(objc_getClass("NSApplication"), sel_registerName("sharedApplication")), sel_registerName("run"));
    while (running) {
    send(send(_window, "contentView"), "setNeedsDisplay:", YES);
    id event = send(application, "nextEventMatchingMask:untilDate:inMode:dequeue:", ULONG_MAX, nil, NSDefaultRunLoopMode, YES);
    send(application, "sendEvent:", event);
    }

    objc_disposeClassPair(windowDelegate);
    return 0;
    @@ -46,23 +56,23 @@ class Window {
    id _window;
    id _metalLayer;

    static void windowWillClose(id self, SEL _cmd, id sender) {
    send(send(objc_getClass("NSApplication"), sel_registerName("sharedApplication")),
    sel_registerName("terminate:"), nil);
    auto static windowWillClose(id self, SEL _cmd, id sender) -> void {
    send(send("NSApplication", "sharedApplication"),"terminate:", nil);
    running = false;
    }

    void createMetalLayer() {
    _metalLayer = send(objc_getClass("CAMetalLayer"), sel_registerName("new"));
    send(_metalLayer, sel_registerName("setDevice:"), send(objc_getClass("MTLCreateSystemDefaultDevice"), sel_registerName("new")));
    send(_metalLayer, sel_registerName("setPixelFormat:"), 70); // MTLPixelFormatBGRA8Unorm
    send(_metalLayer, sel_registerName("setFrame:"), CGRectMake(0, 0, 800, 600));
    auto createMetalLayer() -> void {
    _metalLayer = send("CAMetalLayer", "new");
    send(_metalLayer, "setDevice:", send("MTLCreateSystemDefaultDevice", "new"));
    send(_metalLayer, "setPixelFormat:", 70); // MTLPixelFormatBGRA8Unorm
    send(_metalLayer, "setFrame:", CGRectMake(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT));

    auto contentView = send(_window, sel_registerName("contentView"));
    send(contentView, sel_registerName("setWantsLayer:"), YES);
    send(contentView, sel_registerName("setLayer:"), _metalLayer);
    auto contentView = send(_window, "contentView");
    send(contentView, "setWantsLayer:", YES);
    send(contentView, "setLayer:", _metalLayer);
    }
    };

    int main() {
    auto main(int, char**) -> int {
    return Window{}.run();
    }
  6. xenobrain revised this gist Jun 27, 2023. 1 changed file with 29 additions and 26 deletions.
    55 changes: 29 additions & 26 deletions main.cpp
    Original file line number Diff line number Diff line change
    @@ -2,35 +2,41 @@
    #include <objc/message.h>
    #include <CoreGraphics/CoreGraphics.h>

    template <typename Return, typename... Args> auto send(id obj, SEL selector, Args... args) {
    return reinterpret_cast<Return (*)(id, SEL, Args...)>(objc_msgSend)(obj, selector, args...);
    template <typename... Args> auto send(id obj, SEL selector, Args... args) {
    return reinterpret_cast<id (*)(id, SEL, Args...)>(objc_msgSend)(obj, selector, args...);
    }

    template <typename Return, typename... Args> auto send(Class cls, SEL selector, Args... args) {
    return reinterpret_cast<Return (*)(id, SEL, Args...)>(objc_msgSend)(reinterpret_cast<id>(cls), selector, args...);
    template <typename... Args> auto send(Class cls, SEL selector, Args... args) {
    return reinterpret_cast<id (*)(id, SEL, Args...)>(objc_msgSend)(reinterpret_cast<id>(cls), selector, args...);
    }


    class Window {
    public:
    ~Window() {
    send(_metalLayer, sel_registerName("release"));
    send(_window, sel_registerName("release"));
    }

    int run() {
    auto application = send<id>(objc_getClass("NSApplication"), sel_registerName("sharedApplication"));
    send<void>(application, sel_registerName("setActivationPolicy:"), 0);
    auto application = send(objc_getClass("NSApplication"), sel_registerName("sharedApplication"));
    send(application, sel_registerName("setActivationPolicy:"), 0);

    auto windowDelegate = objc_allocateClassPair(objc_getClass("NSObject"), "WindowDelegate", 0);
    class_addMethod(windowDelegate, sel_registerName("windowWillClose:"), reinterpret_cast<IMP>(windowWillClose), "v@:@");
    objc_registerClassPair(windowDelegate);

    _window = send<id>(objc_getClass("NSWindow"), sel_registerName("alloc"));
    send<void>(_window, sel_registerName("initWithContentRect:styleMask:backing:defer:"), CGRectMake(0, 0, 800, 600), 15, 2, NO);
    send<void>(_window, sel_registerName("setTitle:"), send<id>(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "Cocoa window"));
    send<void>(_window, sel_registerName("center"));
    send<void>(_window, sel_registerName("setDelegate:"), send<id>(windowDelegate, sel_registerName("new")));
    send<void>(_window, sel_registerName("makeKeyAndOrderFront:"), nil);
    send<void>(application, sel_registerName("activateIgnoringOtherApps:"), YES);
    _window = send(objc_getClass("NSWindow"), sel_registerName("alloc"));
    send(_window, sel_registerName("initWithContentRect:styleMask:backing:defer:"), CGRectMake(0, 0, 800, 600), 15, 2, NO);
    send(_window, sel_registerName("setTitle:"), send(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "Cocoa window"));
    send(_window, sel_registerName("center"));
    send(_window, sel_registerName("setDelegate:"), send(windowDelegate, sel_registerName("new")));
    send(_window, sel_registerName("makeKeyAndOrderFront:"), nil);
    send(application, sel_registerName("activateIgnoringOtherApps:"), YES);

    createMetalLayer();

    send<void>(send<id>(objc_getClass("NSApplication"), sel_registerName("sharedApplication")), sel_registerName("run"));
    send(send(objc_getClass("NSApplication"), sel_registerName("sharedApplication")), sel_registerName("run"));

    objc_disposeClassPair(windowDelegate);
    return 0;
    @@ -41,25 +47,22 @@ class Window {
    id _metalLayer;

    static void windowWillClose(id self, SEL _cmd, id sender) {
    send<void>(send<id>(objc_getClass("NSApplication"), sel_registerName("sharedApplication")),
    send(send(objc_getClass("NSApplication"), sel_registerName("sharedApplication")),
    sel_registerName("terminate:"), nil);
    }

    void createMetalLayer() {
    _metalLayer = send<id>(objc_getClass("CAMetalLayer"), sel_registerName("new"));
    send<void>(_metalLayer, sel_registerName("setDevice:"), send<id>(objc_getClass("MTLCreateSystemDefaultDevice"), sel_registerName("new")));
    send<void>(_metalLayer, sel_registerName("setPixelFormat:"), 70); // MTLPixelFormatBGRA8Unorm
    send<void>(_metalLayer, sel_registerName("setFrame:"), CGRectMake(0, 0, 800, 600));
    _metalLayer = send(objc_getClass("CAMetalLayer"), sel_registerName("new"));
    send(_metalLayer, sel_registerName("setDevice:"), send(objc_getClass("MTLCreateSystemDefaultDevice"), sel_registerName("new")));
    send(_metalLayer, sel_registerName("setPixelFormat:"), 70); // MTLPixelFormatBGRA8Unorm
    send(_metalLayer, sel_registerName("setFrame:"), CGRectMake(0, 0, 800, 600));

    auto contentView = send<id>(_window, sel_registerName("contentView"));
    send<void>(contentView, sel_registerName("setWantsLayer:"), YES);
    send<void>(contentView, sel_registerName("setLayer:"), _metalLayer);
    auto contentView = send(_window, sel_registerName("contentView"));
    send(contentView, sel_registerName("setWantsLayer:"), YES);
    send(contentView, sel_registerName("setLayer:"), _metalLayer);
    }


    };

    int main() {
    Window win{};
    return win.run();
    return Window{}.run();
    }
  7. xenobrain revised this gist Jun 27, 2023. 1 changed file with 10 additions and 7 deletions.
    17 changes: 10 additions & 7 deletions main.cpp
    Original file line number Diff line number Diff line change
    @@ -28,10 +28,10 @@ class Window {
    send<void>(_window, sel_registerName("makeKeyAndOrderFront:"), nil);
    send<void>(application, sel_registerName("activateIgnoringOtherApps:"), YES);

    send<void>(send<id>(objc_getClass("NSApplication"), sel_registerName("sharedApplication")), sel_registerName("run"));

    createMetalLayer();

    send<void>(send<id>(objc_getClass("NSApplication"), sel_registerName("sharedApplication")), sel_registerName("run"));

    objc_disposeClassPair(windowDelegate);
    return 0;
    }
    @@ -48,15 +48,18 @@ class Window {
    void createMetalLayer() {
    _metalLayer = send<id>(objc_getClass("CAMetalLayer"), sel_registerName("new"));
    send<void>(_metalLayer, sel_registerName("setDevice:"), send<id>(objc_getClass("MTLCreateSystemDefaultDevice"), sel_registerName("new")));

    send<void>(_metalLayer, sel_registerName("setPixelFormat:"), 70); // MTLPixelFormatBGRA8Unorm
    send<void>(_metalLayer, sel_registerName("setFrame:"), send<CGRect>(_window, sel_registerName("frame")));
    send<void>(_window, sel_registerName("contentView"), sel_registerName("setLayer:"), _metalLayer);
    send<void>(_window, sel_registerName("contentView"), sel_registerName("setWantsLayer:"), YES);
    send<void>(_metalLayer, sel_registerName("setFrame:"), CGRectMake(0, 0, 800, 600));

    auto contentView = send<id>(_window, sel_registerName("contentView"));
    send<void>(contentView, sel_registerName("setWantsLayer:"), YES);
    send<void>(contentView, sel_registerName("setLayer:"), _metalLayer);
    }


    };

    int main() {
    Window win{};
    return win.run();
    }
    }
  8. xenobrain created this gist Jun 27, 2023.
    62 changes: 62 additions & 0 deletions main.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,62 @@
    #include <objc/runtime.h>
    #include <objc/message.h>
    #include <CoreGraphics/CoreGraphics.h>

    template <typename Return, typename... Args> auto send(id obj, SEL selector, Args... args) {
    return reinterpret_cast<Return (*)(id, SEL, Args...)>(objc_msgSend)(obj, selector, args...);
    }

    template <typename Return, typename... Args> auto send(Class cls, SEL selector, Args... args) {
    return reinterpret_cast<Return (*)(id, SEL, Args...)>(objc_msgSend)(reinterpret_cast<id>(cls), selector, args...);
    }

    class Window {
    public:
    int run() {
    auto application = send<id>(objc_getClass("NSApplication"), sel_registerName("sharedApplication"));
    send<void>(application, sel_registerName("setActivationPolicy:"), 0);

    auto windowDelegate = objc_allocateClassPair(objc_getClass("NSObject"), "WindowDelegate", 0);
    class_addMethod(windowDelegate, sel_registerName("windowWillClose:"), reinterpret_cast<IMP>(windowWillClose), "v@:@");
    objc_registerClassPair(windowDelegate);

    _window = send<id>(objc_getClass("NSWindow"), sel_registerName("alloc"));
    send<void>(_window, sel_registerName("initWithContentRect:styleMask:backing:defer:"), CGRectMake(0, 0, 800, 600), 15, 2, NO);
    send<void>(_window, sel_registerName("setTitle:"), send<id>(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "Cocoa window"));
    send<void>(_window, sel_registerName("center"));
    send<void>(_window, sel_registerName("setDelegate:"), send<id>(windowDelegate, sel_registerName("new")));
    send<void>(_window, sel_registerName("makeKeyAndOrderFront:"), nil);
    send<void>(application, sel_registerName("activateIgnoringOtherApps:"), YES);

    send<void>(send<id>(objc_getClass("NSApplication"), sel_registerName("sharedApplication")), sel_registerName("run"));

    createMetalLayer();

    objc_disposeClassPair(windowDelegate);
    return 0;
    }

    private:
    id _window;
    id _metalLayer;

    static void windowWillClose(id self, SEL _cmd, id sender) {
    send<void>(send<id>(objc_getClass("NSApplication"), sel_registerName("sharedApplication")),
    sel_registerName("terminate:"), nil);
    }

    void createMetalLayer() {
    _metalLayer = send<id>(objc_getClass("CAMetalLayer"), sel_registerName("new"));
    send<void>(_metalLayer, sel_registerName("setDevice:"), send<id>(objc_getClass("MTLCreateSystemDefaultDevice"), sel_registerName("new")));

    send<void>(_metalLayer, sel_registerName("setPixelFormat:"), 70); // MTLPixelFormatBGRA8Unorm
    send<void>(_metalLayer, sel_registerName("setFrame:"), send<CGRect>(_window, sel_registerName("frame")));
    send<void>(_window, sel_registerName("contentView"), sel_registerName("setLayer:"), _metalLayer);
    send<void>(_window, sel_registerName("contentView"), sel_registerName("setWantsLayer:"), YES);
    }
    };

    int main() {
    Window win{};
    return win.run();
    }