From d29e1b8710ffe259ad7b532fb76056c52e2061ae Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Wed, 5 Mar 2014 20:09:15 -0500 Subject: [PATCH] Have ui.Go() return on main() return on Mac OS X. --- bleh_darwin.m | 29 +++++++++++++++++++++++++++++ objc_darwin.h | 4 ++++ uitask_darwin.go | 17 ++++++++++++++++- 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/bleh_darwin.m b/bleh_darwin.m index ca9c91a..08b02bb 100644 --- a/bleh_darwin.m +++ b/bleh_darwin.m @@ -7,6 +7,7 @@ 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 - wrong documentation +though this is not always the case. Go wrapper functions (bleh_darwin.go) call these directly and take care of stdint.h -> Go type conversions. */ @@ -17,6 +18,7 @@ Go wrapper functions (bleh_darwin.go) call these directly and take care of stdin #include #include +#include /* exception to the above: cgo doesn't like Nil and delegate_darwin.go has //export so I can't have this there */ Class NilClass = Nil; @@ -155,3 +157,30 @@ uintptr_t *NSIndexSetEntries(id indexset, uintptr_t count) free(nsuints); return ret; } + +/* +See uitask_darwin.go: we need to synthesize a NSEvent so -[NSApplication stop:] will work. We cannot simply init the default NSEvent though (it throws an exception) so we must do it "the right way". This involves a very convoluted initializer; we'll just do it here to keep things clean on the Go side (this will only be run once anyway, on program exit). +*/ + +static id c_NSEvent; +static SEL s_newEvent; +static BOOL newEvent_init = NO; + +id makeDummyEvent() +{ + if (newEvent_init == NO) { + c_NSEvent = objc_getClass("NSEvent"); + s_newEvent = sel_getUid("otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:"); + newEvent_init = YES; + } + return objc_msgSend(c_NSEvent, s_newEvent, + (NSUInteger) NSApplicationDefined, /* otherEventWithType: */ + NSMakePoint(0, 0), /* location: */ + (NSUInteger) 0, /* modifierFlags: */ + (double) 0, /* timestamp: */ + (NSInteger) 0, /* windowNumber: */ + nil, /* context: */ + (short) 0, /* subtype: */ + (NSInteger) 0, /* data1: */ + (NSInteger) 0); /* data2: */ +} diff --git a/objc_darwin.h b/objc_darwin.h index e2d9d92..f73bc2b 100644 --- a/objc_darwin.h +++ b/objc_darwin.h @@ -89,6 +89,7 @@ m2(id_id, id, id) extern id _objc_msgSend_rect_bool(id obj, SEL sel, int64_t x, int64_t y, int64_t w, int64_t h, BOOL b); extern id objc_msgSend_id_int(id obj, SEL sel, id a, intptr_t b); extern id objc_msgSend_id_uint(id obj, SEL sel, id a, uintptr_t b); +m2(id_bool, id, BOOL) m3(id_id_id, id, id, id) m3(sel_id_bool, SEL, id, BOOL) @@ -100,4 +101,7 @@ m4(id_id_id_id, id, id, id, id) /* for listbox_darwin.go */ extern uintptr_t *NSIndexSetEntries(id, uintptr_t); +/* for uitask_darwin.go */ +extern id makeDummyEvent(); + #endif diff --git a/uitask_darwin.go b/uitask_darwin.go index 8a77dfa..6acf080 100644 --- a/uitask_darwin.go +++ b/uitask_darwin.go @@ -20,6 +20,8 @@ var ( _valueWithPointer = sel_getUid("valueWithPointer:") _performSelectorOnMainThread = sel_getUid("performSelectorOnMainThread:withObject:waitUntilDone:") + _stop = sel_getUid("stop:") + _postEventAtStart = sel_getUid("postEvent:atStart:") _pointerValue = sel_getUid("pointerValue") _run = sel_getUid("run") ) @@ -51,7 +53,20 @@ func ui(main func()) error { } }() - go main() + go func() { + main() + uitask <- func() { + // -[NSApplication stop:] stops the event loop; it won't do a clean termination, but we're not too concerned with that (at least not on the other platforms either so) + // we can't call -[NSApplication terminate:] because that will just quit the program, ensuring we never leave ui.Go() + C.objc_msgSend_id(NSApp, _stop, NSApp) + // simply calling -[NSApplication stop:] is not good enough, as the stop flag is only checked when an event comes in + // we have to create a "proper" event; a blank event will just throw an exception + C.objc_msgSend_id_bool(NSApp, + _postEventAtStart, + C.makeDummyEvent(), + C.BOOL(C.NO)) // not at start, just in case there are other events pending (TODO is this correct?) + } + }() C.objc_msgSend_noargs(NSApp, _run) return nil