No issues found
1 /* GNOME libraries - GdkPixbuf item for the GNOME canvas
2 *
3 * Copyright (C) 1999 The Free Software Foundation
4 *
5 * Author: Federico Mena-Quintero <federico@gimp.org>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <math.h>
28 #include <libgnomecanvas/gnome-canvas.h>
29 #include <libgnomecanvas/gnome-canvas-util.h>
30 #include <gdk-pixbuf/gdk-pixbuf.h>
31 #include "gnome-canvas-pixbuf.h"
32
33 #define GNOME_CANVAS_PIXBUF_GET_PRIVATE(obj) \
34 (G_TYPE_INSTANCE_GET_PRIVATE \
35 ((obj), GNOME_TYPE_CANVAS_PIXBUF, GnomeCanvasPixbufPrivate))
36
37 /* Private part of the GnomeCanvasPixbuf structure */
38 struct _GnomeCanvasPixbufPrivate {
39 /* Our gdk-pixbuf */
40 GdkPixbuf *pixbuf;
41 };
42
43 /* Object argument IDs */
44 enum {
45 PROP_0,
46 PROP_PIXBUF
47 };
48
49 static void gnome_canvas_pixbuf_dispose (GnomeCanvasItem *object);
50 static void gnome_canvas_pixbuf_set_property (GObject *object,
51 guint param_id,
52 const GValue *value,
53 GParamSpec *pspec);
54 static void gnome_canvas_pixbuf_get_property (GObject *object,
55 guint param_id,
56 GValue *value,
57 GParamSpec *pspec);
58
59 static void gnome_canvas_pixbuf_update (GnomeCanvasItem *item,
60 const cairo_matrix_t *i2c,
61 gint flags);
62 static void gnome_canvas_pixbuf_draw (GnomeCanvasItem *item, cairo_t *cr,
63 gint x, gint y, gint width, gint height);
64 static GnomeCanvasItem *gnome_canvas_pixbuf_point (GnomeCanvasItem *item,
65 gdouble x,
66 gdouble y,
67 gint cx,
68 gint cy);
69 static void gnome_canvas_pixbuf_bounds (GnomeCanvasItem *item,
70 gdouble *x1, gdouble *y1, gdouble *x2, gdouble *y2);
71
72 G_DEFINE_TYPE (GnomeCanvasPixbuf, gnome_canvas_pixbuf, GNOME_TYPE_CANVAS_ITEM)
73
74 /* Class initialization function for the pixbuf canvas item */
75 static void
76 gnome_canvas_pixbuf_class_init (GnomeCanvasPixbufClass *class)
77 {
78 GObjectClass *gobject_class;
79 GnomeCanvasItemClass *item_class;
80
81 gobject_class = (GObjectClass *) class;
82 item_class = (GnomeCanvasItemClass *) class;
83
84 gobject_class->set_property = gnome_canvas_pixbuf_set_property;
85 gobject_class->get_property = gnome_canvas_pixbuf_get_property;
86
87 g_object_class_install_property
88 (gobject_class,
89 PROP_PIXBUF,
90 g_param_spec_object ("pixbuf", NULL, NULL,
91 GDK_TYPE_PIXBUF,
92 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
93
94 item_class->dispose = gnome_canvas_pixbuf_dispose;
95 item_class->update = gnome_canvas_pixbuf_update;
96 item_class->draw = gnome_canvas_pixbuf_draw;
97 item_class->point = gnome_canvas_pixbuf_point;
98 item_class->bounds = gnome_canvas_pixbuf_bounds;
99
100 g_type_class_add_private (class, sizeof (GnomeCanvasPixbufPrivate));
101 }
102
103 /* Object initialization function for the pixbuf canvas item */
104 static void
105 gnome_canvas_pixbuf_init (GnomeCanvasPixbuf *gcp)
106 {
107 gcp->priv = GNOME_CANVAS_PIXBUF_GET_PRIVATE (gcp);
108 }
109
110 /* Dispose handler for the pixbuf canvas item */
111 static void
112 gnome_canvas_pixbuf_dispose (GnomeCanvasItem *object)
113 {
114 GnomeCanvasPixbuf *gcp;
115 GnomeCanvasPixbufPrivate *priv;
116
117 g_return_if_fail (object != NULL);
118 g_return_if_fail (GNOME_IS_CANVAS_PIXBUF (object));
119
120 gcp = GNOME_CANVAS_PIXBUF (object);
121 priv = gcp->priv;
122
123 if (priv->pixbuf != NULL) {
124 g_object_unref (priv->pixbuf);
125 priv->pixbuf = NULL;
126 }
127
128 if (GNOME_CANVAS_ITEM_CLASS (gnome_canvas_pixbuf_parent_class)->dispose)
129 GNOME_CANVAS_ITEM_CLASS (gnome_canvas_pixbuf_parent_class)->dispose (object);
130 }
131
132 /* Set_property handler for the pixbuf canvas item */
133 static void
134 gnome_canvas_pixbuf_set_property (GObject *object,
135 guint param_id,
136 const GValue *value,
137 GParamSpec *pspec)
138 {
139 GnomeCanvasItem *item;
140 GnomeCanvasPixbuf *gcp;
141 GnomeCanvasPixbufPrivate *priv;
142 GdkPixbuf *pixbuf;
143
144 g_return_if_fail (object != NULL);
145 g_return_if_fail (GNOME_IS_CANVAS_PIXBUF (object));
146
147 item = GNOME_CANVAS_ITEM (object);
148 gcp = GNOME_CANVAS_PIXBUF (object);
149 priv = gcp->priv;
150
151 switch (param_id) {
152 case PROP_PIXBUF:
153 pixbuf = g_value_get_object (value);
154 if (pixbuf != priv->pixbuf) {
155 if (priv->pixbuf)
156 g_object_unref (priv->pixbuf);
157
158 priv->pixbuf = g_object_ref (pixbuf);
159 }
160
161 gnome_canvas_item_request_update (item);
162 break;
163
164 default:
165 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
166 break;
167 }
168 }
169
170 /* Get_property handler for the pixbuf canvasi item */
171 static void
172 gnome_canvas_pixbuf_get_property (GObject *object,
173 guint param_id,
174 GValue *value,
175 GParamSpec *pspec)
176 {
177 GnomeCanvasPixbuf *gcp;
178 GnomeCanvasPixbufPrivate *priv;
179
180 g_return_if_fail (object != NULL);
181 g_return_if_fail (GNOME_IS_CANVAS_PIXBUF (object));
182
183 gcp = GNOME_CANVAS_PIXBUF (object);
184 priv = gcp->priv;
185
186 switch (param_id) {
187 case PROP_PIXBUF:
188 g_value_set_object (value, priv->pixbuf);
189 break;
190
191 default:
192 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
193 break;
194 }
195 }
196
197 /* Bounds and utilities */
198
199 /* Recomputes the bounding box of a pixbuf canvas item. The horizontal and
200 * vertical dimensions may be specified in units or pixels, separately, so we
201 * have to compute the components individually for each dimension.
202 */
203 static void
204 recompute_bounding_box (GnomeCanvasPixbuf *gcp)
205 {
206 GnomeCanvasItem *item;
207 GnomeCanvasPixbufPrivate *priv;
208 cairo_matrix_t i2c;
209 gdouble x1, x2, y1, y2;
210
211 item = GNOME_CANVAS_ITEM (gcp);
212 priv = gcp->priv;
213
214 if (!priv->pixbuf) {
215 item->x1 = item->y1 = item->x2 = item->y2 = 0.0;
216 return;
217 }
218
219 x1 = 0.0;
220 x2 = gdk_pixbuf_get_width (priv->pixbuf);
221 y1 = 0.0;
222 y2 = gdk_pixbuf_get_height (priv->pixbuf);
223
224 gnome_canvas_item_i2c_matrix (item, &i2c);
225 gnome_canvas_matrix_transform_rect (&i2c, &x1, &y1, &x2, &y2);
226
227 item->x1 = floor (x1);
228 item->y1 = floor (y1);
229 item->x2 = ceil (x2);
230 item->y2 = ceil (y2);
231 }
232
233 /* Update sequence */
234
235 /* Update handler for the pixbuf canvas item */
236 static void
237 gnome_canvas_pixbuf_update (GnomeCanvasItem *item,
238 const cairo_matrix_t *i2c,
239 gint flags)
240 {
241 GnomeCanvasPixbuf *gcp;
242
243 gcp = GNOME_CANVAS_PIXBUF (item);
244
245 if (GNOME_CANVAS_ITEM_CLASS (gnome_canvas_pixbuf_parent_class)->update)
246 GNOME_CANVAS_ITEM_CLASS (gnome_canvas_pixbuf_parent_class)->
247 update (item, i2c, flags);
248
249 /* ordinary update logic */
250 gnome_canvas_request_redraw (
251 item->canvas, item->x1, item->y1, item->x2, item->y2);
252 recompute_bounding_box (gcp);
253 gnome_canvas_request_redraw (
254 item->canvas, item->x1, item->y1, item->x2, item->y2);
255 }
256
257 /* Draw handler for the pixbuf canvas item */
258 static void
259 gnome_canvas_pixbuf_draw (GnomeCanvasItem *item,
260 cairo_t *cr,
261 gint x,
262 gint y,
263 gint width,
264 gint height)
265 {
266 GnomeCanvasPixbuf *gcp;
267 GnomeCanvasPixbufPrivate *priv;
268 cairo_matrix_t matrix;
269
270 gcp = GNOME_CANVAS_PIXBUF (item);
271 priv = gcp->priv;
272
273 if (!priv->pixbuf)
274 return;
275
276 gnome_canvas_item_i2c_matrix (item, &matrix);
277
278 cairo_save (cr);
279 cairo_transform (cr, &matrix);
280
281 gdk_cairo_set_source_pixbuf (cr, priv->pixbuf, 0, 0);
282 cairo_paint (cr);
283 cairo_restore (cr);
284 }
285
286 /* Point handler for the pixbuf canvas item */
287 static GnomeCanvasItem *
288 gnome_canvas_pixbuf_point (GnomeCanvasItem *item,
289 gdouble x,
290 gdouble y,
291 gint cx,
292 gint cy)
293 {
294 GnomeCanvasPixbuf *gcp;
295 GnomeCanvasPixbufPrivate *priv;
296 GdkPixbuf *pixbuf;
297 gint px, py;
298 guchar *src;
299
300 gcp = GNOME_CANVAS_PIXBUF (item);
301 priv = gcp->priv;
302 pixbuf = priv->pixbuf;
303
304 if (!priv->pixbuf)
305 return NULL;
306
307 px = x;
308 py = y;
309
310 if (px < 0 || px >= gdk_pixbuf_get_width (pixbuf) ||
311 py < 0 || py >= gdk_pixbuf_get_height (pixbuf))
312 return NULL;
313
314 if (!gdk_pixbuf_get_has_alpha (pixbuf))
315 return item;
316
317 src = gdk_pixbuf_get_pixels (pixbuf) +
318 py * gdk_pixbuf_get_rowstride (pixbuf) +
319 px * gdk_pixbuf_get_n_channels (pixbuf);
320
321 if (src[3] < 128)
322 return NULL;
323 else
324 return item;
325 }
326
327 /* Bounds handler for the pixbuf canvas item */
328 static void
329 gnome_canvas_pixbuf_bounds (GnomeCanvasItem *item,
330 gdouble *x1,
331 gdouble *y1,
332 gdouble *x2,
333 gdouble *y2)
334 {
335 GnomeCanvasPixbuf *gcp;
336 GnomeCanvasPixbufPrivate *priv;
337
338 gcp = GNOME_CANVAS_PIXBUF (item);
339 priv = gcp->priv;
340
341 if (!priv->pixbuf) {
342 *x1 = *y1 = *x2 = *y2 = 0.0;
343 return;
344 }
345
346 *x1 = 0;
347 *y1 = 0;
348 *x2 = gdk_pixbuf_get_width (priv->pixbuf);
349 *y2 = gdk_pixbuf_get_height (priv->pixbuf);
350 }