Methods being skipped when generating wrapping
Closed this issue · 5 comments
I am trying to add NSNotificationCenter to MacDriver. MacSchema was able to create a schema file successfully. When I look inside the file I do see the postNotification method and others there. For some reason I can't generate bindings for methods like postNotification. In the terminal I see these messages that tell me these methods are being skipped:
2023/07/08 19:17:32 skip NSNotificationCenter.addObserver:selector:name:object:: mapType: NSNotificationName
2023/07/08 19:17:32 skip NSNotificationCenter.addObserverForName:object:queue:usingBlock:: mapType: NSNotificationName
2023/07/08 19:17:32 skip NSNotificationCenter.postNotification:: pointers schema.DataType{Name:"NSNotification", IsPtr:true, IsPtrPtr:false, Annotations:[]string(nil), FuncPtr:(*schema.Func)(nil), Block:(*schema.Func)(nil), Params:[]schema.DataType(nil)}
2023/07/08 19:17:32 skip NSNotificationCenter.postNotificationName:object:: mapType: NSNotificationName
2023/07/08 19:17:32 skip NSNotificationCenter.postNotificationName:object:userInfo:: mapType: NSNotificationName
2023/07/08 19:17:32 skip NSNotificationCenter.removeObserver:name:object:: mapType: NSNotificationName
Why are these methods being skipped?
Is there a way to make the gen command not skip these methods?
They're being skipped because macdriver doesn't support them yet. I think in this case it's because they are using blocks/callbacks. For every callback signature we'd need to generate a CGO re-entry wrapper and the code to set that up. There is a very simple but also special case of this for the dispatch API, using a channel to queue Go functions to be called by a generic C callback sent to the actual dispatcher.
https://github.com/progrium/macdriver/tree/main/dispatch
I don't know if blocks are any different from function pointer callbacks.
I am trying to work with Objective-C methods calling Go functions. I think I have figured out this problem but I can't make my code compile due to a mysterious duplicate system error. Since it looks about done I thought would share it and see what you think.
package core
/*
This file tries to implement NSNotificationCenter's AddObserver:selector:name:object in Go.
Since NSNotificationCenter does call back methods on objects I have to make a system that
can call Go functions instead. A table in Go is made that keeps track of a Go function,
a Go object, and Go observer object. Each item in this table is identified by ID number.
Well when AddObserverSelectorNameObject() is called it sends to its objective-c method the
ID number and the name of the notification. A small class is made as a wrapper for the ID number
called ObjCCallback. When a notification is delivered, the ObjCCallback instance calls the
runCallbackFunc: method that then calls the Go CallGoCode() function. CallGoCode() is sent
the ID and uses it to search the table for a matching instance. The Go function that the
instance points to is finally called.
*/
/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework foundation
#include <foundation/foundation.h>
extern void CallGoCode(int, char *, char *);
// This class will be used to connect the ID field in
// the GoCallback struct in Go to this class' goID field.
@interface ObjCCallback : NSObject
{
@public int goID;
}
- (void) runCallbackFunc: (NSNotification *) n;
@end
@implementation ObjCCallback
- (void) runCallbackFunc: (NSNotification *) n
{
char *name = [[n name] cString];
char *anObject = [[n object] cString];
CallGoCode(self->goID, name, anObject);
}
@end
ObjCCallback *callbackObject;
void addObserverSelectorName(int objectID, char *name)
{
callbackObject = [ObjCCallback new];
callbackObject->goID = objectID;
NSString *nameStr = [NSString stringWithCString: name];
[[NSNotificationCenter defaultCenter] addObserver: callbackObject selector: @selector(runCallbackFunc:) name: nameStr object: nil];
}
void postNotificationNameObject(char *name, char *anObject) {
NSString *nameStr = [NSString stringWithCString: name];
if (anObject != nil) {
NSString *objStr = [NSString stringWithCString: anObject];
[[NSNotificationCenter defaultCenter] postNotificationName: nameStr object: objStr];
}
else {
[[NSNotificationCenter defaultCenter] postNotificationName: nameStr object: nil];
}
}
*/
import "C"
import "fmt"
type NSNotificationCenter struct {
gen_NSNotificationCenter
}
type GoCallback struct {
ID int
Callback func(n NSNotification)
Observer interface{}
AnObject interface{}
}
func (n NSNotificationCenter) PostNotificationNameObject(name string, anObject string) {
cName := C.CString(name)
cAnObject := C.CString(anObject)
C.postNotificationNameObject(cName, cAnObject)
}
var goCallbackTable []GoCallback
// Keeps track of number of times newGoCallback is called.
// Used an an ID
var callbackCount int
// Creates a new GoCallback object
func newGoCallback(callbackFunc func(n NSNotification), anObserver interface{}, anObject interface{}) GoCallback {
callbackCount++
return GoCallback{callbackCount, callbackFunc, anObserver, anObject}
}
func (n NSNotificationCenter) AddObserverSelectorNameObject(anObserver interface{}, callbackFunc func(n NSNotification),
name string, object interface{}) {
newObserver := newGoCallback(callbackFunc, anObserver, object)
goCallbackTable = append(goCallbackTable, newObserver)
C.addObserverSelectorName(C.int(newObserver.ID), C.CString(name))
}
//export CallGoCode
func CallGoCode(CID C.int, CName *C.char, CAnObject *C.char) {
// Convert arguments to Go types
ID := int(CID)
name := C.GoString(CName)
anObject := C.GoString(CAnObject)
fmt.Println("Hello from Go:", ID, name, anObject) // Maybe anObject can only be a string 🤨
for _, callbackObj := range goCallbackTable {
if callbackObj.ID == ID {
if callbackObj.AnObject != nil && callbackObj.AnObject == anObject {
notification := NSNotification{name, anObject}
callbackObj.Callback(notification)
} else {
notification := NSNotification{name, anObject}
callbackObj.Callback(notification)
}
}
break
}
}
I don't remember specifics but this might be related to an issue I ran into with the dispatch package. It's why the Go exported dispatcher
is in a separate file. Try putting your CallGoCode into a separate source file.
I also have the same question.
2023/07/11 17:05:59 skip NSToolbarItem.itemWithItemIdentifier:barButtonItem:: mapType: NSToolbarItemIdentifier
2023/07/11 17:05:59 skip NSToolbarItem.initWithItemIdentifier:: mapType: NSToolbarItemIdentifier
2023/07/11 17:05:59 skip NSToolbarItem.itemIdentifier: mapType: NSToolbarItemIdentifier
2023/07/11 17:05:59 skip NSSegmentedControl.segmentedControlWithImages:trackingMode:target:action:: mapType: NSSegmentSwitchTracking
2023/07/11 17:05:59 skip NSSegmentedControl.segmentedControlWithLabels:trackingMode:target:action:: mapType: NSSegmentSwitchTracking
Is it because there is no NSSegmentSwitchTracking enum and NSToolbarItemIdentifier generated?