Added a notification system, hopefully allowing us to merge AppKit requests onto a single thread. In practice, this generates autorelease pool leak messages; it appears notifications are not for this...

This commit is contained in:
Pietro Gagliardi 2014-02-28 15:08:07 -05:00
parent 3b9e26ab38
commit 6982912a58
2 changed files with 85 additions and 7 deletions

View File

@ -15,8 +15,12 @@ import (
// extern void windowShouldClose(id, SEL, id);
// extern id objc_msgSend_id(id, SEL, id);
// extern void buttonClicked(id, SEL, id);
// /* cgo doesn't like Nil */
// extern void gotNotification(id, SEL, id);
// extern id objc_msgSend_id_id_id(id, SEL, id, id, id);
// /* cgo doesn't like nil or Nil */
// extern id objc_msgSend_noargs(id, SEL);
// extern Class NilClass; /* in runtimetest.go because of cgo limitations */
// extern id Nilid;
import "C"
var NSObject = C.object_getClass(objc_getClass("NSObject"))
@ -42,7 +46,22 @@ func windowShouldClose(self C.id, sel C.SEL, sender C.id) {
//export buttonClicked
func buttonClicked(self C.id, sel C.SEL, sender C.id) {
fmt.Println("button clicked")
fmt.Println("button clicked; sending notification...")
notify("button")
}
//export gotNotification
func gotNotification(self C.id, sel C.SEL, note C.id) {
data := C.objc_msgSend_noargs(note,
sel_getUid("userInfo"))
val := C.objc_msgSend_id(data,
sel_getUid("objectForKey:"),
notekey)
source := (*C.char)(unsafe.Pointer(
C.objc_msgSend_noargs(val,
sel_getUid("UTF8String"))))
fmt.Println("got notification from %s",
C.GoString(source))
}
func addOurMethod(class C.Class, sel C.SEL, imp C.IMP) {
@ -61,7 +80,7 @@ func addOurMethod(class C.Class, sel C.SEL, imp C.IMP) {
}
}
func mk(name string, selW C.SEL, selB C.SEL) C.id {
func mk(name string, selW C.SEL, selB C.SEL, selN C.SEL) C.id {
class := newClass(name)
addOurMethod(class, selW,
// using &C.ourMethod causes faults for some reason
@ -69,5 +88,7 @@ func mk(name string, selW C.SEL, selB C.SEL) C.id {
C.objc_registerClassPair(class)
addOurMethod(class, selB,
C.IMP(unsafe.Pointer(C.buttonClicked)))
addOurMethod(class, selN,
C.IMP(unsafe.Pointer(C.gotNotification)))
return objc_getClass(name)
}

View File

@ -4,6 +4,7 @@ package main
import (
"fmt"
"unsafe"
"time"
)
// #cgo LDFLAGS: -lobjc -framework Foundation -framework AppKit
@ -24,7 +25,11 @@ import (
// id objc_msgSend_NSRect(id obj, SEL sel, CGRect a) { return objc_msgSend(obj, sel, a); }
// id objc_msgSend_sel(id obj, SEL sel, SEL a) { return objc_msgSend(obj, sel, a); }
// id objc_msgSend_uint(id obj, SEL sel, NSUInteger a) { return objc_msgSend(obj, sel, a); }
// id objc_msgSend_id_sel_id_id(id obj, SEL sel, id a, SEL b, id c, id d) { return objc_msgSend(obj, sel, a, b, c, d); }
// id objc_msgSend_id_id_id(id obj, SEL sel, id a, id b, id c) { return objc_msgSend(obj, sel, a, b, c); }
// id objc_msgSend_id_id(id obj, SEL sel, id a, id b) { return objc_msgSend(obj, sel, a, b); }
// Class NilClass = Nil; /* for newtypes.go */
// id Nilid = nil;
import "C"
func objc_getClass(class string) C.id {
@ -42,6 +47,10 @@ func sel_getUid(sel string) C.SEL {
}
var NSApp C.id
var defNC C.id
var delegate C.id
var note C.id
var notekey C.id
func init() {
// need an NSApplication first - see https://github.com/TooTallNate/NodObjC/issues/21
@ -49,9 +58,31 @@ func init() {
sharedApplication := sel_getUid("sharedApplication")
NSApp = C.objc_msgSend_noargs(NSApplication, sharedApplication)
defNC = C.objc_msgSend_noargs(
objc_getClass("NSNotificationCenter"),
sel_getUid("defaultCenter"))
selW := sel_getUid("windowShouldClose:")
selB := sel_getUid("buttonClicked:")
mk("hello", selW, selB)
selN := sel_getUid("gotNotification:")
mk("hello", selW, selB, selN)
delegate = C.objc_msgSend_noargs(
objc_getClass("hello"),
alloc)
noteStr := []C.char{'g', 'o', 'n', 'o', 't', 'e', 0}
note = C.objc_msgSend_strarg(
objc_getClass("NSString"),
sel_getUid("stringWithUTF8String:"),
&noteStr[0])
notekey = note
C.objc_msgSend_id_sel_id_id(
defNC,
sel_getUid("addObserver:selector:name:object:"),
delegate,
selN,
note,
C.Nilid)
}
const (
@ -75,6 +106,27 @@ const (
var alloc = sel_getUid("alloc")
func notify(source string) {
csource := C.CString(source)
defer C.free(unsafe.Pointer(csource))
src := C.objc_msgSend_strarg(
objc_getClass("NSString"),
sel_getUid("stringWithUTF8String:"),
csource)
dict := C.objc_msgSend_id_id(
objc_getClass("NSDictionary"),
sel_getUid("dictionaryWithObject:forKey:"),
src,
notekey)
C.objc_msgSend_id_id_id(
defNC,
sel_getUid("postNotificationName:object:userInfo:"),
note,
C.Nilid,
dict)
}
func main() {
NSWindow := objc_getClass("NSWindow")
NSWindowinit :=
@ -92,9 +144,6 @@ func main() {
window := C.objc_msgSend_noargs(NSWindow, alloc)
window = C.objc_msgSend_NSRect_uint_uint_bool(window, NSWindowinit, rect, style, backing, deferx)
C.objc_msgSend_id(window, makeKeyAndOrderFront, window)
delegate := C.objc_msgSend_noargs(
objc_getClass("hello"),
alloc)
C.objc_msgSend_id(window, setDelegate,
delegate)
windowView := C.objc_msgSend_noargs(window,
@ -121,6 +170,14 @@ func main() {
sel_getUid("addSubview:"),
button)
go func() {
for {
<-time.After(5 * time.Second)
fmt.Println("five seconds passed; sending notification...")
notify("timer")
}
}()
C.objc_msgSend_noargs(NSApp,
sel_getUid("run"))
}