/* GNOME libraries - GdkPixbuf item for the GNOME canvas * * Copyright (C) 1999 The Free Software Foundation * * Author: Federico Mena-Quintero * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "gnome-canvas-pixbuf.h" #define GNOME_CANVAS_PIXBUF_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), GNOME_TYPE_CANVAS_PIXBUF, GnomeCanvasPixbufPrivate)) /* Private part of the GnomeCanvasPixbuf structure */ struct _GnomeCanvasPixbufPrivate { /* Our gdk-pixbuf */ GdkPixbuf *pixbuf; }; /* Object argument IDs */ enum { PROP_0, PROP_PIXBUF }; static void gnome_canvas_pixbuf_dispose (GnomeCanvasItem *object); static void gnome_canvas_pixbuf_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec); static void gnome_canvas_pixbuf_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec); static void gnome_canvas_pixbuf_update (GnomeCanvasItem *item, const cairo_matrix_t *i2c, gint flags); static void gnome_canvas_pixbuf_draw (GnomeCanvasItem *item, cairo_t *cr, gint x, gint y, gint width, gint height); static GnomeCanvasItem *gnome_canvas_pixbuf_point (GnomeCanvasItem *item, gdouble x, gdouble y, gint cx, gint cy); static void gnome_canvas_pixbuf_bounds (GnomeCanvasItem *item, gdouble *x1, gdouble *y1, gdouble *x2, gdouble *y2); G_DEFINE_TYPE (GnomeCanvasPixbuf, gnome_canvas_pixbuf, GNOME_TYPE_CANVAS_ITEM) /* Class initialization function for the pixbuf canvas item */ static void gnome_canvas_pixbuf_class_init (GnomeCanvasPixbufClass *class) { GObjectClass *gobject_class; GnomeCanvasItemClass *item_class; gobject_class = (GObjectClass *) class; item_class = (GnomeCanvasItemClass *) class; gobject_class->set_property = gnome_canvas_pixbuf_set_property; gobject_class->get_property = gnome_canvas_pixbuf_get_property; g_object_class_install_property (gobject_class, PROP_PIXBUF, g_param_spec_object ("pixbuf", NULL, NULL, GDK_TYPE_PIXBUF, (G_PARAM_READABLE | G_PARAM_WRITABLE))); item_class->dispose = gnome_canvas_pixbuf_dispose; item_class->update = gnome_canvas_pixbuf_update; item_class->draw = gnome_canvas_pixbuf_draw; item_class->point = gnome_canvas_pixbuf_point; item_class->bounds = gnome_canvas_pixbuf_bounds; g_type_class_add_private (class, sizeof (GnomeCanvasPixbufPrivate)); } /* Object initialization function for the pixbuf canvas item */ static void gnome_canvas_pixbuf_init (GnomeCanvasPixbuf *gcp) { gcp->priv = GNOME_CANVAS_PIXBUF_GET_PRIVATE (gcp); } /* Dispose handler for the pixbuf canvas item */ static void gnome_canvas_pixbuf_dispose (GnomeCanvasItem *object) { GnomeCanvasPixbuf *gcp; GnomeCanvasPixbufPrivate *priv; g_return_if_fail (object != NULL); g_return_if_fail (GNOME_IS_CANVAS_PIXBUF (object)); gcp = GNOME_CANVAS_PIXBUF (object); priv = gcp->priv; if (priv->pixbuf != NULL) { g_object_unref (priv->pixbuf); priv->pixbuf = NULL; } if (GNOME_CANVAS_ITEM_CLASS (gnome_canvas_pixbuf_parent_class)->dispose) GNOME_CANVAS_ITEM_CLASS (gnome_canvas_pixbuf_parent_class)->dispose (object); } /* Set_property handler for the pixbuf canvas item */ static void gnome_canvas_pixbuf_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec) { GnomeCanvasItem *item; GnomeCanvasPixbuf *gcp; GnomeCanvasPixbufPrivate *priv; GdkPixbuf *pixbuf; g_return_if_fail (object != NULL); g_return_if_fail (GNOME_IS_CANVAS_PIXBUF (object)); item = GNOME_CANVAS_ITEM (object); gcp = GNOME_CANVAS_PIXBUF (object); priv = gcp->priv; switch (param_id) { case PROP_PIXBUF: pixbuf = g_value_get_object (value); if (pixbuf != priv->pixbuf) { if (priv->pixbuf) g_object_unref (priv->pixbuf); priv->pixbuf = g_object_ref (pixbuf); } gnome_canvas_item_request_update (item); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; } } /* Get_property handler for the pixbuf canvasi item */ static void gnome_canvas_pixbuf_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec) { GnomeCanvasPixbuf *gcp; GnomeCanvasPixbufPrivate *priv; g_return_if_fail (object != NULL); g_return_if_fail (GNOME_IS_CANVAS_PIXBUF (object)); gcp = GNOME_CANVAS_PIXBUF (object); priv = gcp->priv; switch (param_id) { case PROP_PIXBUF: g_value_set_object (value, priv->pixbuf); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; } } /* Bounds and utilities */ /* Recomputes the bounding box of a pixbuf canvas item. The horizontal and * vertical dimensions may be specified in units or pixels, separately, so we * have to compute the components individually for each dimension. */ static void recompute_bounding_box (GnomeCanvasPixbuf *gcp) { GnomeCanvasItem *item; GnomeCanvasPixbufPrivate *priv; cairo_matrix_t i2c; gdouble x1, x2, y1, y2; item = GNOME_CANVAS_ITEM (gcp); priv = gcp->priv; if (!priv->pixbuf) { item->x1 = item->y1 = item->x2 = item->y2 = 0.0; return; } x1 = 0.0; x2 = gdk_pixbuf_get_width (priv->pixbuf); y1 = 0.0; y2 = gdk_pixbuf_get_height (priv->pixbuf); gnome_canvas_item_i2c_matrix (item, &i2c); gnome_canvas_matrix_transform_rect (&i2c, &x1, &y1, &x2, &y2); item->x1 = floor (x1); item->y1 = floor (y1); item->x2 = ceil (x2); item->y2 = ceil (y2); } /* Update sequence */ /* Update handler for the pixbuf canvas item */ static void gnome_canvas_pixbuf_update (GnomeCanvasItem *item, const cairo_matrix_t *i2c, gint flags) { GnomeCanvasPixbuf *gcp; gcp = GNOME_CANVAS_PIXBUF (item); if (GNOME_CANVAS_ITEM_CLASS (gnome_canvas_pixbuf_parent_class)->update) GNOME_CANVAS_ITEM_CLASS (gnome_canvas_pixbuf_parent_class)-> update (item, i2c, flags); /* ordinary update logic */ gnome_canvas_request_redraw ( item->canvas, item->x1, item->y1, item->x2, item->y2); recompute_bounding_box (gcp); gnome_canvas_request_redraw ( item->canvas, item->x1, item->y1, item->x2, item->y2); } /* Draw handler for the pixbuf canvas item */ static void gnome_canvas_pixbuf_draw (GnomeCanvasItem *item, cairo_t *cr, gint x, gint y, gint width, gint height) { GnomeCanvasPixbuf *gcp; GnomeCanvasPixbufPrivate *priv; cairo_matrix_t matrix; gcp = GNOME_CANVAS_PIXBUF (item); priv = gcp->priv; if (!priv->pixbuf) return; gnome_canvas_item_i2c_matrix (item, &matrix); cairo_save (cr); cairo_transform (cr, &matrix); gdk_cairo_set_source_pixbuf (cr, priv->pixbuf, 0, 0); cairo_paint (cr); cairo_restore (cr); } /* Point handler for the pixbuf canvas item */ static GnomeCanvasItem * gnome_canvas_pixbuf_point (GnomeCanvasItem *item, gdouble x, gdouble y, gint cx, gint cy) { GnomeCanvasPixbuf *gcp; GnomeCanvasPixbufPrivate *priv; GdkPixbuf *pixbuf; gint px, py; guchar *src; gcp = GNOME_CANVAS_PIXBUF (item); priv = gcp->priv; pixbuf = priv->pixbuf; if (!priv->pixbuf) return NULL; px = x; py = y; if (px < 0 || px >= gdk_pixbuf_get_width (pixbuf) || py < 0 || py >= gdk_pixbuf_get_height (pixbuf)) return NULL; if (!gdk_pixbuf_get_has_alpha (pixbuf)) return item; src = gdk_pixbuf_get_pixels (pixbuf) + py * gdk_pixbuf_get_rowstride (pixbuf) + px * gdk_pixbuf_get_n_channels (pixbuf); if (src[3] < 128) return NULL; else return item; } /* Bounds handler for the pixbuf canvas item */ static void gnome_canvas_pixbuf_bounds (GnomeCanvasItem *item, gdouble *x1, gdouble *y1, gdouble *x2, gdouble *y2) { GnomeCanvasPixbuf *gcp; GnomeCanvasPixbufPrivate *priv; gcp = GNOME_CANVAS_PIXBUF (item); priv = gcp->priv; if (!priv->pixbuf) { *x1 = *y1 = *x2 = *y2 = 0.0; return; } *x1 = 0; *y1 = 0; *x2 = gdk_pixbuf_get_width (priv->pixbuf); *y2 = gdk_pixbuf_get_height (priv->pixbuf); }