Re: Perl bindings for libaosd: v0.01



On Sat, 2008-03-15 at 14:23 +0100, JÃrn Reder wrote:

It doesn't use GObject to implement its own objects, so it won't be
completely fool-proof to write bindings.  It's still not really hard,
and you don't need that much C experience.  So just give it a try.  Look
at other bindings.  Read some things about Perl's extension language XS.
Ask questions on this list.

Ok, so I did and so I'll do ;)

Great!

I wrote a first version binding the elementary stuff, so at least the 
test suite produces a black OSD rectangle (wow, I'm a hero :). For now 
you can download this well undocumented version here:

  http://www.exit1.org/packages/X11-Aosd/X11-Aosd-0.01.tar.gz

  (any comments are welcome how to do things better)

OK, some comments:

* Makefile.PL: ExtUtils::Depends allows to specify other
ExtUtils::Depens-using modules as dependencies.  get_makefile_vars()
will then set everything up correctly.  So, do:

  my $package = ExtUtils::Depends->new('X11::Aosd', 'Cairo', 'Gtk2');

* Aosd.xs

  - I'm surprised to see no PREFIX in the MODULE line.  That's usually
needed so xsubpp knows how to form the method names.

  - You expose aosd_destroy.  Try to avoid binding memory management
related functions.  In this case, you can automate releasing the object
by writing a DESTROY xsub which calls aosd_destroy:

void
DESTROY (Aosd *aosd)
    CODE:
        aosd_destroy (aosd);

DESTROY is automatically called by perl when a variable goes out of
scope.

  - You use newSVnv to convert integers to SVs.  newSVnv is for floating
point numbers.  Use newSViv for signed integers.

But in this state it's quite unusable and I'd appreciate some help. Next
thing is to add the Cairo stuff, which is realized using a callback in 
libaosd:

The callback:

  typedef void (*AosdRenderer)(cairo_t* cr, void* user_data);

Passing it to the Aosd object:

  void aosd_set_renderer(Aosd* aosd, AosdRenderer renderer, void* user_data);

My questions are: how do I create such a callback function? How do I 
reference to the Cairo Perl objects? Is it just adding a T_PTROBJ entry
for cairo_t in the typemap and passing a Cairo Perl object?

When you tell EU::Depends that Cairo is a dependency, you get access to
Cairo's typemaps.  So cairo_t* is handled automatically in normal
methods.

Unfortunately, callbacks can't be handled automatically yet.  You need
to write a C function that has the specified signature.  You pass a
reference to this C function to aosd_set_renderer.  When aosd then
invokes the callback, your C function is called.  Now the C function
needs to invoke a Perl callback somehow.  To do that, you put a function
and a user data scalar into a struct and pass this struct to
aosd_set_renderer as user_data.  Your C function receives this struct as
the second argument, so you unpack it and use perl's API to invoke the
function scalar.

To make things easier, you should depend on Gtk2 and thus on Glib.
Above the MODULE line, do this:

#include <gperl.h>
#include <cairo-perl.h>

static void
perl_aosd_renderer (cairo_t *cr, void *user_data)
{
        GPerlCallback *callback = user_data;
        dSP;

        ENTER;
        SAVETMPS;

        PUSHMARK (SP);
        EXTEND (SP, 2);
        PUSHs (sv_2mortal (newSVCairoContext (cr)));
        PUSHs (sv_2mortal (newSVsv (callback->data)));
        PUTBACK;

        call_sv (callback->func, G_DISCARD);

        FREETMPS;
        LEAVE;
}

And somewhere below the MODULE line, add this:

void
aosd_set_renderer (Aosd *aosd, SV *func, SV *data=NULL)
    PREINIT:
        CPerlCallback *callback;
    CODE:
        callback = gperl_callback_new (func, data, 0, NULL, 0);
        aosd_set_renderer (aosd, perl_aosd_renderer, callback);

Unfortunately, aosd doesn't provide destruction notification here, so
the memory used for callback will never be released.

The code is untested, so you might have to apply a compilation fix here
or there.

-- 
Bye,
-Torsten




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