summaryrefslogtreecommitdiff
path: root/uitask_darwin.go
diff options
context:
space:
mode:
Diffstat (limited to 'uitask_darwin.go')
-rw-r--r--uitask_darwin.go84
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