That's a pretty good idea. I tried to make the Pointer class as simple (and stupid) as possible but we might need some convenience APIs on top of it, for those not familiar with the Objective-C encoding types. Here is an API proposal based on Brian's snippet... thoughts? class Pointer def self.new(type='@') new_with_type(type) end TYPES = { :int => 'i', :uint => 'I', ... } def self.to(sym) new_with_type(TYPES[sym]) end def value self[0] end end # I'm pretty sure I already wrote something similar in RubyCocoa. Laurent On Feb 25, 2009, at 1:16 PM, Matt Aimonetti wrote:
Thanks Brian for the detailed explanation. I wonder if your Pointer extension shouldn't be merged into HotCocoa or MacRuby itself.
What do you guys think?
- Matt
On Wed, Feb 25, 2009 at 12:43 PM, Brian Chapados <chapbr@gmail.com> wrote:
Can you explain: "^{_CGLRendererInfoObject=}"? is that some secret incantation only known by the MacRuby/Obj overlords?
Yes, it is actually a 7th level spell: 'Encode Structure'. To learn it, you must study the ancient tome: http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/A... /apple_ref/doc/uid/TP40008048-CH100-SW1
If it makes you feel better, I usually need to look it up (or just run the Obj-C code sample), unless it is something simple (like '@'). I don't keep this spell in memory, as it is only required in special situations.
Seriously though, that is actually how you encode a pointer to a struct. If you use the @encode(type) directive, the compiler will return the runtime encoding for 'type'. It's a bit cryptic, but not too bad once you know the syntax:
'^type' encodes a pointer to type. '{name=<field1 type><field2 type><field3 type>...<fieldN type>}' encodes a struct with N fields.
To break it down using 2 examples:
(from the docs) typedef struct example { id anObject; // encoding = @ char *aString; // encoding = c int anInt; // enoding = i } Example;
@encode(Example) = "^{example=@ci}"
CGLRendererInfoObj is a pointer to an opaque struct (we don't know anything about the fields) named _CGLRendererInfoObject. All we know is: typedef struct _CGLRendererInfoObject *CGLRendererInfoObj;
so it's just "^{_CGLRendererInfoObject=}"
In practice (unless you're working with CoreFoundation C APIs) you usually just need a pointer to an object. The most common usage I run across is to retrieve NSError objects. The CoreFoundation C API uses pass-by-reference extensively. To use these functions with MacRuby, you need to create lots of pointer objects. In general, this is an area where interfacing ruby with C is just fugly. I'd personally avoid doing this in MacRuby. If you find yourself needing to use lots Pointer objects, it's probably better and less error-prone to write that code in C and expose it to MacRuby through an Objective-C interface.
That said, for common things, I've used something like this extension to the Pointer class:
---- class Pointer def self.ptr new_with_type("@") end
def self.to(type = :object) case type when :object new_with_type('@') when :int new_with_type('i') when :char when :bool when :BOOL new_with_type('c') when :unsigned new_with_type('I') end end
def value self[0] end end
----
Need a pointer to an ObjC object? p = Pointer.ptr
To a BOOL? p = Pointer.to(:BOOL)
Need the value? p.value
Those are the most common types I've needed.
On Wed, Feb 25, 2009 at 11:11 AM, Matt Aimonetti <mattaimonetti@gmail.com> wrote:
Brian, what's up with this syntax: info = Pointer.new_with_type("^{_CGLRendererInfoObject=}") Can you explain: "^{_CGLRendererInfoObject=}"? is that some secret incantation only known by the MacRuby/Obj overlords? Thanks, - Matt
On Wed, Feb 25, 2009 at 10:13 AM, Brian Chapados <chapbr@gmail.com> wrote:
CGLRendererInfo is a pointer to a struct: typedef struct _CGLRendererInfoObject *CGLRendererInfoObj;
try creating a pointer to void or to the struct:
info = Pointer.new_with_type("^v") # void *info;
or
info = Pointer.new_with_type("^{_CGLRendererInfoObject=}") # CGLRendererInfo *info
I think the second one is effectively the same as what you were trying to do with: info = Pointer.new_with_type("CGLRendererInfoObj")
except that the runtime doesn't know what to do with "CGLRendererInfo". The argument to Pointer.new_with_type must be a valid Objective-C type encoding[1].
[1]: http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/A... /apple_ref/doc/uid/TP40008048-CH100-SW1
If you are ever in doubt about what encoding to use, you can always compile a small Objective-C program that prints out the output of @encode(). For example:
#import <Foundation/Foundation.h> #import <OpenGL/OpenGL.h>
int main(int argc, char *argv[]) { char *encoding = @encode(CGLRendererInfoObj); printf("\nencoding => %s\n\n", encoding); return 0; }
compile with: gcc -Wall -o encode encode.m -framework Foundation -framework OpenGL
then run: ./encode
Maybe there is an easier way to obtain the output of @encode(). I'm not sure.
Brian
On Wed, Feb 25, 2009 at 1:42 AM, Julien Jassaud <julien@collectapply.jp
wrote:
Hello, I am trying to port the Cocoa OpenGL sample to MacRuby and encountered a few problems.
First, I can't access some constants defined in an enum in GLTypes.h. Do I need to port those constants to ruby by hand ? Is that related to gen_bridge_metadata ?
Second, I need to use CGLQueryRendererInfo and CGLDescribeRenderer functions. The first one requires a pointer to a CGLRendererInfoObj structure but the second requires the object to be passed directly. I tried some C style pointer arithmetic : info = Pointer.new_with_type("CGLRendererInfoObj") count = Pointer.new_with_type("l") CGLQueryRendererInfo(caps[:cgl_display_mask], info, count) <- works fine, but CGLRendererInfoObj is opaque so I can't check it in irb. CGLDescribeRenderer(info[0], 0, kCGLRPRendererCount, count) <- I naively tried to dereference the pointer, but it doesn't work. CGLDescribeRenderer(info, 0, kCGLRPRendererCount, count) <- No complaints, but the value for count[0] is not consistent (100468704 renderers). I see in MacIRB that there is a CGLRendererInfoObj class but I can't instantiate it. This is all new to me and I may be overlooking something obvious. If anyone has an idea, please help. Thanks, Julien Jassaud _______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel