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 <[email protected]> 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/Articles/chapter_7_section_1.html#/ /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) = "^{examp...@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
<[email protected]> 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 <[email protected]> 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/Articles/chapter_7_section_1.html#/ /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 <[email protected] >
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
[email protected]
http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel


_______________________________________________
MacRuby-devel mailing list
[email protected]
http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel


_______________________________________________
MacRuby-devel mailing list
[email protected]
http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel


_______________________________________________
MacRuby-devel mailing list
[email protected]
http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel

_______________________________________________
MacRuby-devel mailing list
[email protected]
http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel

_______________________________________________
MacRuby-devel mailing list
[email protected]
http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel

Reply via email to