Skip to content

Instantly share code, notes, and snippets.

@xenobrain
Last active June 28, 2023 14:07
Show Gist options
  • Save xenobrain/00e27d2ef03b9cce274f7e3b9a5dee2f to your computer and use it in GitHub Desktop.
Save xenobrain/00e27d2ef03b9cce274f7e3b9a5dee2f to your computer and use it in GitHub Desktop.
Cocoa Window with Metal layer in pure C++
#include <objc/objc-runtime.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...);
}
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);
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("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();
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);
}
objc_disposeClassPair(windowDelegate);
return 0;
}
private:
id _window;
id _metalLayer;
auto static windowWillClose(id self, SEL _cmd, id sender) -> void {
send(send("NSApplication", "sharedApplication"),"terminate:", nil);
running = false;
}
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, "contentView");
send(contentView, "setWantsLayer:", YES);
send(contentView, "setLayer:", _metalLayer);
}
};
auto main(int, char**) -> int {
return Window{}.run();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment