I've written a small class to create a circular image from a base64 encoded JPEG bytearray, but it seems to constantly cause segfaults. This was the simplest way I could find to create a cairo surface in GJS, although I'm not opposed to Clutter, if it solves my problem.
var CircularImage = new Lang.Class({
Name: "CircularImage",
Extends: Gtk.DrawingArea,
_init: function (bytearray, win, size) {
this.parent({
height_request: size,
width_request: size
});
this.size = size;
let image_stream = Gio.MemoryInputStream.new_from_data(
GLib.base64_decode(bytearray),
GLib.free
);
let pixbuf = GdkPixbuf.Pixbuf.new_from_stream(
image_stream,
null
)
pixbuf.scale_simple(this.size, this.size, GdkPixbuf.InterpType.HYPER);
this._surface = Gdk.cairo_surface_create_from_pixbuf(
pixbuf,
0,
win.get_window()
);
this.connect("draw", (widget, cr) => {
this._draw(widget, cr);
return false;
});
},
_draw: function (widget, cr) {
cr.setSourceSurface(this._surface, 0, 0);
cr.arc(this.size/2, this.size/2, this.size/2, 0, 2*Math.PI);
cr.clip();
cr.paint();
}
});
There doesn't seem to be a destroy function or signal for CairoImageSurface's and I've tried unreffing the pixbuf to see if that helped, but this results in an error:
GLib-GObject-WARNING **: g_object_remove_toggle_ref: couldn't find toggle ref 0x7f45456b19e0((nil))
I've used this in a simple Gtk window and it works, but it seems to cause segfaults about half the time. I know little about memory management since I usually use garbage-collected languages, so I only assume this has something to do with memory I'm not freeing.
Is there something obvious I'm doing wrong, an easier way to do this with Clutter or simple way I can track down the arbitrary segfaults?
You should not have to deal with memory management in GJS even if the underlying library requires it. If you do, it's a bug. Trying to do it anyway will definitely cause a crash. (So if you see any instructions to call GLib.free()
or GObject.unref()
even in the GJS docs — they're autogenerated from the C documentation and should not be there.)
Unfortunately such bugs that require you to care about memory management do still exist, and two of them are relevant to your code snippet.
The bug you're hitting right now is this one: https://bugzilla.gnome.org/show_bug.cgi?id=747431 Instead, do something like this:
let image_stream = Gio.MemoryInputStream.new_from_bytes(
GLib.base64_decode(bytearray).toGBytes());
Another GJS bug which might become relevant later is that when you connect to a draw
signal you do currently have to call cr.$dispose()
on the Cairo context or the memory will be leaked.