diff options
Diffstat (limited to 'uitask_darwin.go')
| -rw-r--r-- | uitask_darwin.go | 84 |
1 files changed, 35 insertions, 49 deletions
diff --git a/uitask_darwin.go b/uitask_darwin.go index 3a6d633..2fb6b45 100644 --- a/uitask_darwin.go +++ b/uitask_darwin.go @@ -17,7 +17,6 @@ We will create an Objective-C class goAppDelegate. It contains two methods: // #cgo LDFLAGS: -lobjc -framework Foundation -framework AppKit // #include "objc_darwin.h" -// extern void appDelegate_applicationDidFinishLaunching(id, SEL, id); // extern void appDelegate_uitask(id, SEL, id); import "C" @@ -27,8 +26,6 @@ func msgBoxError(string, string){} var uitask chan func() -var mtret chan interface{} - var ( _NSAutoreleasePool = objc_getClass("NSAutoreleasePool") _NSValue = objc_getClass("NSValue") @@ -38,36 +35,44 @@ var ( _performSelectorOnMainThread = sel_getUid("performSelectorOnMainThread:withObject:waitUntilDone:") _pointerValue = sel_getUid("pointerValue") + _run = sel_getUid("run") ) -func ui(initDone chan error) { +func ui(main func()) error { runtime.LockOSThread() uitask = make(chan func()) - mtret = make(chan interface{}) - go mainThread() - v := <-mtret - if err, ok := v.(error); ok { - initDone <- fmt.Errorf("error initializing Cocoa: %v", err) - return - } - appDelegate := v.(C.id) - for f := range uitask { - // we need to make an NSAutoreleasePool, otherwise we get leak warnings on stderr - pool := objc_new(_NSAutoreleasePool) - fp := C.objc_msgSend_ptr(_NSValue, _valueWithPointer, - unsafe.Pointer(&f)) - C.objc_msgSend_sel_id_bool( - appDelegate, - _performSelectorOnMainThread, - _uitask, - fp, - 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 - objc_release(pool) + NSApp, appDelegate, err := initCocoa() + if err != nil { + return err } + + // Cocoa must run on the first thread created by the program, so we run our dispatcher on another thread instead + go func() { + for f := range uitask { + // we need to make an NSAutoreleasePool, otherwise we get leak warnings on stderr + pool := objc_new(_NSAutoreleasePool) + fp := C.objc_msgSend_ptr(_NSValue, _valueWithPointer, + unsafe.Pointer(&f)) + C.objc_msgSend_sel_id_bool( + appDelegate, + _performSelectorOnMainThread, + _uitask, + fp, + 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 + objc_release(pool) + } + }() + + go main() + + C.objc_msgSend_noargs(NSApp, _run) + return nil } +// TODO move to init_darwin.go? + const ( _goAppDelegate = "goAppDelegate" ) @@ -76,41 +81,22 @@ var ( _NSApplication = objc_getClass("NSApplication") _sharedApplication = sel_getUid("sharedApplication") - _applicationDidFinishLaunching = sel_getUid("applicationDidFinishLaunching:") - _run = sel_getUid("run") ) -func mainThread() { - runtime.LockOSThread() +func initCocoa() (NSApp C.id, appDelegate C.id, err error) { + var appdelegateclass C.Class - _NSApp := C.objc_msgSend_noargs(_NSApplication, _sharedApplication) - appdelegateclass, err := makeDelegateClass(_goAppDelegate) - if err != nil { - mtret <- fmt.Errorf("error creating NSApplication delegate: %v", err) - return - } - err = addDelegateMethod(appdelegateclass, _applicationDidFinishLaunching, - C.appDelegate_applicationDidFinishLaunching) - if err != nil { - mtret <- fmt.Errorf("error adding NSApplication delegate applicationDidFinishLaunching: method (to start UI loop): %v", err) - return - } + NSApp = C.objc_msgSend_noargs(_NSApplication, _sharedApplication) err = addDelegateMethod(appdelegateclass, _uitask, C.appDelegate_uitask) if err != nil { - mtret <- fmt.Errorf("error adding NSApplication delegate uitask: method (to do UI tasks): %v", err) + err = fmt.Errorf("error adding NSApplication delegate uitask: method (to do UI tasks): %v", err) return } // TODO using objc_new() causes a segfault; find out why // TODO make alloc followed by init (I thought NSObject provided its own init?) - appDelegate := objc_alloc(objc_getClass(_goAppDelegate)) - objc_setDelegate(_NSApp, appDelegate) - // and that's it, really - C.objc_msgSend_noargs(_NSApp, _run) -} + appDelegate = objc_alloc(objc_getClass(_goAppDelegate)) -//export appDelegate_applicationDidFinishLaunching -func appDelegate_applicationDidFinishLaunching(self C.id, sel C.SEL, arg C.id) { - mtret <- self + return } //export appDelegate_uitask |
