This is a read-only archive of lispforum.com. The forum was locked to new users and posts and is preserved here as static HTML from a database snapshot taken on 2019-09-07.

cffi-clutter

20 posts · 10326 views

Hello, forum

In the last few days I have been fighting the "no way to do GUI in CL" problem by creating the bindings to Clutter Toolkit. It is a rather neat base for creating OpenGL based user interfaces. It is really a base though, as it provides no complex widgets, but it gives a signal-based event system and rendering management. It also quite intensively uses the GObject system, but it turned out to be much easier to manipulate from CL than I thought. There are examples how to subclass a GObject from Lisp, including implementing interfaces. It requires about as much boilerplate as in C, unfortunately, and I can't think of a good way to get rid of it.

The bindings are on github. There are two problems remaining that I am not sure how to solve. First, there are absolute paths in grovel/bindings file, and I am not sure how the get rid of those. Especially include directories, cffi-grovel seems not to allow `pkg-config` calls.

The second issue is more stylistic. I have semi-autogenerated the bindings (ie. autogenerated from a heavily hand-edited input files using a minimal subset of C), and given all generated function names a '%' prefix. But I don't think that there is much point in wrapping foreign Clutter objects in Lisp-side objects, so the public interface right now requires using those '%' functions, which is probably bad style, since those are usually used to signify functions internal to implementation. On the other hand, I don't want to get rid of '%' globally, because it makes wrapping those functions which use out-pointer C idiom annoying. On the other other hand as I written before, Clutter is low level enough that those function can be, in a sense, considered internal anyway.

Oh, well. I would appreciate any input on those issues, and if someone would test the bindings and check if I haven't somehow make them work on my machine only (other than the paths issues, which have to be modified for every installation). Note that the bindings are for recently released version 0.9.6, which breaks API compatibility with 0.8 series. I have no idea what versions are in package managers. In portage there is none, so I compiled Clutter from sources, which only compounds the paths issue.

Re: cffi-clutter

That sounds interesting.
I've been coding my cl-gtk2 binding for some time and have some experience working with GObject.
It looks like that you do not use the GObject system properly. First, it has a first-class support for using closures as callbacks (no need to defcallback every callback type and generic type-safe way to invoke/emit signals using GValue and GClosure). This lets you pass a closure as a signal handler and have it properly garbage collected.
Also, it does not seem that you use the GObject memory management to properly garbage-collect GObjects.
Then, you do not need to grovel for enums and flags, objects, properties and signals — GObject has it all exposed. The only things that require grovelling are:
1) methods/functions
2) vtable structures for interfaces/objects (needed for subclassing GObjects and implementing GInterfaces)
3) some properties that are for some reason not exposed through GObject type system
4) structures
Btw, I have a pretty good (as far as I think :) ) GObject binding at cl-gtk2. I think it is worth looking at it (however, subclassing objects is not quite supported yet, but implementing GInterfaces works.

Re: cffi-clutter

dmitry_vk wrote:It looks like that you do not use the GObject system properly.
That is more than likely, since I haven't really looked into it before, and only read about its features in minimal way necessary to implement Clutter features one after another.
dmitry_vk wrote: First, it has a first-class support for using closures as callbacks (no need to defcallback every callback type and generic type-safe way to invoke/emit signals using GValue and GClosure). This lets you pass a closure as a signal handler and have it properly garbage collected.
I noticed that, but I have an irrational hate and fear of GValue ;) , and don't want to write a proper marshaller. And before I understood how that works I had all those callbacks defined, and then it didn't seem worth bothering. And I am not sure about performance issues, although there probably is no point in worrying at this point with all the other things flying around already in GObject alone... not to mention I trampoline to Lisp functions anyway. At least those do get garbage collected.

