diff --git a/darwintest/bleh_darwin.go b/darwintest/bleh_darwin.go new file mode 100644 index 0000000..79fe4d3 --- /dev/null +++ b/darwintest/bleh_darwin.go @@ -0,0 +1,27 @@ +// 28 february 2014 +package main + +/* +These are wrapper functions for the functions in bleh_darwin.m to wrap around stdint.h type casting. + +This will eventually be expanded to include the other Objective-C runtime support functions. +*/ + +// #cgo LDFLAGS: -lobjc -framework Foundation +// #include "objc_darwin.h" +import "C" + +func objc_msgSend_rect(obj C.id, sel C.SEL, x int, y int, w int, h int) C.id { + return C._objc_msgSend_rect(obj, sel, + C.int64_t(x), C.int64_t(y), C.int64_t(w), C.int64_t(h)) +} + +func objc_msgSend_uint(obj C.id, sel C.SEL, a uintptr) C.id { + return C._objc_msgSend_uint(obj, sel, C.uintptr_t(a)) +} + +func objc_msgSend_rect_uint_uint_bool(obj C.id, sel C.SEL, x int, y int, w int, h int, b uintptr, c uintptr, d C.BOOL) C.id { + return C._objc_msgSend_rect_uint_uint_bool(obj, sel, + C.int64_t(x), C.int64_t(y), C.int64_t(w), C.int64_t(h), + C.uintptr_t(b), C.uintptr_t(c), d) +} diff --git a/darwintest/bleh_darwin.m b/darwintest/bleh_darwin.m new file mode 100644 index 0000000..5ed2155 --- /dev/null +++ b/darwintest/bleh_darwin.m @@ -0,0 +1,46 @@ +/* 28 february 2014 */ + +/* +I wanted to avoid invoking Objective-C directly, preferring to do everything directly with the API. However, there are some things that simply cannot be done too well; for those situations, there's this. It does use the Objective-C runtime, eschewing the actual Objective-C part of this being an Objective-C file. + +The main culprits are: +- data types listed as being defined in nonexistent headers +- 32-bit/64-bit type differences that are more than just a different typedef + +Go wrapper functions (bleh_darwin.go) call these directly and take care of stdint.h -> Go type conversions. +*/ + +#include +#include +#include + +#include + +#include + +/* +NSUInteger is listed as being in ... which doesn't exist. Rather than relying on undocumented behavior or explicitly typedef-ing NSUInteger to the (documented) unsigned long, I'll just place things here for maximum safety. I use uintptr_t as that should encompass every possible unsigned long. +*/ + +id _objc_msgSend_uint(id obj, SEL sel, uintptr_t a) +{ + return objc_msgSend(obj, sel, (NSUInteger) a); +} + +/* +These are the objc_msgSend() wrappers around NSRect. The problem is that while on 32-bit systems, NSRect is a concrete structure, on 64-bit systems it's just a typedef to CGRect. While in practice just using CGRect everywhere seems to work, better to be safe than sorry. + +I use int64_t for maximum safety, as my coordinates are stored as Go ints and Go int -> C int (which is what is documented as happening) isn't reliable. +*/ + +#define OurRect() (NSMakeRect((CGFloat) x, (CGFloat) y, (CGFloat) w, (CGFloat) h)) + +id _objc_msgSend_rect(id obj, SEL sel, int64_t x, int64_t y, int64_t w, int64_t h) +{ + return objc_msgSend(obj, sel, OurRect()); +} + +id _objc_msgSend_rect_uint_uint_bool(id obj, SEL sel, int64_t x, int64_t y, int64_t w, int64_t h, uintptr_t b, uintptr_t c, BOOL d) +{ + return objc_msgSend(obj, sel, OurRect(), (NSUInteger) b, (NSUInteger) c, d); +} diff --git a/darwintest/objc_darwin.h b/darwintest/objc_darwin.h index 85bf0b4..abf9712 100644 --- a/darwintest/objc_darwin.h +++ b/darwintest/objc_darwin.h @@ -14,6 +14,8 @@ The format should be self-explanatory. #include #include +#include + /* TODO this HAS to be unsafe, but not found?! */ typedef unsigned long NSUInteger; @@ -48,14 +50,14 @@ inline id objc_msgSend_noargs(id obj, SEL sel) m1(str, char *) /* TODO Go string? */ m1(id, id) -/* TODO NSRect */ +extern id _objc_msgSend_rect(id obj, SEL sel, int64_t x, int64_t y, int64_t w, int64_t h); m1(sel, SEL) -m1(uint, NSUInteger) +extern id _objc_msgSend_uint(id obj, SEL sel, uintptr_t a); m2(id_id, id, id) m3(id_id_id, id, id, id) m3(sel_id_bool, SEL, id, BOOL) -/* TODO NSRect */ +extern id _objc_msgSend_rect_uint_uint_bool(id obj, SEL sel, int64_t x, int64_t y, int64_t w, int64_t h, uintptr_t b, uintptr_t c, BOOL d); m4(id_sel_id_id, id, SEL, id, id) diff --git a/darwintest/runtimetest.go b/darwintest/runtimetest.go index f92e0f8..46933a4 100644 --- a/darwintest/runtimetest.go +++ b/darwintest/runtimetest.go @@ -10,11 +10,6 @@ import ( // #cgo LDFLAGS: -lobjc -framework Foundation -framework AppKit // #include // #include "objc_darwin.h" -// /* avoid depending on Objective-C */ -// #include -// /* cgo doesn't handle ... */ -// id objc_msgSend_NSRect_uint_uint_bool(id obj, SEL sel, CGRect a, NSUInteger b, NSUInteger c, BOOL d) { return objc_msgSend(obj, sel, a, b, c, d); } -// id objc_msgSend_NSRect(id obj, SEL sel, CGRect a) { return objc_msgSend(obj, sel, a); } // Class NilClass = Nil; /* for newtypes.go */ // id Nilid = nil; import "C" @@ -97,7 +92,7 @@ func notify(source string) { sel_getUid("performSelectorOnMainThread:withObject:waitUntilDone:"), notesel, src, - C.BOOL(C.TRUE)) // wait so we can properly drain the autorelease pool; on other platforms we wind up waiting anyway (since the main thread can only handle one thing at a time) so + C.BOOL(C.YES)) // wait so we can properly drain the autorelease pool; on other platforms we wind up waiting anyway (since the main thread can only handle one thing at a time) so C.objc_msgSend_noargs(pool, sel_getUid("release")) } @@ -109,15 +104,13 @@ func main() { setDelegate := sel_getUid("setDelegate:") makeKeyAndOrderFront := sel_getUid("makeKeyAndOrderFront:") - rect := C.CGRect{ - origin: C.CGPoint{100, 100}, - size: C.CGSize{320, 240}, - } - style := C.NSUInteger(NSTitledWindowMask | NSClosableWindowMask) - backing := C.NSUInteger(NSBackingStoreBuffered) + style := uintptr(NSTitledWindowMask | NSClosableWindowMask) + backing := uintptr(NSBackingStoreBuffered) deferx := C.BOOL(C.YES) window := C.objc_msgSend_noargs(NSWindow, alloc) - window = C.objc_msgSend_NSRect_uint_uint_bool(window, NSWindowinit, rect, style, backing, deferx) + window = objc_msgSend_rect_uint_uint_bool(window, NSWindowinit, + 100, 100, 320, 240, + style, backing, deferx) C.objc_msgSend_id(window, makeKeyAndOrderFront, window) C.objc_msgSend_id(window, setDelegate, delegate) @@ -126,21 +119,18 @@ func main() { NSButton := objc_getClass("NSButton") button := C.objc_msgSend_noargs(NSButton, alloc) - button = C.objc_msgSend_NSRect(button, + button = objc_msgSend_rect(button, sel_getUid("initWithFrame:"), - C.CGRect{ - origin: C.CGPoint{20, 20}, - size: C.CGSize{200, 200}, - }) + 20, 20, 200, 200) C.objc_msgSend_id(button, sel_getUid("setTarget:"), delegate) C.objc_msgSend_sel(button, sel_getUid("setAction:"), sel_getUid("buttonClicked:")) - C.objc_msgSend_uint(button, + objc_msgSend_uint(button, sel_getUid("setBezelStyle:"), - C.NSUInteger(NSRoundedBezelStyle)) + NSRoundedBezelStyle) C.objc_msgSend_id(windowView, sel_getUid("addSubview:"), button)