Search code examples
dgobjectclutter

Casting ClutterActor* to ClutterStage*


I am exploring the possibility of creating a Clutter binding for the D language ( http://d-programming-language.org/) and have started by trying some simple tests using dynamic loading of libclutter. I've run into a problem that might derive from the GObject inheritance system, and I'd appreciate any help getting it figured out. Here's the rundown: using clutter_stage_get_default returns a ClutterActor* which I can use with the clutter_actor_* methods. But I always get errors or segfaults when I use the clutter_stage_* or clutter_container_* methods. Here's my test code: http://pastebin.com/nVrQ69dU

At the clutter_container_add_actor call on line 56, I get the following error: (<unknown>:11976): Clutter-CRITICAL **: clutter_container_add_actor: assertion 'CLUTTER_IS_CONTAINER (container)' failed

In example code, I have noticed the CLUTTER_STAGE and CLUTTER_CONTAINER macros for casting (these obviously are not available to me), but as far as I could tell, they simply performed some checks, then did a plain C cast. If this is incorrect, and some Gobject type magic needs to be done on the stage pointer before casting, please let me know. Binding and using the clutter_stage_set_title or clutter_stage_set_color with cast(ClutterStage*)stage resulted in segmentation faults, presumably the same issue.

EDIT: Here's a stripped down example with no external dependencies (if you're not on Linux, you'll need to replace the dl calls with your OS's equivalents). This code fails with a segfault, which according to GDB and Valgrind, is in clutter_stage_set_title (in /usr/lib/libclutter-glx-1.0.so.0.600.14)


Solution

  • The problem is that you don't declare the C functions as extern(C). Because of that dmd thinks you're calling a D function and uses the wrong calling convention. One way to do this correctly is like this:

    alias extern(C) void function(void*, const char*) setTitleFunc;
    auto clutter_stage_set_title = getSym!(setTitleFunc)("clutter_stage_set_title");
    

    I'm not sure how to make it work without the alias though. DMD refuses to parse anything with extern(C) in a template parameter:

    auto clutter_stage_set_title = getSym!(extern(C) void function(void*, const char*))("clutter_stage_set_title"); //Doesn't work
    

    BTW: Your cstring function is dangerous: It returns a char* indicating that the string can be modified, but this is not always true: If you pass a string literal to toStringz it might not allocate new memory but return the pointer of the original string instead. String literals are in readonly memory, so this could lead to problems.

    You could just adjust your function types to match the C Types (const gchar* in C --> const char* in D) and use toStringz directly.