2

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)

Justin W
  • 2,077
  • 12
  • 17

2 Answers2

2

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.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
jpf
  • 527
  • 3
  • 7
  • Ah, I didn't realize that I needed to specify the C calling convention when dynamically binding, though in retrospect it makes sense. – Justin W Jun 07 '11 at 16:27
0

structs in D cannot inherit from each other and casting struct pointers will return null unless there's a intermediate cast to void* (unlike a C cast) I got refuted here

you're better off adding another abstraction layer using handle-wrapping structs and emulating the checks from those macros when casting

but what happens if you do

clutter_container_add_actor(cast(ClutterContainer*)(cast(void*)stage), textbox);

(casting to void* first and then to ClutterContainer*)

ratchet freak
  • 47,288
  • 5
  • 68
  • 106
  • Using your suggestion produces the same results. Also, casting the struct pointers around does not produce null--adding `writeln(stage); writeln(cast(ClutterContainer*)stage);` produces two identical memory addresses. I'm using DMD 2.053, if that makes any difference. – Justin W Jun 06 '11 at 20:41
  • @justin you might just have to use void pointers for the Clutter handles, that's what I've seen done in other libraries interfacing with C-style structs – ratchet freak Jun 06 '11 at 21:23
  • @justin or try to get the exact structure of the structs and recreate them into the D interface files and try it with those – ratchet freak Jun 06 '11 at 21:43
  • Since I'm simply passing pointers from one clutter function to the next, I shouldn't need to know anything about the contents of the structs. Also, edited question with link to simplified, nothing but void*'s example. – Justin W Jun 06 '11 at 22:27
  • @justin as an aside are the functions you're importing made with the C calling convention? – ratchet freak Jun 06 '11 at 22:40
  • You can see the API reference here: http://docs.clutter-project.org/docs/clutter/stable/clutter-General.html I translate these to the D convention (e.g. `void function(int*, char***)` when binding as the C-style is no longer supported by DMD). – Justin W Jun 06 '11 at 22:44
  • @justin what happens if you call `clutter_stage_set_title(clutter_stage_get_default(), cstring("A window title"));` i.e. bypass the typing of the data – ratchet freak Jun 06 '11 at 22:54
  • Same thing, seg fault in clutter_stage_set_title. This is why I suspect the GObject system/clutter internals. – Justin W Jun 06 '11 at 22:57