UPDATE: SUCCESS!
Since I sent that last email. I had a little break through.
Then GNUStep ObjC function class_getMethodImplementation (Apple also has
function class_getMethodImplementation_stret that is evidently not used in
GNUStep and is just a stub) and allows one to look up the C function that is
precisely used with the function.
So I created a nice Swift version of this lookup.
public func objc_smart_getIMP<T>(object: GNUStepNSObjectWrapper, selector:
String) -> T? {
let c = object_getClass(&object._nsobjptr!.pointee)
let v = class_getMethodImplementation(c, sel_getUid(selector))
let rt: T? = unsafeBitCast(v, to: T.self)
return rt
}
And then in the the var frame property of my NSView wrapper the following
public var frame: CGRect {
get {
var imp: (@convention(c) (id, SEL) -> (CGRect))? =
objc_smart_getIMP(object: self, selector: "frame")
if let rtn = imp?(&self._nsobjptr!.pointee,
sel_getUid("frame")) {
return rtn
}
return .init(x: 0, y: 0, width: 0, height: 0)
}
set {
guard let selfPtr = self._nsobjptr else {return}
let _: Any? = objc_smart_sendMessage(object: self,
selector: "setFrame:", value1: newValue)
}
}
RESULT: It worked!
When Swift Macros are working on Linux, this could be a Macro that generates
everything we need. Maybe @GNUStepPropertyWrapper("frame", "getFrame") We could
also have @GNUStepMethodWrapper that automatically wraps the method callers.
> On Aug 8, 2023, at 7:48 PM, [email protected] wrote:
>
> One of the issues that I am identifying is trying to manage the functions
> `objc_msgSend ` and `objc_msgSend_stret `. I did a write up on my GitHub for
> this project, and (as of right now) am trying to come up with solutions to
> getting the right memory out of calls to `objc_msgSend ` and
> `objc_msgSend_stret `.
>
> Basically I need a way to make objc_msgSend_stret more generic.
>
> Also what datatype size does objc_msgSend_stret service vs objc_msgSend. I am
> assuming, that objc_msgSend is good for pointers and datives that are the
> size of pointers?
>
> You can view my evolving discussion with myself at
> https://github.com/austintatiousness/GNUStepSwiftBridge
>
> - Austin
> objc_msgSend and objc_msgSend_stret
>
> objc_msgSend() is a c function used by the Objective-C runtime to send
> messages. Unfortunately it has a variable arguments which cannot be imported
> into Swift. To overcome this, I have created some specialized versions of of
> objc_msgSend that have different number of arguments. These can be found in
> the ObjCSwiftInterop.c file.
>
> Ultimately, I would like a swift version of this which more intelligently
> decides how to map the values. I started work on this, in the AppKit.swift
> file called func objc_smart_sendMessage<T>(object:
> NSObjectGNUStepSwiftBridge, selector: String, value1: Any?, value2: Any?,
> value3: Any?, value4: Any?, value5: Any?, value6: Any?, value7: Any?, value8:
> Any?, value9: Any?) -> T?
>
> This solves the problem that we have to send messages of arbitrary side, but
> it does not solve the issues around casting, and that two separate functions
> objc_msgSend and objc_msgSend_stret depending on which type we are going to
> get back from.
>
>
> <https://github.com/austintatiousness/GNUStepSwiftBridge/blob/main/README.md#casting>CASTING
>
> Just some thoughts and notes: Please correct me where I am wrong or
> misunderstanding.
>
> objc_msgSend and objc_msgSend_stret are very difficult functions to properly
> import into Swift. objc_msgSend is used for messages that return Objective-C
> classes, and simple data values that have the same size as id . From what I
> understand, both require the the function to be properly cast to work and
> because they are implemented in assembly and they are doing some magic with
> the registers to properly get the result. objc_msgSend returns void* but
> objc_msgSend_stret on GNUStep's runtime returns void. Before you can use
> objc_msgSend_stret, you have to cast it to a function that returns the value
> you are expecting.
>
> UIView *view = [[NSView alloc] initWithFrame:NSRectZero];
>
> NSRect (*sendRectFn)(id receiver, SEL operation);
> sendRectFn = (NSRect(*)(id, SEL))objc_msgSend_stret;
> NSRect frame = sendRectFn(view, @selector(frame));
> Idea 1: THIS DOES NOT WORK. I really have no idea what I am doing.
>
> void* forSwift_objcMsgSend_stret(id ID, SEL cmd, int64_t returnSize) {
> void* itemArr = malloc(returnSize);
> void* (*sendRectFn)(id receiver, SEL operation);
> sendRectFn = (void(*)(id, SEL))objc_msgSend_stret;
> itemArr = sendRectFn(ID, cmd);
> return itemArr;
> }
> What we need to be able to do is express this in Swift using
>
> I do not know how the objc_msgSend_stret knows what the returned data type
> should be.
>
>> On Aug 8, 2023, at 4:56 AM, Gregory Casamento <[email protected]>
>> wrote:
>>
>> M A,
>>
>> I guess you could consider the issues and such on github as a todo list.
>> You are welcome to take on any tasks on there if you like. Each repo has
>> it's own "Issues" tab where you can see what issues are outstanding. Or if
>> you can think of features that you think might be useful, please discuss it
>> here and we can all work together to make it happen if it sounds reasonable.
>>
>> Wrapping an ObjC class around swift sounds interesting, though most people
>> go the other way around these days... Swift->ObjC.
>>
>> Yours, GC
>>
>> On Mon, Aug 7, 2023 at 1:58 PM M A <[email protected]
>> <mailto:[email protected]>> wrote:
>>> A to do list would be a great edition to this project's website.
>>>
>>> One thing I would add it making a program that can wrap an Objective-c
>>> class around Swift code. There are just too many classes and methods to do
>>> it all by hand.
>>>
>>> > On Aug 7, 2023, at 1:51 PM, Gregory Casamento <[email protected]
>>> > <mailto:[email protected]>> wrote:
>>> >
>>> > I am extremely impressed!!! This is great! Please let me know if I can
>>> > help in any way.
>>> >
>>> > GC
>>> >
>>> > On Mon, Aug 7, 2023 at 10:35 AM <[email protected] <mailto:[email protected]>>
>>> > wrote:
>>> > Gregory,
>>> >
>>> > Thank you. I over last night, I was able to solve almost all the issues
>>> > with calling into GNUStep's AppKit and Foundation. I've been able to set
>>> > up buttons that respond to selectors, create objects at runtime and
>>> > register them with the runtime. Right now, I am working on generalizing a
>>> > sort of "Smart" version of obj_msgSend that allows me to not have to
>>> > write a separate version of that handles each type parameters. As it is
>>> > now, the only way I am getting it to work is to make a version of
>>> > objc_msgSend that explicitly takes, for example, an NSRect, or id.
>>> >
>>> > This is probably because I just don't fully understand how pointers work
>>> > in Swift. If anyone has any idea of how we can generalize the function, I
>>> > would greatly appreciate it. Thanks!
>>> >
>>> > Below is a screen shot of a working app written in Swift. The button does
>>> > work and does open the other window. It's pretty cool. You can see the
>>> > code on my GitHub. It's messy still.
>>> >
>>> >
>>> > <Image 8-7-23 at 9.33 AM.jpeg>
>>> >
>>> >> On Aug 6, 2023, at 7:59 PM, Gregory Casamento <[email protected]
>>> >> <mailto:[email protected]>> wrote:
>>> >>
>>> >> Hey, I just want you to know that this is VERY VERY cool!!! Yours, GC
>>> >>
>>> >> On Sun, Aug 6, 2023 at 12:05 PM <[email protected] <mailto:[email protected]>>
>>> >> wrote:
>>> >> I have solved the NSWindow initializer issue. I didn't realize I was
>>> >> passing Swift's Foundation.NSRect and not the C version. Sill haven't
>>> >> solved the issues regarding adding new ObjC classes to the runtime at
>>> >> runtime through Swift. Any ideas here would be appreciated.
>>> >>
>>> >> The image below is an GNUStep app written in Swift. The Menu is from the
>>> >> GORM file from the Terminal (I had to start somewhere!)
>>> >>
>>> >> <Screenshot 2023-08-06 at 10.54.06 AM.png>
>>> >>
>>> >>
>>> >>> On Aug 5, 2023, at 9:03 PM, [email protected] <mailto:[email protected]>
>>> >>> wrote:
>>> >>>
>>> >>> I just wanted to update everyone on my progress and solicit some help
>>> >>> if possible.
>>> >>>
>>> >>> State of my progress:
>>> >>> I've had a lot of success patching into GNUStep's libobjc2 C runtime
>>> >>> from within Swift. I've been able to create NSWindows through Swift,
>>> >>> call methods, et cetera. You can see my progress here
>>> >>> https://github.com/austintatiousness/GNUStepSwiftBridge . This assumes
>>> >>> that you're running this from within OnFlapp's GNUStep Desktop.
>>> >>>
>>> >>> Solution to objcSendMessage:
>>> >>> Because Swift doesn't allow variable argument parameters, I had to
>>> >>> create various versions of objcSendMessage (e.g
>>> >>> forSwift_objcSendMessage1, forSwift_objcSendMessage2,
>>> >>> forSwift_objcSendMessage3) to accommodate various number of arguments.
>>> >>>
>>> >>> Problem 1: NSWindow initWithContentRect:styleMask:backing:defer
>>> >>>
>>> >>> 1) I am having trouble with the NSWindow.initWith… functions. I am sure
>>> >>> that it is because of the way that I am casting all the values from
>>> >>> Swift into to the C implementation. Either I just don't understand how
>>> >>> the casting between Swift and C works OR I am just using the wrong
>>> >>> variables. I include a C version of the NSRect struct in my project.
>>> >>>
>>> >>> let nsWindowClass = objc_getClass("NSWindow")
>>> >>> var allocatedObject = forSwift_objcSendMessage(&nsWindowClass!.pointee,
>>> >>> sel_registerName("alloc"))
>>> >>>
>>> >>> var styleMask: UInt64 = 1 + 2 + 4
>>> >>> var backingStoreType: UInt64 = 0
>>> >>> var deferr: UInt8 = 0
>>> >>> var rect = NSRect(x: 200, y: 200, width: 300, height: 300)
>>> >>>
>>> >>> allocatedObject = forSwift_objcSendMessage4(&allocatedObject!.pointee,
>>> >>> sel_registerName("initWithContentRect:styleMask:backing:defer:"),
>>> >>> &rect, &styleMask, &backingStoreType, &deferr)
>>> >>>
>>> >>> I've tried several times to change the various integer types from
>>> >>> UInt64 to UInt8 to no avail.
>>> >>>
>>> >>> Problem 2: Registering new classes with the runtime.
>>> >>> This is the current state of the HelloWorld target:
>>> >>>
>>> >>> For reasons I cannot explain, I am able to allocate a new obj-c object
>>> >>> with objc_allocateClassPair and then register it using
>>> >>> objc_registerClassPair but when objc_getClass using the same class name
>>> >>> that I registered, it returns nil.
>>> >>>
>>> >>> Any help would be appreciated. I am currently unable to make progress
>>> >>> on adding delegates with out being able to register new ObjC classes
>>> >>> with the runtime.
>>> >>>
>>> >>> Thanks!
>>> >>
>>> >>
>>> >>
>>> >> --
>>> >> Gregory Casamento
>>> >> GNUstep Lead Developer / OLC, Principal Consultant
>>> >> http://www.gnustep.org <http://www.gnustep.org/> -
>>> >> http://heronsperch.blogspot.com <http://heronsperch.blogspot.com/>
>>> >> https://www.patreon.com/bePatron?u=352392 - Become a Patron
>>> >> https://www.openhub.net/languages/objective_c - OpenHub standings
>>> >
>>> >
>>> >
>>> > --
>>> > Gregory Casamento
>>> > GNUstep Lead Developer / OLC, Principal Consultant
>>> > http://www.gnustep.org <http://www.gnustep.org/> -
>>> > http://heronsperch.blogspot.com <http://heronsperch.blogspot.com/>
>>> > https://www.patreon.com/bePatron?u=352392 - Become a Patron
>>> > https://www.openhub.net/languages/objective_c - OpenHub standings
>>>
>>>
>>
>>
>> --
>> Gregory Casamento
>> GNUstep Lead Developer / OLC, Principal Consultant
>> http://www.gnustep.org <http://www.gnustep.org/> -
>> http://heronsperch.blogspot.com <http://heronsperch.blogspot.com/>
>> https://www.patreon.com/bePatron?u=352392 - Become a Patron
>> https://www.openhub.net/languages/objective_c - OpenHub standings
>