With GTK4, we’ve been trying to find better solution for image data. In GTK3 the objects we used for this were pixbufs and Cairo surfaces. But they don’t fit the bill anymore, so now we have GdkTexture
and GdkPaintable
.
GdkTexture
GdkTexture
is the replacement for GdkPixbuf
. Why is it better?
For a start, it is a lot simpler. The API looks like this:
int gdk_texture_get_width (GdkTexture *texture); int gdk_texture_get_height (GdkTexture *texture); void gdk_texture_download (GdkTexture *texture, guchar *data, gsize stride);
So it is a 2D pixel array and if you want to, you can download the pixels. It is also guaranteed immutable, so the pixels will never change. Lots of constructors exist to create textures from files, resources, data or pixbufs.
But the biggest difference between textures and pixbufs is that they don’t expose the memory that they use to store the pixels. In fact, before gdk_texture_download()
is called, that data doesn’t even need to exist.
And this is used in the GL texture. The GtkGLArea widget for example uses this method to pass data around. GStreamer is expected to pass video in the form of GL textures, too.
GdkPaintable
But sometimes, you have something more complex than an immutable bunch of pixels. For example you could have an animated GIF or a scalable SVG. That’s where GdkPaintable
comes in.
In abstract terms, GdkPaintable
is an interface for objects that know how to render themselves at any size. Inspired by CSS images, they can optionally provide intrinsic sizing information that GTK widgets can use to place them.
So the core of the GdkPaintable interface are the function make the paintable render itself and the 3 functions that provide sizing information:
void gdk_paintable_snapshot (GdkPaintable *paintable, GdkSnapshot *snapshot, double width, double height); int gdk_paintable_get_intrinsic_width (GdkPaintable *paintable); int gdk_paintable_get_intrinsic_height (GdkPaintable *paintable); double gdk_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable);
On top of that, the paintable can emit the “invalidate-contents” and “invalidate-size” signals when its contents or size changes.
To make this more concrete, let’s take a scalable SVG as an example: The paintable implementation would return no intrinsic size (the return value 0 for those sizing function achieves that) and whenever it is drawn, it would draw itself pixel-exact at the given size.
Or take the example of the animated GIF: It would provide its pixel size as its intrinsic size and draw the current frame of the animation scaled to the given size. And whenever the next frame of the animation should be displayed, it would emit the “invalidate-size” signal.
And last but not least, GdkTexture
implements this interface.
We’re currently in the process of changing all the code that in GTK3 accepted GdkPixbuf
to now accept GdkPaintable
. The GtkImage
widget of course has been changed already, as have the drag’n’drop icons or GtkAboutDialog
. Experimental patches exist to let applications provide paintables to the GTK CSS engine.
And if you now put all this information together about GStreamer potentially providing textures backed by GL images and creating paintables that do animations that can then be uploaded to CSS, you can maybe see where this is going…