discuss-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Swift calling into GNUStep Progress


From: dr_clow
Subject: Re: Swift calling into GNUStep Progress
Date: Sun, 20 Aug 2023 16:09:50 -0500

I'm not familiar (yet) with StepTalk. I will look into it. 

> On Aug 17, 2023, at 6:03 PM, Ondrej Florian <onflapp@yahoo.com> wrote:
> 
> I am just wondering, would it make sense to make this part of 
> https://github.com/onflapp/libs-steptalk ?
> I was able to get quite far with it. 
> It is even possible to create GUI app now (see 
> https://github.com/onflapp/libs-steptalk/blob/master/Examples/AppKit/app.st)
> 
> On 2023-08-11 03:35:22 +0200 dr_clow@me.com wrote:
> 
>> Hello Friends,
>> I just wanted to give you a little update regarding my progress. All of this 
>> can also be viewed on my GitHub at 
>> <https://github.com/austintatiousness/GNUStepSwiftBridge/>
>> NSObjects and Subclassing
>> I have two classes that help bridge Swift classes to Objective-C (1) 
>> GNUStepNSObjectWrapper and (2) GNUStepNSObjectSubclassConstructor. The 
>> former 
>> is used to simply wrap Objective-C NSObjects and the latter is used to 
>> register subclasses with the GNUStep Objective-C runtime. All classes crated 
>> with GNUStepNSObjectSubclassConstructor get a special Ivar '___swiftPtr ' 
>> intended to hold a reference back the Swift. Once you use 
>> GNUStepNSObjectSubclassConstructor to create a new subclass, you can then 
>> wrap  it using GNUStepNSObjectWrapper.
>> I've actually had to do this already, within the Swift AppKit API, I've 
>> subclassed NSButton as "NSButtonForSwift" but expose it as NSButton to the 
>> Swift API. This allows me to use closures instead of target/selectors.
>> I don not currently like how I am using ___swiftPtr to hold a reference to 
>> the Swift object created with any class registered with 
>> GNUStepNSObjectSubclassConstructor, but it is the best solution I could come 
>> up keep track of who owns the Objective-C object.
>> I understand that on Apple platforms, Swift actually emits Objective-C 
>> compatible Swift objects when @objc or inheriting from NSObject occurs, 
>> which 
>> allows them casted on either side correctly.
>> NSString, NSArray and NSDictionary are all going to be problematic types 
>> because there is currently no way to share storage like in Apple's Swift 
>> implementation. I think that some work needs to be done here to figure this 
>> out. That is beyond my abilities. For now, I am just going to be copying 
>> data 
>> between them.
>> 
>> Currently, variables for like NSButton 'var title: String' take a String 
>> type 
>> and I just convert between NSString when getting and setting (I wish we 
>> could 
>> offer both, but Swift doesn't allow that) ; but when we have functions like 
>> "func setTitle(string: String)" I plan to also offer "func setTitle(string: 
>> NSString)" so we do not have to do any copying.
>> Additionally, NSArray and NSDictionary are only going to be able to store 
>> Objective-C types. On Apple Platforms,
>> 
>> Regarding Sending Messages / Calling Method: I've to figure out how to use 
>> objc_msgSend and objc_msgSend_stret from Swift, so instead I am now using 
>> class_getMethodImplementation. Which has been incredibly successful. I 
>> created some helper swift functions called objc_smart_getIMP to aid in 
>> setting these up better.
>> API Bridging Update:
>> I've gotten some of the the GUI objects going: NSWindow, NSButton, NSImage, 
>> NSImageView, NSFont, NSColor. You can get and set frames. It's pretty cool.
>> 
>> 
>> 
>> 
>> 
>>> On Aug 8, 2023, at 8:56 PM, dr_clow@me.com wrote:
>> 
>>> 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, dr_clow@me.com 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 
>>>>> <greg.casamento@gmail.com> 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 <teammember0x01@gmail.com 
>>>>> <mailto:teammember0x01@gmail.com>> 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 <greg.casamento@gmail.com 
>>>>>>> <mailto:greg.casamento@gmail.com>> 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 <dr_clow@me.com
>>>>>>> <mailto:dr_clow@me.com>> 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
>>>>>>> <greg.casamento@gmail.com <mailto:greg.casamento@gmail.com>> 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 <dr_clow@me.com
>>>>>>>> <mailto:dr_clow@me.com>> 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, dr_clow@me.com
>>>>>>>> <mailto:dr_clow@me.com> 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
>> 
>> 
>> 
>> 
> 
> 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]