From 354f2b65fa417d29647995e73bae059a633d442d Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 2 Nov 2020 20:58:28 -0500 Subject: [PATCH] gtk-demo: Reanimate floppy buddy Implement a GdkPaintable wrapper around GdkPixbufAnimation, so floppy buddy can waive again. --- demos/gtk-demo/demo.gresource.xml | 2 + demos/gtk-demo/images.c | 5 +- demos/gtk-demo/meson.build | 3 +- demos/gtk-demo/pixbufpaintable.c | 187 ++++++++++++++++++++++++++++++ demos/gtk-demo/pixbufpaintable.h | 13 +++ 5 files changed, 208 insertions(+), 2 deletions(-) create mode 100644 demos/gtk-demo/pixbufpaintable.c create mode 100644 demos/gtk-demo/pixbufpaintable.h diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml index 89d88edaa3..17388f4fbb 100644 --- a/demos/gtk-demo/demo.gresource.xml +++ b/demos/gtk-demo/demo.gresource.xml @@ -229,6 +229,8 @@ revealer.ui + pixbufpaintable.h + pixbufpaintable.c alphatest.png floppybuddy.gif gtk-logo.webm diff --git a/demos/gtk-demo/images.c b/demos/gtk-demo/images.c index c8b8ed8fd3..aec8412776 100644 --- a/demos/gtk-demo/images.c +++ b/demos/gtk-demo/images.c @@ -17,6 +17,7 @@ #include #include #include +#include "pixbufpaintable.h" static GtkWidget *window = NULL; static GdkPixbufLoader *pixbuf_loader = NULL; @@ -372,7 +373,9 @@ do_images (GtkWidget *do_widget) gtk_widget_set_valign (frame, GTK_ALIGN_CENTER); gtk_box_append (GTK_BOX (vbox), frame); - picture = gtk_picture_new_for_resource ("/images/floppybuddy.gif"); + paintable = pixbuf_paintable_new_from_resource ("/images/floppybuddy.gif"); + picture = gtk_picture_new_for_paintable (paintable); + g_object_unref (paintable); gtk_frame_set_child (GTK_FRAME (frame), picture); diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build index 39070bb925..49f37c7130 100644 --- a/demos/gtk-demo/meson.build +++ b/demos/gtk-demo/meson.build @@ -119,7 +119,8 @@ extra_demo_sources = files(['main.c', 'singular_value_decomposition.c', 'four_point_transform.c', 'demo2widget.c', - 'demo3widget.c']) + 'demo3widget.c', + 'pixbufpaintable.c']) if harfbuzz_dep.found() and pangoft_dep.found() demos += files(['font_features.c', 'listview_ucd.c']) diff --git a/demos/gtk-demo/pixbufpaintable.c b/demos/gtk-demo/pixbufpaintable.c new file mode 100644 index 0000000000..11685b726d --- /dev/null +++ b/demos/gtk-demo/pixbufpaintable.c @@ -0,0 +1,187 @@ +#include +#include "pixbufpaintable.h" + +struct _PixbufPaintable { + GObject parent_instance; + + char *resource_path; + GdkPixbufAnimation *anim; + GdkPixbufAnimationIter *iter; + + guint timeout; +}; + +enum { + PROP_RESOURCE_PATH = 1, + NUM_PROPERTIES +}; + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS; +static void +pixbuf_paintable_snapshot (GdkPaintable *paintable, + GdkSnapshot *snapshot, + double width, + double height) +{ + PixbufPaintable *self = PIXBUF_PAINTABLE (paintable); + GTimeVal val; + GdkPixbuf *pixbuf; + GdkTexture *texture; + + g_get_current_time (&val); + gdk_pixbuf_animation_iter_advance (self->iter, &val); + pixbuf = gdk_pixbuf_animation_iter_get_pixbuf (self->iter); + texture = gdk_texture_new_for_pixbuf (pixbuf); + + gdk_paintable_snapshot (GDK_PAINTABLE (texture), snapshot, width, height); + + g_object_unref (texture); +} +G_GNUC_END_IGNORE_DEPRECATIONS; + +static int +pixbuf_paintable_get_intrinsic_width (GdkPaintable *paintable) +{ + PixbufPaintable *self = PIXBUF_PAINTABLE (paintable); + + return gdk_pixbuf_animation_get_width (self->anim); +} + +static int +pixbuf_paintable_get_intrinsic_height (GdkPaintable *paintable) +{ + PixbufPaintable *self = PIXBUF_PAINTABLE (paintable); + + return gdk_pixbuf_animation_get_height (self->anim); +} + +static void +pixbuf_paintable_init_interface (GdkPaintableInterface *iface) +{ + iface->snapshot = pixbuf_paintable_snapshot; + iface->get_intrinsic_width = pixbuf_paintable_get_intrinsic_width; + iface->get_intrinsic_height = pixbuf_paintable_get_intrinsic_height; +} + +G_DEFINE_TYPE_WITH_CODE(PixbufPaintable, pixbuf_paintable, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE, + pixbuf_paintable_init_interface)) + +static void +pixbuf_paintable_init (PixbufPaintable *paintable) +{ +} + +static gboolean +delay_cb (gpointer data) +{ + PixbufPaintable *self = data; + int delay; + + delay = gdk_pixbuf_animation_iter_get_delay_time (self->iter); + self->timeout = g_timeout_add (delay, delay_cb, self); + + gdk_paintable_invalidate_contents (GDK_PAINTABLE (self)); + + return G_SOURCE_REMOVE; +} + +static void +pixbuf_paintable_set_resource_path (PixbufPaintable *self, + const char *resource_path) +{ + int delay; + + g_free (self->resource_path); + self->resource_path = g_strdup (resource_path); + + g_clear_object (&self->anim); + self->anim = gdk_pixbuf_animation_new_from_resource (resource_path, NULL); + g_clear_object (&self->iter); + self->iter = gdk_pixbuf_animation_get_iter (self->anim, NULL); + + delay = gdk_pixbuf_animation_iter_get_delay_time (self->iter); + self->timeout = g_timeout_add (delay, delay_cb, self); + + gdk_paintable_invalidate_contents (GDK_PAINTABLE (self)); + + g_object_notify (G_OBJECT (self), "resource-path"); +} + +static void +pixbuf_paintable_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PixbufPaintable *self = PIXBUF_PAINTABLE (object); + + switch (prop_id) + { + case PROP_RESOURCE_PATH: + pixbuf_paintable_set_resource_path (self, g_value_get_string (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +pixbuf_paintable_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PixbufPaintable *self = PIXBUF_PAINTABLE (object); + + switch (prop_id) + { + case PROP_RESOURCE_PATH: + g_value_set_string (value, self->resource_path); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +pixbuf_paintable_dispose (GObject *object) +{ + PixbufPaintable *self = PIXBUF_PAINTABLE (object); + + g_clear_pointer (&self->resource_path, g_free); + g_clear_object (&self->anim); + g_clear_object (&self->iter); + if (self->timeout) + { + g_source_remove (self->timeout); + self->timeout = 0; + } + + G_OBJECT_CLASS (pixbuf_paintable_parent_class)->dispose (object); +} + +static void +pixbuf_paintable_class_init (PixbufPaintableClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->dispose = pixbuf_paintable_dispose; + object_class->get_property = pixbuf_paintable_get_property; + object_class->set_property = pixbuf_paintable_set_property; + + g_object_class_install_property (object_class, PROP_RESOURCE_PATH, + g_param_spec_string ("resource-path", "Resource path", "Resource path", + NULL, G_PARAM_READWRITE)); + +} + +GdkPaintable * +pixbuf_paintable_new_from_resource (const char *path) +{ + return g_object_new (PIXBUF_TYPE_PAINTABLE, + "resource-path", path, + NULL); +} diff --git a/demos/gtk-demo/pixbufpaintable.h b/demos/gtk-demo/pixbufpaintable.h new file mode 100644 index 0000000000..5e075e3fb1 --- /dev/null +++ b/demos/gtk-demo/pixbufpaintable.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +G_BEGIN_DECLS + +#define PIXBUF_TYPE_PAINTABLE (pixbuf_paintable_get_type ()) + +G_DECLARE_FINAL_TYPE(PixbufPaintable, pixbuf_paintable, PIXBUF, PAINTABLE, GObject) + +GdkPaintable * pixbuf_paintable_new_from_resource (const char *path); + +G_END_DECLS