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 [email protected] 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, [email protected] 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, [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 > > > >
