Started to build a single global delegate object; now to fix issues.
This commit is contained in:
parent
0b4e1ff246
commit
9b4e30ccf9
|
@ -0,0 +1,100 @@
|
||||||
|
// 27 february 2014
|
||||||
|
package ui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
This creates a class goAppDelegate that will be used as the delegate for /everything/. Specifically, it:
|
||||||
|
- runs uitask requests (uitask:)
|
||||||
|
- handles window close events (windowShouldClose:)
|
||||||
|
- handles window resize events (xxxx:)
|
||||||
|
- handles button click events (buttonClick:)
|
||||||
|
*/
|
||||||
|
|
||||||
|
// #cgo LDFLAGS: -lobjc -framework Foundation -framework AppKit
|
||||||
|
// #include <stdlib.h>
|
||||||
|
// #include "objc_darwin.h"
|
||||||
|
// extern void appDelegate_uitask(id, SEL, id); /* from uitask_darwin.go */
|
||||||
|
// extern BOOL appDelegate_windowShouldClose(id, SEL, id);
|
||||||
|
// /* because cgo doesn't like Nil */
|
||||||
|
// static Class NilClass = Nil;
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
var (
|
||||||
|
appDelegate C.id
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
_goAppDelegate = "goAppDelegate"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_uitask = sel_getUid("uitask:")
|
||||||
|
_windowShouldClose = sel_getUid("windowShouldClose:")
|
||||||
|
)
|
||||||
|
|
||||||
|
func mkAppDelegate() error {
|
||||||
|
var appdelegateclass C.Class
|
||||||
|
|
||||||
|
appdelegateclass, err = makeDelegateClass(_goAppDelegate)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error creating NSApplication delegate: %v", err)
|
||||||
|
}
|
||||||
|
err = addDelegateMethod(appdelegateclass, _uitask,
|
||||||
|
C.appDelegate_uitask, delegate_void)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error adding NSApplication delegate uitask: method (to do UI tasks): %v", err)
|
||||||
|
}
|
||||||
|
err = addDelegateMethod(appdelegateclass, _windowShouldClose,
|
||||||
|
C.appDelegate_windowShouldClose, delegate_bool)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error adding NSApplication delegate windowShouldClose: method (to handle window close button events): %v", err)
|
||||||
|
}
|
||||||
|
// 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))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//export appDelegate_windowShouldClose
|
||||||
|
func appDelegate_windowShouldClose(self C.id, sel C.SEL, win C.id) C.BOOL {
|
||||||
|
sysData := getSysData(win)
|
||||||
|
sysData.signal()
|
||||||
|
return C.BOOL(C.NO) // don't close
|
||||||
|
}
|
||||||
|
|
||||||
|
// this actually constructs the delegate class
|
||||||
|
|
||||||
|
var (
|
||||||
|
_NSObject_Class = C.object_getClass(_NSObject)
|
||||||
|
)
|
||||||
|
|
||||||
|
func makeDelegateClass(name string) (C.Class, error) {
|
||||||
|
cname := C.CString(name)
|
||||||
|
defer C.free(unsafe.Pointer(cname))
|
||||||
|
|
||||||
|
c := C.objc_allocateClassPair(_NSObject_Class, cname, 0)
|
||||||
|
if c == C.NilClass {
|
||||||
|
return C.NilClass, fmt.Errorf("unable to create Objective-C class %s; reason unknown", name)
|
||||||
|
}
|
||||||
|
C.objc_registerClassPair(c)
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
delegate_void = []C.char{'v', '@', ':', '@', 0} // void (*)(id, SEL, id)
|
||||||
|
delegate_bool = []C.char{'#', '@', ':', '@', 0} // BOOL (*)(id, SEL, id)
|
||||||
|
)
|
||||||
|
|
||||||
|
// according to errors spit out by cgo, C function pointers are unsafe.Pointer
|
||||||
|
func addDelegateMethod(class C.Class, sel C.SEL, imp unsafe.Pointer, ty []C.char) error {
|
||||||
|
ok := C.class_addMethod(class, sel, C.IMP(imp), &ty[0])
|
||||||
|
if ok == C.BOOL(C.NO) {
|
||||||
|
// TODO get function name
|
||||||
|
return fmt.Errorf("unable to add selector %v/imp %v (reason unknown)", sel, imp)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,49 +0,0 @@
|
||||||
// 27 february 2014
|
|
||||||
package ui
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// #cgo LDFLAGS: -lobjc -framework Foundation
|
|
||||||
// #include <stdlib.h>
|
|
||||||
// #include "objc_darwin.h"
|
|
||||||
// /* because cgo doesn't like Nil */
|
|
||||||
// Class NilClass = Nil;
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
var (
|
|
||||||
_NSObject_Class = C.object_getClass(_NSObject)
|
|
||||||
)
|
|
||||||
|
|
||||||
func makeDelegateClass(name string) (C.Class, error) {
|
|
||||||
cname := C.CString(name)
|
|
||||||
defer C.free(unsafe.Pointer(cname))
|
|
||||||
|
|
||||||
c := C.objc_allocateClassPair(_NSObject_Class, cname, 0)
|
|
||||||
if c == C.NilClass {
|
|
||||||
return C.NilClass, fmt.Errorf("unable to create Objective-C class %s; reason unknown", name)
|
|
||||||
}
|
|
||||||
C.objc_registerClassPair(c)
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// according to errors spit out by cgo, C function pointers are unsafe.Pointer
|
|
||||||
func addDelegateMethod(class C.Class, sel C.SEL, imp unsafe.Pointer) error {
|
|
||||||
// maps to void (*)(id, SEL, id)
|
|
||||||
ty := []C.char{'v', '@', ':', '@', 0}
|
|
||||||
|
|
||||||
// clas methods get stored in the metaclass; the objc_allocateClassPair() docs say this will work
|
|
||||||
// metaclass := C.object_getClass(C.id(unsafe.Pointer(class)))
|
|
||||||
// we're adding instance methods, so just class will do
|
|
||||||
ok := C.class_addMethod(class,
|
|
||||||
sel,
|
|
||||||
C.IMP(imp),
|
|
||||||
&ty[0])
|
|
||||||
if ok == C.BOOL(C.NO) {
|
|
||||||
// TODO get function name
|
|
||||||
return fmt.Errorf("unable to add selector %v/imp %v (reason unknown)", sel, imp)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -7,17 +7,8 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
|
||||||
We will create an Objective-C class goAppDelegate. It contains two methods:
|
|
||||||
- (void)applicationDidFinishLoading:(NSNotification *)unused
|
|
||||||
will signal to ui() that we are now in the Cocoa event loop; we make our goAppDelegate instance the NSApplication delegate
|
|
||||||
- (void)uitask:(NSValue *)functionPointer
|
|
||||||
the function that actually performs our UI task functions; it is called with NSObject's performSelectorOnMainThread system
|
|
||||||
*/
|
|
||||||
|
|
||||||
// #cgo LDFLAGS: -lobjc -framework Foundation -framework AppKit
|
// #cgo LDFLAGS: -lobjc -framework Foundation -framework AppKit
|
||||||
// #include "objc_darwin.h"
|
// #include "objc_darwin.h"
|
||||||
// extern void appDelegate_uitask(id, SEL, id);
|
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
// temporary for now
|
// temporary for now
|
||||||
|
@ -30,7 +21,6 @@ var (
|
||||||
_NSAutoreleasePool = objc_getClass("NSAutoreleasePool")
|
_NSAutoreleasePool = objc_getClass("NSAutoreleasePool")
|
||||||
_NSValue = objc_getClass("NSValue")
|
_NSValue = objc_getClass("NSValue")
|
||||||
|
|
||||||
_uitask = sel_getUid("uitask:")
|
|
||||||
_valueWithPointer = sel_getUid("valueWithPointer:")
|
_valueWithPointer = sel_getUid("valueWithPointer:")
|
||||||
_performSelectorOnMainThread =
|
_performSelectorOnMainThread =
|
||||||
sel_getUid("performSelectorOnMainThread:withObject:waitUntilDone:")
|
sel_getUid("performSelectorOnMainThread:withObject:waitUntilDone:")
|
||||||
|
@ -43,7 +33,7 @@ func ui(main func()) error {
|
||||||
|
|
||||||
uitask = make(chan func())
|
uitask = make(chan func())
|
||||||
|
|
||||||
NSApp, appDelegate, err := initCocoa()
|
NSApp, err := initCocoa()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -73,34 +63,15 @@ func ui(main func()) error {
|
||||||
|
|
||||||
// TODO move to init_darwin.go?
|
// TODO move to init_darwin.go?
|
||||||
|
|
||||||
const (
|
|
||||||
_goAppDelegate = "goAppDelegate"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_NSApplication = objc_getClass("NSApplication")
|
_NSApplication = objc_getClass("NSApplication")
|
||||||
|
|
||||||
_sharedApplication = sel_getUid("sharedApplication")
|
_sharedApplication = sel_getUid("sharedApplication")
|
||||||
)
|
)
|
||||||
|
|
||||||
func initCocoa() (NSApp C.id, appDelegate C.id, err error) {
|
func initCocoa() (NSApp C.id, err error) {
|
||||||
var appdelegateclass C.Class
|
|
||||||
|
|
||||||
NSApp = C.objc_msgSend_noargs(_NSApplication, _sharedApplication)
|
NSApp = C.objc_msgSend_noargs(_NSApplication, _sharedApplication)
|
||||||
appdelegateclass, err = makeDelegateClass(_goAppDelegate)
|
err = mkAppDelegate()
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("error creating NSApplication delegate: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = addDelegateMethod(appdelegateclass, _uitask, C.appDelegate_uitask)
|
|
||||||
if err != nil {
|
|
||||||
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))
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue