2014-02-28 22:01:48 -06:00
// 28 february 2014
package ui
import (
2014-03-01 19:31:17 -06:00
"fmt"
2014-02-28 22:01:48 -06:00
"runtime"
"unsafe"
)
// #cgo LDFLAGS: -lobjc -framework Foundation -framework AppKit
// #include "objc_darwin.h"
import "C"
2014-03-01 13:05:14 -06:00
// temporary for now
func msgBox ( string , string ) { }
func msgBoxError ( string , string ) { }
2014-02-28 22:01:48 -06:00
var uitask chan func ( )
var (
_NSAutoreleasePool = objc_getClass ( "NSAutoreleasePool" )
_NSValue = objc_getClass ( "NSValue" )
_valueWithPointer = sel_getUid ( "valueWithPointer:" )
_performSelectorOnMainThread =
sel_getUid ( "performSelectorOnMainThread:withObject:waitUntilDone:" )
_pointerValue = sel_getUid ( "pointerValue" )
2014-03-01 14:18:29 -06:00
_run = sel_getUid ( "run" )
2014-02-28 22:01:48 -06:00
)
2014-03-01 14:18:29 -06:00
func ui ( main func ( ) ) error {
2014-02-28 22:01:48 -06:00
runtime . LockOSThread ( )
uitask = make ( chan func ( ) )
2014-03-01 14:18:29 -06:00
2014-03-01 15:56:22 -06:00
NSApp , err := initCocoa ( )
2014-03-01 14:18:29 -06:00
if err != nil {
return err
2014-02-28 22:01:48 -06:00
}
2014-03-01 14:18:29 -06:00
// 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
2014-02-28 22:01:48 -06:00
}
2014-03-01 14:18:29 -06:00
// TODO move to init_darwin.go?
2014-02-28 22:01:48 -06:00
var (
_NSApplication = objc_getClass ( "NSApplication" )
_sharedApplication = sel_getUid ( "sharedApplication" )
2014-03-01 19:31:17 -06:00
_setActivationPolicy = sel_getUid ( "setActivationPolicy:" )
2014-02-28 22:01:48 -06:00
)
2014-03-01 15:56:22 -06:00
func initCocoa ( ) ( NSApp C . id , err error ) {
2014-03-01 14:18:29 -06:00
NSApp = C . objc_msgSend_noargs ( _NSApplication , _sharedApplication )
2014-03-01 19:31:17 -06:00
r := C . objc_msgSend_int ( NSApp , _setActivationPolicy ,
0 ) // NSApplicationActivationPolicyRegular
if C . BOOL ( uintptr ( unsafe . Pointer ( r ) ) ) != C . BOOL ( C . YES ) {
err = fmt . Errorf ( "error setting NSApplication activation policy (basically identifies our program as a separate program; needed for several things, such as Dock icon, menu, window resizing, etc.) (unknown reason)" )
return
}
2014-03-01 15:56:22 -06:00
err = mkAppDelegate ( )
2014-03-01 14:18:29 -06:00
return
2014-02-28 22:01:48 -06:00
}
//export appDelegate_uitask
func appDelegate_uitask ( self C . id , sel C . SEL , arg C . id ) {
p := C . objc_msgSend_noargs ( arg , _pointerValue )
f := ( * func ( ) ) ( unsafe . Pointer ( p ) )
( * f ) ( )
}