From dd20d56f257b001fe58783e86c113c11de58ca53 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Fri, 4 Apr 2014 21:06:01 -0400 Subject: [PATCH] Created a new, simpler, easier to work with, and consistent way to create the necessary Objective-C classes in our Go code, and converted the appDelegate class to use it. Now for goArea... --- delegate_darwin.go | 61 ++++++++++++---------------------------------- objc_darwin.go | 44 +++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 45 deletions(-) diff --git a/delegate_darwin.go b/delegate_darwin.go index 8fa8097..460e930 100644 --- a/delegate_darwin.go +++ b/delegate_darwin.go @@ -33,36 +33,26 @@ const ( ) var ( - _uitask = sel_getUid("uitask:") - _windowShouldClose = sel_getUid("windowShouldClose:") - _windowDidResize = sel_getUid("windowDidResize:") - _buttonClicked = sel_getUid("buttonClicked:") + _uitask = sel_getUid("uitask:") // used by uitask_darwin.go + _buttonClicked = sel_getUid("buttonClicked:") // used by sysdata_darwin.go ) +var appDelegateSels = []selector{ + selector{"uitask:", uintptr(C.appDelegate_uitask), sel_void_id, + "performing/dispatching UI events"}, + selector{"windowShouldClose:", uintptr(C.appDelegate_windowShouldClose), sel_bool_id, + "handling window close button events"}, + selector{"windowDidResize:", uintptr(C.appDelegate_windowDidResize), sel_void_id, + "handling window resize events"}, + selector{"buttonClicked:", uintptr(C.appDelegate_buttonClicked), sel_bool_id, + "handling button clicks"}, +} + func mkAppDelegate() error { - appdelegateclass, err := makeDelegateClass(_goAppDelegate) + err := makeClass(_goAppDelegate, _NSObject, appDelegateSels, + "application delegate (handles events)") 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) - } - err = addDelegateMethod(appdelegateclass, _windowDidResize, - C.appDelegate_windowDidResize, delegate_void) - if err != nil { - return fmt.Errorf("error adding NSApplication delegate windowDidResize: method (to handle window resize events): %v", err) - } - err = addDelegateMethod(appdelegateclass, _buttonClicked, - C.appDelegate_buttonClicked, delegate_void) - if err != nil { - return fmt.Errorf("error adding NSApplication delegate buttonClicked: method (to handle button clicks): %v", err) + return err } appDelegate = C.objc_msgSend_noargs(objc_getClass(_goAppDelegate), _new) return nil @@ -108,25 +98,6 @@ func appDelegate_buttonClicked(self C.id, sel C.SEL, button C.id) { // this actually constructs the delegate class -var ( - // objc_getClass() says it returns an id but it's actually a Class - // thanks to Psy| in irc.freenode.net/##objc - // don't call object_getClass() on this then, as I originally thought — that returns the /metaclass/ (which we don't want, and in fact I wasn't even aware we COULD subclass the metaclass directly like this) - _NSObject_Class = C.Class(unsafe.Pointer(_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 for NSApplication delegate; 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{'c', '@', ':', '@', 0} // BOOL (*)(id, SEL, id) diff --git a/objc_darwin.go b/objc_darwin.go index f8d7771..90afd74 100644 --- a/objc_darwin.go +++ b/objc_darwin.go @@ -3,6 +3,7 @@ package ui import ( + "fmt" "unsafe" ) @@ -50,3 +51,46 @@ func fromNSString(str C.id) string { cstr := C.objc_msgSend_noargs(str, _UTF8String) return C.GoString((*C.char)(unsafe.Pointer(cstr))) } + +// These create new classes. + +// selector contains the information for a new selector. +type selector struct { + name string + imp uintptr // not unsafe.Pointer because https://code.google.com/p/go/issues/detail?id=7665 + itype itype + desc string // for error reporting +} + +type itype uint +const ( + sel_void_id itype = iota + sel_bool_id + nitypes +) + +var itypes = [nitypes][]C.char{ + sel_void_id: []C.char{'v', '@', ':', '@', 0}, + sel_bool_id: []C.char{'c', '@', ':', '@', 0}, +} + +func makeClass(name string, super C.id, sels []selector, desc string) (err error) { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + + // an id that describes a class is itself a Class + // thanks to Psy| in irc.freenode.net/##objc + c := C.objc_allocateClassPair(C.Class(unsafe.Pointer(super)), cname, 0) + if c == C.NilClass { + return fmt.Errorf("unable to create Objective-C class %s for %s; reason unknown", name, desc) + } + C.objc_registerClassPair(c) + for _, v := range sels { + ok := C.class_addMethod(c, sel_getUid(v.name), + C.IMP(unsafe.Pointer(v.imp)), &itypes[v.itype][0]) + if ok == C.BOOL(C.NO) { + return fmt.Errorf("unable to add selector %s to class %s (needed for %s; reason unknown)", v.name, name, v.desc) + } + } + return nil +}