What am i doing wrong here? I was expecting a pointer to the NSString class. The definition of the c function is defined in Apple's Objective-C Runtime Reference:https://developer.apple.com/library/mac ... c_getClass
objc_getClass
Returns the class definition of a specified class.
id objc_getClass(const char *name)
Parameters
name
The name of the class to look up.
Return Value
The Class object for the named class, or nil if the class is not registered with the Objective-C runtime.
I got the idea from this blog post http://sjhannah.com/blog/?p=219 which calls the objective-C runtime from Java by using the c-funtions:
objc_msgSend(), to pass messages to objects,
objc_getClass(), to get a pointer to a class and
selector_getUid(), to get the pointer to a selector.
Last edited by fdb on Wed Sep 03, 2014 3:26 pm, edited 1 time in total.
Is anyone interested in an newlisp-OBJC bridge? An obvious advantage would be the ability to make native MAC GUI applications, and maybe even IOS applications but i don't know how feasible/desirable that is. I'm going to see how far i can take this, but i don't have a lot of experience in C/ObjC/Cocoa and any help especially regarding memory mgt and proxy's is very welcome!
Cavemen in bearskins invaded the ivory towers of Artificial Intelligence. Nine months later, they left with a baby named newLISP. The women of the ivory towers wept and wailed. "Abomination!" they cried.
Ok, got the basic machinery working to send messages to classes and instances, see below. Next step is to use callbacks for setting delegate's so you could populate a table view from newLISP.
;;Objective-c bridge
(import "/System/Library/Frameworks/Foundation.framework/Foundation")
(set 'get-class (import "libobjc.dylib" "objc_getClass"))
(set 'get-sel (import "libobjc.dylib" "sel_getUid"))
(set 'msg (import "libobjc.dylib" "objc_msgSend"))
;; principal function sending a message to an instance or class with a variable
;; number of arguments
(define (send-to ptr sel)
(eval (flat (list 'msg ptr (get-sel sel) (args)))))
;; convenience functions can also be made for all classes which will let
;; code look exactly like OBJC syntax (without the ugly square brackets ofcourse)
(define (NSString sel)
(send-to (get-class "NSString") sel (args)))
;; we can then send messsages to classes which almost looks like standard OBJC syntax
;; at least for one variable statements
(set 'my-ns-string(NSString "stringWithUTF8String:" "i'm a pointer to an NSString instance"))
;; converting back from ns-string to normal string, as this is a pointer you need to
;; convert back with get-string. We are sending it to the instance we created with
;; send-to but first make a shortcut to make it almost look like OBJC
(set (sym "_") send-to)
(get-string (_ my-ns-string "UTF8String"))
Also, last night I pulled in some libc functions on my linux box; utimes(2) and link(2). It was so fast and easy I had a hard time believing it Just Worked. Thanks to Lutz for the libffi stuff, and the guy who came up with the (struct ..) function.
Only took 5 minutes. newLisp is letting me get over that nervous feeling of "what is going to go wrong next" every time I try something new.
Cavemen in bearskins invaded the ivory towers of Artificial Intelligence. Nine months later, they left with a baby named newLISP. The women of the ivory towers wept and wailed. "Abomination!" they cried.
I'm having problems with a function which returns a struct. To make a window appear on the screen i need an NSRect type, which is defined as a struct: {{CGFloat,CGFloat},{CGFloat,CGFloat}}. I've imported this function:
(import "/System/Library/Frameworks/Foundation.framework/Foundation" "NSRectFromString")
NSRectFromString@7FFF8C0561F9
'; but when called
(NSRectFromString "1 2 3 4")
There is nothing, Newlisp halts and i need to restart the shell.
Is there another way to construct this struct and pass it to another function? I've tried
NSRectFromString is expecting an NSString class as an argument, but you are passing it a pointer to a regular C string.
Wish I had access to the header files and stuff where this is implemented. Trying to find the class definition of NSString was tough; how would you use (struct) in newlisp to create an NSString. Or let's say you call the NSString() initializer that creates it for you, how do you modify its members inside newLISP.
Cavemen in bearskins invaded the ivory towers of Artificial Intelligence. Nine months later, they left with a baby named newLISP. The women of the ivory towers wept and wailed. "Abomination!" they cried.
doesn't work either. I think it is because it is returning a struct by value and in the import function you cannot define that it returns a struct by value, only pointers, primitive types and c-strings. Not sure if this is a limitation in the libffi library or just not implemented in newLisp.
I found a very nice toolset at ww.f-script.org which does what i try to achieve in newlIsp. Looks like they package structs in NSValue instances and have their own functions written in objective-c but i was hoping that i could interact with the runtime without an intermediate layer.
I've changed my message sending function to • (alt 8) and can alternate in methods and value and it looks nice have imported some constants and such and works fine except for structs..(i think) i can't get the following code to work
The runtime also complains about the style mask, but the message can differ every time i invoke the init method.
Lutz could you help here? After some googling i found that it may be the FFI: big structs 'are not passed on the stack' or something, i'm really out of my depth here and any help is much appreciated.
The fact, that the error looks different each time, makes me think that already reclaimed memory is overwritten.
I am not at all familiar with Objective C and how it manages memory but could imagine, that some of the memory allocated for structures by Objc—C (coming back as structure return values) is collected soon afterwards by Objective C. What might help is: not to nest newLISP expressions too much but do assignments first. This way memory crated in Obc-C functions gets copied/created and managed inside newLISP. E.g.:
Ps: I assume that @rect and • are functions imported from Objective C
Ps: on second thought if @rect and • return just some integer handle numbers/addresses it won't make a difference and still crash
Well i'm almost there (i hope)
The crashing is because you need to instantiate an NSApplication first which generates an event loop and takes care of events in the Window. So this tiny ObjC program works fine, the application starts and displays and empty window.
I still suspect that the rect struct isn't passed correctly, for the other values i also tested with 'packing' them but that didn't help either, Does anyone know how to test that the rect struct is passed correctly?
for sure nil and YES are not the same in newLISP and Objective C. In case of YES the contents of the newLISP variable YES will be passed. Somewhere you would have to set YES to the same value it has in Objective C. Probably you can find out from the header files. The same is true for nil, you probably have to define a NIL in newLISP for usage with Objective C:
Well i got it working! However structs are not passed correctly by libffi or the objc runtime is to blame. In order to get past this I made a small objc dynamic library:
and at last i got my window on screen! As you can see i can set the window title afterwards and also numbers are passed correctly only structs not because trying to change the size afterwards by passing a struct doesn't work.
Cavemen in bearskins invaded the ivory towers of Artificial Intelligence. Nine months later, they left with a baby named newLISP. The women of the ivory towers wept and wailed. "Abomination!" they cried.
Coming back to this (after 4 years , time flies!) I've recently made a minimalistic objective-c/cocoa bridge which doesn't need any 'glue' c-code /libraries. You only need to import 3 functions from the libobjc.dylib and two frameworks (foundation and appkit) which are standard available on a Mac. It is only 22 loc... but gives you the ability to create native GUI's on a Mac with newLisp. In order to use it you need some basic understanding of Objective-C and Cocoa (Google is your friend) but I'm going to start by building a layer on top of this conforming to the same API/functions as guiserver.lsp. So this is what the code looks like:
;;@module Minimalistic Cocoa / Objective-C bridge
(import "/System/Library/Frameworks/Foundation.framework/Foundation")
(import "/System/Library/Frameworks/AppKit.framework/AppKit")
(set 'get-class (import "libobjc.dylib" "objc_getClass"))
(set 'get-sel (import "libobjc.dylib" "sel_getUid"))
(import "libobjc.dylib" "objc_msgSend")
;; principal function sending a message to an instance or class with a variable
;; number of arguments use when the arguments are NOT floating points or structs
(define (-> ptr sel)
(when (string? ptr) (set 'ptr (get-class ptr)))
(eval (flat (list 'objc_msgSend ptr (get-sel sel) (args))))
)
;; function sending a message to an instance or class using an invocation object,
;; use when the arguments contain floats and or structs. The address of the return
;; value is returned
(define (=> target selector)
(when (string? target)
(set 'target (get-class target)))
(set 'sel (get-sel selector))
(set 'method (-> target "methodSignatureForSelector:" sel))
(set 'invocation (-> "NSInvocation" "invocationWithMethodSignature:" method))
(-> invocation "setSelector:" sel)
(doargs (arg)
(-> invocation "setArgument:atIndex:" (address arg) (+ $idx 2)))
(-> invocation "invokeWithTarget:" target)
(set 'size (-> method "methodReturnLength"))
(set 'return (dup "\000" size))
(-> invocation "getReturnValue:" (address return))
(address return)
)
To see an example see below code, which creates a window with a button on it.
Cavemen in bearskins invaded the ivory towers of Artificial Intelligence. Nine months later, they left with a baby named newLISP. The women of the ivory towers wept and wailed. "Abomination!" they cried.
And as probably the final piece I imported the objc function to dynamically add a method (= function) to an existing class with a given implementation (function pointer) which gives you the possibility to execute a newlisp function when for instance clicking on a button. You'll have to define the function first before adding the function to the class. See below code which executes the newlisp function "button-clicked" when you.. click the button! I think I've got everything in place now to copy the functionality of the guiserver for OSX , so no need for Java anymore.