First of all thank for sharing your example, and thank you for creating a github repository about it. I need to look deeper to better assess what is happening and provide a solution. But here you have my initial guess: you may need first to allocate Typed memory for example for cairo_t (and actually probably for other similar struct that you use).
In the other example in which you nicely worked (ncforeign) the signature of the functions was a bit more simple, in this case with libgtk it seems to me that you use pointers/Types that need allocation.
seems to be similar to other I have seen, and after read your code, you have:
type cairo_t
let cairo_t : cairo_t structure typ = structure "_cairo"
It might be that you need a line in the function where you try to pass the cairo_t similar to:
(* I need to check further the specific syntax but the idea is like *)
let cairo_ptr = Ctypes.allocate cairo_t (cairo' ()) in
(* and you may pass cairo_ptr here defined *)
Here’s what I think is going on. I know the solution I gave you is still incomplete (so it is not a final solution) as I need to dig deeper into your code and try things there when I find some free time. But I wanted to give you an idea of what might be going on in case you want to try something like this yourself.
Note: there is a small section about this here, a bit incomplete but you have there ideas applied to other examples.