1 | #include <gtk/gtk.h> |
2 | #include "pixbufpaintable.h" |
3 | |
4 | struct _PixbufPaintable { |
5 | GObject parent_instance; |
6 | |
7 | char *resource_path; |
8 | GdkPixbufAnimation *anim; |
9 | GdkPixbufAnimationIter *iter; |
10 | |
11 | guint timeout; |
12 | }; |
13 | |
14 | enum { |
15 | PROP_RESOURCE_PATH = 1, |
16 | NUM_PROPERTIES |
17 | }; |
18 | |
19 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS; |
20 | static void |
21 | pixbuf_paintable_snapshot (GdkPaintable *paintable, |
22 | GdkSnapshot *snapshot, |
23 | double width, |
24 | double height) |
25 | { |
26 | PixbufPaintable *self = PIXBUF_PAINTABLE (ptr: paintable); |
27 | GTimeVal val; |
28 | GdkPixbuf *pixbuf; |
29 | GdkTexture *texture; |
30 | |
31 | g_get_current_time (result: &val); |
32 | gdk_pixbuf_animation_iter_advance (iter: self->iter, current_time: &val); |
33 | pixbuf = gdk_pixbuf_animation_iter_get_pixbuf (iter: self->iter); |
34 | texture = gdk_texture_new_for_pixbuf (pixbuf); |
35 | |
36 | gdk_paintable_snapshot (paintable: GDK_PAINTABLE (ptr: texture), snapshot, width, height); |
37 | |
38 | g_object_unref (object: texture); |
39 | } |
40 | G_GNUC_END_IGNORE_DEPRECATIONS; |
41 | |
42 | static int |
43 | pixbuf_paintable_get_intrinsic_width (GdkPaintable *paintable) |
44 | { |
45 | PixbufPaintable *self = PIXBUF_PAINTABLE (ptr: paintable); |
46 | |
47 | return gdk_pixbuf_animation_get_width (animation: self->anim); |
48 | } |
49 | |
50 | static int |
51 | pixbuf_paintable_get_intrinsic_height (GdkPaintable *paintable) |
52 | { |
53 | PixbufPaintable *self = PIXBUF_PAINTABLE (ptr: paintable); |
54 | |
55 | return gdk_pixbuf_animation_get_height (animation: self->anim); |
56 | } |
57 | |
58 | static void |
59 | pixbuf_paintable_init_interface (GdkPaintableInterface *iface) |
60 | { |
61 | iface->snapshot = pixbuf_paintable_snapshot; |
62 | iface->get_intrinsic_width = pixbuf_paintable_get_intrinsic_width; |
63 | iface->get_intrinsic_height = pixbuf_paintable_get_intrinsic_height; |
64 | } |
65 | |
66 | G_DEFINE_TYPE_WITH_CODE(PixbufPaintable, pixbuf_paintable, G_TYPE_OBJECT, |
67 | G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE, |
68 | pixbuf_paintable_init_interface)) |
69 | |
70 | static void |
71 | pixbuf_paintable_init (PixbufPaintable *paintable) |
72 | { |
73 | } |
74 | |
75 | static gboolean |
76 | delay_cb (gpointer data) |
77 | { |
78 | PixbufPaintable *self = data; |
79 | int delay; |
80 | |
81 | delay = gdk_pixbuf_animation_iter_get_delay_time (iter: self->iter); |
82 | self->timeout = g_timeout_add (interval: delay, function: delay_cb, data: self); |
83 | |
84 | gdk_paintable_invalidate_contents (paintable: GDK_PAINTABLE (ptr: self)); |
85 | |
86 | return G_SOURCE_REMOVE; |
87 | } |
88 | |
89 | static void |
90 | pixbuf_paintable_set_resource_path (PixbufPaintable *self, |
91 | const char *resource_path) |
92 | { |
93 | int delay; |
94 | |
95 | g_free (mem: self->resource_path); |
96 | self->resource_path = g_strdup (str: resource_path); |
97 | |
98 | g_clear_object (&self->anim); |
99 | self->anim = gdk_pixbuf_animation_new_from_resource (resource_path, NULL); |
100 | g_clear_object (&self->iter); |
101 | self->iter = gdk_pixbuf_animation_get_iter (animation: self->anim, NULL); |
102 | |
103 | delay = gdk_pixbuf_animation_iter_get_delay_time (iter: self->iter); |
104 | self->timeout = g_timeout_add (interval: delay, function: delay_cb, data: self); |
105 | |
106 | gdk_paintable_invalidate_contents (paintable: GDK_PAINTABLE (ptr: self)); |
107 | |
108 | g_object_notify (G_OBJECT (self), property_name: "resource-path" ); |
109 | } |
110 | |
111 | static void |
112 | pixbuf_paintable_set_property (GObject *object, |
113 | guint prop_id, |
114 | const GValue *value, |
115 | GParamSpec *pspec) |
116 | { |
117 | PixbufPaintable *self = PIXBUF_PAINTABLE (ptr: object); |
118 | |
119 | switch (prop_id) |
120 | { |
121 | case PROP_RESOURCE_PATH: |
122 | pixbuf_paintable_set_resource_path (self, resource_path: g_value_get_string (value)); |
123 | break; |
124 | |
125 | default: |
126 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
127 | } |
128 | } |
129 | |
130 | static void |
131 | pixbuf_paintable_get_property (GObject *object, |
132 | guint prop_id, |
133 | GValue *value, |
134 | GParamSpec *pspec) |
135 | { |
136 | PixbufPaintable *self = PIXBUF_PAINTABLE (ptr: object); |
137 | |
138 | switch (prop_id) |
139 | { |
140 | case PROP_RESOURCE_PATH: |
141 | g_value_set_string (value, v_string: self->resource_path); |
142 | break; |
143 | |
144 | default: |
145 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
146 | } |
147 | } |
148 | |
149 | static void |
150 | pixbuf_paintable_dispose (GObject *object) |
151 | { |
152 | PixbufPaintable *self = PIXBUF_PAINTABLE (ptr: object); |
153 | |
154 | g_clear_pointer (&self->resource_path, g_free); |
155 | g_clear_object (&self->anim); |
156 | g_clear_object (&self->iter); |
157 | if (self->timeout) |
158 | { |
159 | g_source_remove (tag: self->timeout); |
160 | self->timeout = 0; |
161 | } |
162 | |
163 | G_OBJECT_CLASS (pixbuf_paintable_parent_class)->dispose (object); |
164 | } |
165 | |
166 | static void |
167 | pixbuf_paintable_class_init (PixbufPaintableClass *class) |
168 | { |
169 | GObjectClass *object_class = G_OBJECT_CLASS (class); |
170 | |
171 | object_class->dispose = pixbuf_paintable_dispose; |
172 | object_class->get_property = pixbuf_paintable_get_property; |
173 | object_class->set_property = pixbuf_paintable_set_property; |
174 | |
175 | g_object_class_install_property (oclass: object_class, property_id: PROP_RESOURCE_PATH, |
176 | pspec: g_param_spec_string (name: "resource-path" , nick: "Resource path" , blurb: "Resource path" , |
177 | NULL, flags: G_PARAM_READWRITE)); |
178 | |
179 | } |
180 | |
181 | GdkPaintable * |
182 | pixbuf_paintable_new_from_resource (const char *path) |
183 | { |
184 | return g_object_new (PIXBUF_TYPE_PAINTABLE, |
185 | first_property_name: "resource-path" , path, |
186 | NULL); |
187 | } |
188 | |