Now that I think of it, I am not sure how much would moving parts of that mechanism into C-land would gain me anyway. I would have to write a marshaller in Lisp, and get hit from all those calls to g_value_get/set_something, and this way I just leave type translation to FFI with defcallback'ed thing serving as a marshaller of sorts.
dmitry_vk wrote:Also, it does not seem that you use the GObject memory management to properly garbage-collect GObjects.
I actually checked for that, and GObjects do get collected. Clutter does g_object_ref_sink() when an actor is parented and g_object_unref() when they are unparented, so actors are killed when they are dropped of stage, and other things are cleaned up explicitly in main wrapper. I chose not to even try doing something with Lisp-side proxy objects and finalization.
dmitry_vk wrote:Then, you do not need to grovel for enums and flags, objects, properties and signals — GObject has it all exposed. The only things that require grovelling are:
1) methods/functions
2) vtable structures for interfaces/objects (needed for subclassing GObjects and implementing GInterfaces)
3) some properties that are for some reason not exposed through GObject type system
4) structures
Right, I wrote that property-typemap.lisp monstrosity before I realized that the entire point of GObject properties is introspection, got to rewrite that. Enums/flags need mapping from C-names to Lisp-names anyway, even if I used GObject to map to them from values, so I might just as well grovel for them, saving a FFI call per translation.
dmitry_vk wrote:Btw, I have a pretty good (as far as I think :) ) GObject binding at cl-gtk2. I think it is worth looking at it (however, subclassing objects is not quite supported yet, but implementing GInterfaces works.
Subclassing is not hard, but a bit messy, since you can't really avoid grovelling (unless vtable offsets are hardcoded, and that never ends well) and defcallback'ing a lot, since virtual function translations need outright function pointers, not GClosures. I think.

Anyway, it seems that every GTK binding has its own GObject, or at least its subset, binding. Someone should create a stand alone complete one to be used for binding of systems using it. Someone who is not me, because I don't really understand that well how it works and I am not sure if I really want to, the entire thing is a poster child for Greenspun's Tenth Rule. I'm just happy to see rotating triangles which don't leak memory all over the place. I hope they don't, anyway.

Re: cffi-clutter

Ramarren wrote:I actually checked for that, and GObjects do get collected
Actually, what I meant is that you do not use GC, but manually specify what objects should be collected.
Ramarren wrote:Enums/flags need mapping from C-names to Lisp-names anyway, even if I used GObject to map to them from values, so I might just as well grovel for them, saving a FFI call per translation.
Enums/Flags have "nicknames" which are good as Lisp names (they even use dashes as word separators :) ). E.g., GTK_TYPE_TOPLEVEL has nickname "toplevel". Properties names are good for Lisp names.
Ramarren wrote:Subclassing is not hard, but a bit messy, since you can't really avoid grovelling (unless vtable offsets are hardcoded, and that never ends well) and defcallback'ing a lot, since virtual function translations need outright function pointers, not GClosures. I think.
Yes, it's not hard. All the mess with defcallbacks and vtables can and should be hidden be macros. I actually have the vtable and corresponding functions generated by a macro. A good way to automatically obtain vtable offsets and signatures is to use GObjectIntrospection.

Re: cffi-clutter

Neat! One more Lisp toy to play with :D
Ramarren wrote:The second issue is more stylistic. I have semi-autogenerated the bindings (ie. autogenerated from a heavily hand-edited input files using a minimal subset of C), and given all generated function names a '%' prefix. But I don't think that there is much point in wrapping foreign Clutter objects in Lisp-side objects, so the public interface right now requires using those '%' functions, which is probably bad style, since those are usually used to signify functions internal to implementation. On the other hand, I don't want to get rid of '%' globally, because it makes wrapping those functions which use out-pointer C idiom annoying. On the other other hand as I written before, Clutter is low level enough that those function can be, in a sense, considered internal anyway.
Let me stick my nose and give my opinion. You should keep the preffix '%' for generated functions, but always create a function without it and only export those such functions. If you need to add type-checks and do some wrapping or even generalizing these functions a little bit, you won't need to remanufacture everything.

It's not hard to let the REPL do this job for you. You can use do-symbols, or fetch the function definitions from the file in a list (place " '( " in the REPL, copy the contents of the file to the REPL, put a " ) " to terminate and evaluate) and loop into that list to extract the function names and return a list of function definitions.
Ramarren wrote:I have no idea what versions are in package managers. In portage there is none, so I compiled Clutter from sources, which only compounds the paths issue.
Ubuntu Jaunty (the last, and the one I use) have the Clutter version 0.9 and a quick search reveals that Debian have the version 0.8. The fact that gentoo doesn't have any version is, at least, uncommon; I have the felling that gentoo gets almost all packages first, specially small and unknown ones (no compilation is needed, and many developers use it).

Re: cffi-clutter

Ramarren wrote:Note that the bindings are for recently released version 0.9.6, which breaks API compatibility with 0.8 series. I have no idea what versions are in package managers. In portage there is none, so I compiled Clutter from sources, which only compounds the paths issue.
According to the blog post you mentioned, «This version is fully API and ABI incompatible with the previous 0.8 releases.» So API should not break.
I've cleaned up my GObject binding and I'm trying to use it to create binding for clutter. But I noticed that the clutter is rather picky about threading: if I compile a binding and call init in one thread, then start the main function from the REPL (compilation and evalution from REPL creates threads in SLIME), clutter prints messages "(<unknown>:20977): Clutter-CRITICAL **: clutter_id_pool_lookup: assertion `id < id_pool->array->len' failed". But if I call init from the same thread that I call main, it works.
It seems that you have experience with clutter; have you experienced this issue? If yes, how did you solve it (I didn't look very much at your sources)?

Re: cffi-clutter

dmitry_vk wrote:
Ramarren wrote:Note that the bindings are for recently released version 0.9.6, which breaks API compatibility with 0.8 series. I have no idea what versions are in package managers. In portage there is none, so I compiled Clutter from sources, which only compounds the paths issue.
According to the blog post you mentioned, «This version is fully API and ABI incompatible with the previous 0.8 releases.» So API should not break.
Note: fully incompatible. It changes types of most functions and many are replaced outright with other interfaces.
dmitry_vk wrote:I've cleaned up my GObject binding and I'm trying to use it to create binding for clutter. But I noticed that the clutter is rather picky about threading: if I compile a binding and call init in one thread, then start the main function from the REPL (compilation and evalution from REPL creates threads in SLIME), clutter prints messages "(<unknown>:20977): Clutter-CRITICAL **: clutter_id_pool_lookup: assertion `id < id_pool->array->len' failed". But if I call init from the same thread that I call main, it works.
It seems that you have experience with clutter; have you experienced this issue? If yes, how did you solve it (I didn't look very much at your sources)?
You have to call g_thread_init first, then clutter_threads_init, and then all Clutter calls need to be locked with clutter_threads_enter/leave.

Re: cffi-clutter

I was just wandering, are you using windows with clutter? Because i'm trying to build clutter but not managing it.... :?
It appears that it includes glx.h (from mesa libgl) which then includes some x11 headers which means i'm going to have to build this on cygwin...

Re: cffi-clutter

Harnon wrote:I was just wandering, are you using windows with clutter? Because i'm trying to build clutter but not managing it.... :?
It appears that it includes glx.h (from mesa libgl) which then includes some x11 headers which means i'm going to have to build this on cygwin...
I only tried building Clutter on Gentoo Linux. It seems rather Linux centric, but there are some blog posts which claim it is possible to build on Windows.

Re: cffi-clutter

lol. i followed the link and tried it, downloaded codeblocks and everything. 8 errors, syntax for that matter. Sigh...

Re: cffi-clutter

Well, i got version 0.9.2 to build. The instructions worked, i had just left some out. Yoopee! Now am working on 0.9.8. Just wondering, when you say "
It is mostly composed from semi-automatically generated bindings for Clutter and parts of GLib and GObject.", what did you use to semi-automatically generate it with?

Re: cffi-clutter

Harnon wrote:Well, i got version 0.9.2 to build. The instructions worked, i had just left some out. Yoopee! Now am working on 0.9.8.
I wonder if the cffi groveller works on Windows... at least it seems to have some conditional code for it, so there is hope!
Harnon wrote:Just wondering, when you say "
It is mostly composed from semi-automatically generated bindings for Clutter and parts of GLib and GObject.", what did you use to semi-automatically generate it with?
A rather ugly hack involving regular expression to parse a very small subset of C syntax. Essentially, I copy-pasted synopses from the Clutter API documentation (like this one), then cut those parts I couldn't be bothered to parse and done some more hand-editing. Hence, semi-automatically.

This was generally silly, as I should have either used some existing solution, as there are several, or at least done this properly (a wasted chance to try out my attempt at parser combinators). But, well, by the time the ugliness of the hack really got to me I was done.

Done creating the bindings to C functions at least, there are lots of things which should be further wrapped even for a fairly minimal bindings. I just did mostly what was needed for the tutorial.

Re: cffi-clutter

dmitry_vk wrote:Ramarren, if you are interested, I've made documentation for my GObject binding (http://common-lisp.net/project/cl-gtk2/ ... index.html). It may make task of creating clutter binding a little easier (but I don't insist on it). You can see my attempt at http://paste.lisp.org/display/84338. The example works (with the threading issue I told about earlier) and demonstrates basic GObject usage.
It looks quite impressive... I wish something like this was done before I started. Using it properly now would most likely mean a total rewrite. Not that there is much code besides the function bindings, but still... I will have to look more into it. In any case a more complete GObject binding will certainly be useful, because from what I have seen every previous GTK binding implements as little of it as it can get away with, and it is a mess. Although I only looked in detail at cells-gtk FFI layer, trying to make it work, so I might be biased.

Two things. One, it would be probably be a good idea to separate this into an individual project, because it will just get confusing, and adding a dependency on GTK bindings just for GObject seems unintuitive.

Two, I, perhaps unnecessarily, worry about performance impact from wrapping GObjects in (meta)classes. This doesn't matter for GTK, where manipulating objects is relatively rare, but Clutter is much lower level, which means potentially having a callback per animation frame, and unwrapping all those objects is going to add up. Although probably general FFI overhead already swamps it... well, I am not going to benchmark it, certainly not now, and it seems to be the only way to find out. But, if there are Python bindings and people are presumably using them, then why worry... although maybe they implement most of their class behaviour in C. Oh, well.

Re: cffi-clutter

Ramarren wrote:
dmitry_vk wrote:Ramarren, if you are interested, I've made documentation for my GObject binding (http://common-lisp.net/project/cl-gtk2/ ... index.html). It may make task of creating clutter binding a little easier (but I don't insist on it). You can see my attempt at http://paste.lisp.org/display/84338. The example works (with the threading issue I told about earlier) and demonstrates basic GObject usage.
It looks quite impressive... I wish something like this was done before I started. Using it properly now would most likely mean a total rewrite. Not that there is much code besides the function bindings, but still... I will have to look more into it. In any case a more complete GObject binding will certainly be useful, because from what I have seen every previous GTK binding implements as little of it as it can get away with, and it is a mess. Although I only looked in detail at cells-gtk FFI layer, trying to make it work, so I might be biased.

Two things. One, it would be probably be a good idea to separate this into an individual project, because it will just get confusing, and adding a dependency on GTK bindings just for GObject seems unintuitive.

Two, I, perhaps unnecessarily, worry about performance impact from wrapping GObjects in (meta)classes. This doesn't matter for GTK, where manipulating objects is relatively rare, but Clutter is much lower level, which means potentially having a callback per animation frame, and unwrapping all those objects is going to add up. Although probably general FFI overhead already swamps it... well, I am not going to benchmark it, certainly not now, and it seems to be the only way to find out. But, if there are Python bindings and people are presumably using them, then why worry... although maybe they implement most of their class behaviour in C. Oh, well.
I'm planning to split bindings to separate projects, but I'm still working on some parts of GObject (GBoxed and subclassing GObject) that require large modifications of source code, and splitting at this moment would be an obstacle.
I've though about performance of MOP, but I'll have to measure it (from what I can tell, MOP is a balanced protocol that allows efficiency in implementation). There are many ways where performance may drop, and all of them require measuring before deciding. But for now, I want to have a working GObject binding.

Re: cffi-clutter

Heh, i finally got 0.9.8 and 1.0.0. Soon, i can start playing with clutter. :D If anyone on windows needs help, just ask...

Re: cffi-clutter

Harnon wrote:Heh, i finally got 0.9.8 and 1.0.0. Soon, I can start playing with clutter. :D If anyone on windows needs help, just ask...
I haven't yet noticed that 1.0.0 was out... as far as I can see there were no API changes since 0.9.6 on which I based the binding, so it should work without problems, but I will rerun the examples just in case. Not that they cover all that much, but will check if basic initialization didn't suddenly start to fail.

Re: cffi-clutter

Just wandering, do i need threads to use clutter? You said it was pretty low level, lots of callbacks....

Re: cffi-clutter

Harnon wrote:Just wandering, do i need threads to use clutter? You said it was pretty low level, lots of callbacks....
Threads are not necessary, but obviously without threads clutter main loop will block the REPL. GObject based systems are not very amenable to parallelism anyway due to signal propagation, so it is not as the graphics themselves can be threaded.

There is an option to init-clutter wrapper function controlling threads initialization, but it shouldn't really matter to the Lisp side.

Re: cffi-clutter

Good day Jakub,

I've sent you a mail, referring to a patch making cffi-clutter build on a more-or-less default machine, but never got a reply.

I guess gmail has my server blacklisted.

I reproduce the email below:

Good day Jakub, git://git.feelingofgreen.ru/cffi-clutter has two patches:
- streamlining loadability on (at least) ubuntu karmic, by using the :OR
feature of CFFI library path specification, and conditionalising out
the apparently unused private API references
- a basic .gitignore.
regards, Samium Gromoff