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/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();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment