[build] Bumped version to 0.5.1
[adg.git] / adg / adg-entity.c
blob9b27e20733acebabb2af50e616416760455967d1
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009 Nicola Fontana <ntd at entidi.it>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
21 /**
22 * SECTION:adg-entity
23 * @short_description: The base class for renderable objects
25 * This abstract class provides the base for all renderable objects.
27 * To provide a proper #AdgEntity derived type, you must at least
28 * implement the render() virtual method. Also, if you are using
29 * some sort of caching, you must implement invalidate() to clear
30 * this cache.
31 **/
33 /**
34 * AdgEntity:
36 * All fields are private and should not be used directly.
37 * Use its public methods instead.
38 **/
40 /**
41 * AdgEntityClass:
42 * @parent_set: called after the parent has changed
43 * @invalidate: invalidating callback, used to clear the cache
44 * @render: rendering callback, it must be implemented
46 * Any entity (if not abstract) must implement at least the @render method.
47 **/
50 #include "adg-entity.h"
51 #include "adg-entity-private.h"
52 #include "adg-canvas.h"
53 #include "adg-font-style.h"
54 #include "adg-dim-style.h"
55 #include "adg-intl.h"
57 #define PARENT_OBJECT_CLASS ((GObjectClass *) adg_entity_parent_class)
60 enum {
61 PROP_0,
62 PROP_PARENT,
63 PROP_GLOBAL_MAP,
64 PROP_LOCAL_MAP
67 enum {
68 PARENT_SET,
69 INVALIDATE,
70 RENDER,
71 LAST_SIGNAL
75 static void dispose (GObject *object);
76 static void get_property (GObject *object,
77 guint prop_id,
78 GValue *value,
79 GParamSpec *pspec);
80 static void set_property (GObject *object,
81 guint prop_id,
82 const GValue *value,
83 GParamSpec *pspec);
84 static gboolean set_parent (AdgEntity *entity,
85 AdgEntity *parent);
86 static void set_global_map (AdgEntity *entity,
87 const AdgMatrix *map);
88 static void set_local_map (AdgEntity *entity,
89 const AdgMatrix *map);
90 static void get_global_matrix (AdgEntity *entity,
91 AdgMatrix *matrix);
92 static void get_local_matrix (AdgEntity *entity,
93 AdgMatrix *matrix);
94 static void real_invalidate (AdgEntity *entity,
95 gpointer user_data);
96 static void real_render (AdgEntity *entity,
97 cairo_t *cr,
98 gpointer user_data);
100 static guint signals[LAST_SIGNAL] = { 0 };
103 G_DEFINE_ABSTRACT_TYPE(AdgEntity, adg_entity, G_TYPE_INITIALLY_UNOWNED);
106 static void
107 adg_entity_class_init(AdgEntityClass *klass)
109 GObjectClass *gobject_class;
110 GParamSpec *param;
111 GClosure *closure;
112 GType param_types[1];
114 gobject_class = (GObjectClass *) klass;
116 g_type_class_add_private(klass, sizeof(AdgEntityPrivate));
118 gobject_class->dispose = dispose;
119 gobject_class->get_property = get_property;
120 gobject_class->set_property = set_property;
122 klass->parent_set = NULL;
123 klass->get_global_matrix = get_global_matrix;
124 klass->get_local_matrix = get_local_matrix;
125 klass->invalidate = NULL;
126 klass->render = NULL;
128 param = g_param_spec_object("parent",
129 P_("Parent Entity"),
130 P_("The parent entity of this entity or NULL if this is a top-level entity"),
131 ADG_TYPE_ENTITY, G_PARAM_READWRITE);
132 g_object_class_install_property(gobject_class, PROP_PARENT, param);
134 param = g_param_spec_boxed("global-map",
135 P_("Global Map"),
136 P_("The transformation to be combined with the parent ones to get the global matrix"),
137 ADG_TYPE_MATRIX, G_PARAM_READWRITE);
138 g_object_class_install_property(gobject_class, PROP_GLOBAL_MAP, param);
140 param = g_param_spec_boxed("local-map",
141 P_("Local Map"),
142 P_("The transformation to be combined with the parent ones to get the local matrix"),
143 ADG_TYPE_MATRIX, G_PARAM_READWRITE);
144 g_object_class_install_property(gobject_class, PROP_LOCAL_MAP, param);
147 * AdgEntity::parent-set:
148 * @entity: an #AdgEntity
149 * @old_parent: the old parent
151 * Emitted after the parent entity has changed. The new parent
152 * can be inspected using adg_entity_get_parent().
154 * It is allowed for both old and new parent to be %NULL.
156 signals[PARENT_SET] = g_signal_new("parent-set",
157 G_OBJECT_CLASS_TYPE(gobject_class),
158 G_SIGNAL_RUN_FIRST,
159 G_STRUCT_OFFSET(AdgEntityClass, parent_set),
160 NULL, NULL,
161 g_cclosure_marshal_VOID__OBJECT,
162 G_TYPE_NONE, 1, ADG_TYPE_ENTITY);
165 * AdgEntity::invalidate:
166 * @entity: an #AdgEntity
168 * The inverse of the rendering. Usually, invalidation causes the
169 * cache of @entity to be cleared. After a succesful invalidation
170 * the rendered flag is reset: you can access its state using
171 * adg_entity_get_rendered().
173 closure = g_cclosure_new(G_CALLBACK(real_invalidate),
174 (gpointer)0xdeadbeaf, NULL);
175 signals[INVALIDATE] = g_signal_newv("invalidate", ADG_TYPE_ENTITY,
176 G_SIGNAL_RUN_LAST, closure, NULL, NULL,
177 g_cclosure_marshal_VOID__VOID,
178 G_TYPE_NONE, 0, param_types);
181 * AdgEntity::render:
182 * @entity: an #AdgEntity
183 * @cr: a #cairo_t drawing context
185 * Causes the rendering of @entity on @cr. After a succesful rendering
186 * the rendered flag is set: you can access its state using
187 * adg_entity_get_rendered().
189 closure = g_cclosure_new(G_CALLBACK(real_render),
190 (gpointer)0xdeadbeaf, NULL);
191 param_types[0] = G_TYPE_POINTER;
192 signals[RENDER] = g_signal_newv("render", ADG_TYPE_ENTITY,
193 G_SIGNAL_RUN_LAST, closure, NULL, NULL,
194 g_cclosure_marshal_VOID__POINTER,
195 G_TYPE_NONE, 1, param_types);
198 static void
199 adg_entity_init(AdgEntity *entity)
201 AdgEntityPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(entity,
202 ADG_TYPE_ENTITY,
203 AdgEntityPrivate);
204 data->parent = NULL;
205 data->flags = 0;
206 cairo_matrix_init_identity(&data->local_map);
207 cairo_matrix_init_identity(&data->global_map);
208 data->hash_styles = NULL;
210 entity->data = data;
213 static void
214 dispose(GObject *object)
216 AdgEntity *entity;
217 AdgEntityPrivate *data;
219 entity = (AdgEntity *) object;
220 data = entity->data;
222 /* This call will emit a "notify" signal for parent.
223 * Consequentially, the references to the old parent is dropped. */
224 adg_entity_set_parent(entity, NULL);
226 if (data->hash_styles != NULL) {
227 g_hash_table_destroy(data->hash_styles);
228 data->hash_styles = NULL;
231 if (PARENT_OBJECT_CLASS->dispose != NULL)
232 PARENT_OBJECT_CLASS->dispose(object);
236 static void
237 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
239 AdgEntity *entity;
240 AdgEntityPrivate *data;
242 entity = (AdgEntity *) object;
243 data = entity->data;
245 switch (prop_id) {
246 case PROP_PARENT:
247 g_value_set_object(value, data->parent);
248 break;
249 case PROP_GLOBAL_MAP:
250 g_value_set_boxed(value, &data->global_map);
251 break;
252 case PROP_LOCAL_MAP:
253 g_value_set_boxed(value, &data->local_map);
254 break;
255 default:
256 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
257 break;
261 static void
262 set_property(GObject *object,
263 guint prop_id, const GValue *value, GParamSpec *pspec)
265 AdgEntity *entity = (AdgEntity *) object;
267 switch (prop_id) {
268 case PROP_PARENT:
269 set_parent(entity, g_value_get_object(value));
270 break;
271 case PROP_GLOBAL_MAP:
272 set_global_map(entity, g_value_get_boxed(value));
273 break;
274 case PROP_LOCAL_MAP:
275 set_local_map(entity, g_value_get_boxed(value));
276 break;
277 default:
278 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
279 break;
285 * adg_entity_get_parent:
286 * @entity: an #AdgEntity
288 * Gets the parent of @entity.
290 * Returns: the parent entity or %NULL on errors or if @entity is a toplevel
292 AdgEntity *
293 adg_entity_get_parent(AdgEntity *entity)
295 AdgEntityPrivate *data;
297 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
299 data = entity->data;
301 return data->parent;
305 * adg_entity_set_parent:
306 * @entity: an #AdgEntity
307 * @parent: the parent entity
309 * <note><para>
310 * This function is only useful in entity implementations.
311 * </para></note>
313 * Sets a new parent on @entity.
315 void
316 adg_entity_set_parent(AdgEntity *entity, AdgEntity *parent)
318 g_return_if_fail(ADG_IS_ENTITY(entity));
320 if (set_parent(entity, parent))
321 g_object_notify((GObject *) entity, "parent");
325 * adg_entity_get_canvas:
326 * @entity: an #AdgEntity
328 * Walks on the @entity hierarchy and gets the first parent of @entity that is
329 * of #AdgCanvas derived type.
331 * Returns: the requested canvas or %NULL on errors or if there is
332 * no #AdgCanvas in the @entity hierarchy
334 AdgCanvas *
335 adg_entity_get_canvas(AdgEntity *entity)
337 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
339 while (entity) {
340 if (ADG_IS_CANVAS(entity))
341 return (AdgCanvas *) entity;
343 entity = (AdgEntity *) adg_entity_get_parent(entity);
346 return NULL;
350 * adg_entity_get_rendered:
351 * @entity: an #AdgEntity object
353 * <note><para>
354 * This function is only useful in entity implementations.
355 * </para></note>
357 * Gets the rendered flag of @entity.
359 * Returns: the current rendered state
361 gboolean
362 adg_entity_get_rendered(AdgEntity *entity)
364 AdgEntityPrivate *data;
366 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
368 data = entity->data;
370 return ADG_ISSET(data->flags, RENDERED);
374 * adg_entity_set_rendered:
375 * @entity: an #AdgEntity object
376 * @rendered: new state for the rendered flag
378 * <note><para>
379 * This function is only useful in entity implementations.
380 * </para></note>
382 * Sets the rendered flag of @entity to @rendered.
384 void
385 adg_entity_set_rendered(AdgEntity *entity, gboolean rendered)
387 AdgEntityPrivate *data;
389 g_return_if_fail(ADG_IS_ENTITY(entity));
391 data = entity->data;
393 if (rendered)
394 ADG_SET(data->flags, RENDERED);
395 else
396 ADG_UNSET(data->flags, RENDERED);
400 * adg_entity_get_global_map:
401 * @entity: an #AdgEntity object
402 * @map: where to store the global map
404 * Gets the transformation to be used to compute the global matrix
405 * of @entity and store it in @map.
407 void
408 adg_entity_get_global_map(AdgEntity *entity, AdgMatrix *map)
410 AdgEntityPrivate *data;
412 g_return_if_fail(ADG_IS_ENTITY(entity));
413 g_return_if_fail(map != NULL);
415 data = entity->data;
416 adg_matrix_copy(map, &data->global_map);
420 * adg_entity_set_global_map:
421 * @entity: an #AdgEntity object
422 * @map: the new map
424 * Sets the new global transformation of @entity to @map:
425 * the old map is discarded. If @map is %NULL an identity
426 * matrix is implied.
428 void
429 adg_entity_set_global_map(AdgEntity *entity, const AdgMatrix *map)
431 g_return_if_fail(ADG_IS_ENTITY(entity));
433 set_global_map(entity, map);
434 g_object_notify((GObject *) entity, "global-map");
438 * adg_entity_transform_global_map:
439 * @entity: an #AdgEntity object
440 * @transformation: the transformation to apply
442 * Applies a transformation to the global map of @entity. This is
443 * equivalent to the following code:
445 * |[
446 * AdgMatrix tmp_map;
447 * adg_entity_get_global_map(entity, &tmp_map);
448 * cairo_matrix_multiply(&tmp_map, transformation, &tmp_map);
449 * adg_entity_set_global_map(entity, &tmp_map);
450 * ]|
452 void
453 adg_entity_transform_global_map(AdgEntity *entity,
454 const AdgMatrix *transformation)
456 AdgEntityPrivate *data;
458 g_return_if_fail(ADG_IS_ENTITY(entity));
459 g_return_if_fail(transformation != NULL);
461 data = entity->data;
463 cairo_matrix_multiply(&data->global_map, transformation, &data->global_map);
464 g_object_notify((GObject *) entity, "global-map");
468 * adg_entity_get_global_matrix:
469 * @entity: an #AdgEntity object
470 * @matrix: where to store the global matrix
472 * Computes the global matrix by combining all the global maps of the
473 * @entity hierarchy and stores the result in @matrix.
475 void
476 adg_entity_get_global_matrix(AdgEntity *entity, AdgMatrix *matrix)
478 g_return_if_fail(ADG_IS_ENTITY(entity));
479 g_return_if_fail(matrix != NULL);
481 ADG_ENTITY_GET_CLASS(entity)->get_global_matrix(entity, matrix);
485 * adg_entity_get_local_map:
486 * @entity: an #AdgEntity object
487 * @map: where to store the local map
489 * Gets the transformation to be used to compute the local matrix
490 * of @entity and store it in @map.
492 void
493 adg_entity_get_local_map(AdgEntity *entity, AdgMatrix *map)
495 AdgEntityPrivate *data;
497 g_return_if_fail(ADG_IS_ENTITY(entity));
498 g_return_if_fail(map != NULL);
500 data = entity->data;
501 adg_matrix_copy(map, &data->local_map);
505 * adg_entity_set_local_map:
506 * @entity: an #AdgEntity object
507 * @map: the new map
509 * Sets the new global transformation of @entity to @map:
510 * the old map is discarded. If @map is %NULL an identity
511 * matrix is implied.
513 void
514 adg_entity_set_local_map(AdgEntity *entity, const AdgMatrix *map)
516 g_return_if_fail(ADG_IS_ENTITY(entity));
518 set_local_map(entity, map);
519 g_object_notify((GObject *) entity, "local-map");
523 * adg_entity_transform_local_map:
524 * @entity: an #AdgEntity object
525 * @transformation: the transformation to apply
527 * Applies a transformation to the local map of @entity. This is
528 * equivalent to the following code:
530 * |[
531 * AdgMatrix tmp_map;
532 * adg_entity_get_local_map(entity, &tmp_map);
533 * cairo_matrix_multiply(&tmp_map, transformation, &tmp_map);
534 * adg_entity_set_local_map(entity, &tmp_map);
535 * ]|
537 void
538 adg_entity_transform_local_map(AdgEntity *entity,
539 const AdgMatrix *transformation)
541 AdgEntityPrivate *data;
543 g_return_if_fail(ADG_IS_ENTITY(entity));
544 g_return_if_fail(transformation != NULL);
546 data = entity->data;
548 cairo_matrix_multiply(&data->local_map, transformation, &data->local_map);
549 g_object_notify((GObject *) entity, "local-map");
553 * adg_entity_get_local_matrix:
554 * @entity: an #AdgEntity object
555 * @matrix: where to store the local matrix
557 * Computes the local matrix by combining all the local maps of the
558 * @entity hierarchy and stores the result in @matrix.
560 void
561 adg_entity_get_local_matrix(AdgEntity *entity, AdgMatrix *matrix)
563 g_return_if_fail(ADG_IS_ENTITY(entity));
564 g_return_if_fail(matrix != NULL);
566 ADG_ENTITY_GET_CLASS(entity)->get_local_matrix(entity, matrix);
570 * adg_entity_apply_local_matrix:
571 * @entity: an #AdgEntity object
572 * @cr: a #cairo_t drawing context
574 * Applies the local matrix of @entity BEFORE the current transformation
575 * matrix of @cr. This is a convenience function equivalent to:
577 * |[
578 * AdgMatrix local, ctm;
580 * adg_entity_get_local_matrix(entity, &local);
581 * cairo_get_matrix(cr, &ctm);
583 * cairo_matrix_multiply(&ctm, &ctm, &local);
584 * cairo_set_matrix(cr, &ctm);
585 * ]|
587 void
588 adg_entity_apply_local_matrix(AdgEntity *entity, cairo_t *cr)
590 AdgMatrix local, ctm;
592 g_return_if_fail(ADG_IS_ENTITY(entity));
593 g_return_if_fail(cr != NULL);
595 adg_entity_get_local_matrix(entity, &local);
596 cairo_get_matrix(cr, &ctm);
598 cairo_matrix_multiply(&ctm, &ctm, &local);
599 cairo_set_matrix(cr, &ctm);
603 * adg_entity_style:
604 * @entity: an #AdgEntity
605 * @dress: the dress of the style to get
607 * Gets the style to be used for @entity. @dress specifies the "type"
608 * of style to get.
610 * This method is supposed to always return a valid style instance,
611 * specifically the most appropriate one for this entity. The following
612 * sequence of checks is performed to get the proper @dress style,
613 * stopping at the first succesfull result:
615 * <orderedlist>
616 * <listitem>check if the style is defined directly by this entity type,
617 * as returned by adg_entity_get_style();</listitem>
618 * <listitem>check if @entity has a parent, in which case returns the
619 * adg_entity_style() of the parent;</listitem>
620 * <listitem>returns the main style with adg_dress_get_style().</listitem>
621 * </orderedlist>
623 * Returns: the requested style or %NULL on errors
625 AdgStyle *
626 adg_entity_style(AdgEntity *entity, AdgDress dress)
628 AdgStyle *style;
630 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
631 g_return_val_if_fail(dress != ADG_DRESS_UNDEFINED, NULL);
633 style = adg_entity_get_style(entity, dress);
635 if (style == NULL) {
636 AdgEntityPrivate *data = entity->data;
638 if (data->parent != NULL)
639 style = adg_entity_style(data->parent, dress);
640 else
641 style = adg_dress_get_style(dress);
644 return style;
648 * adg_entity_get_style:
649 * @entity: an #AdgEntity
650 * @dress: the dress of the style to get
652 * Gets the overriden @dress style from @entity. This is a kind
653 * of accessor function: to get the style to be used for rendering
654 * purpose, consider adg_entity_style().
656 * Returns: the requested style or %NULL if the @dress style
657 * is not overriden
659 AdgStyle *
660 adg_entity_get_style(AdgEntity *entity, AdgDress dress)
662 AdgEntityPrivate *data;
664 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
665 g_return_val_if_fail(dress != ADG_DRESS_UNDEFINED, NULL);
667 data = entity->data;
669 if (data->hash_styles == NULL)
670 return NULL;
672 return g_hash_table_lookup(data->hash_styles, GINT_TO_POINTER(dress));
676 * adg_entity_set_style:
677 * @entity: an #AdgEntity
678 * @dress: a dress style
679 * @style: the new style to use
681 * Overrides the style of @dress for @entity and its children.
682 * If @style is %NULL, any previous override is removed.
684 void
685 adg_entity_set_style(AdgEntity *entity, AdgDress dress, AdgStyle *style)
687 AdgEntityPrivate *data;
688 gpointer p_dress;
689 AdgStyle *old_style;
691 g_return_if_fail(ADG_IS_ENTITY(entity));
693 data = entity->data;
695 if (data->hash_styles == NULL && style == NULL)
696 return;
698 if (data->hash_styles == NULL)
699 data->hash_styles = g_hash_table_new_full(NULL, NULL,
700 NULL, g_object_unref);
702 p_dress = GINT_TO_POINTER(dress);
703 old_style = g_hash_table_lookup(data->hash_styles, p_dress);
705 if (style == old_style)
706 return;
708 if (style == NULL) {
709 g_hash_table_remove(data->hash_styles, p_dress);
710 } else {
711 g_object_ref(style);
712 g_hash_table_replace(data->hash_styles, p_dress, style);
717 * adg_entity_apply_dress:
718 * @entity: an #AdgEntity
719 * @dress: the dress style to apply
720 * @cr: a #cairo_t drawing context
722 * Convenient function to apply a @dress style (as returned by
723 * adg_entity_style()) to the @cr cairo context.
725 void
726 adg_entity_apply_dress(AdgEntity *entity, AdgDress dress, cairo_t *cr)
728 g_return_if_fail(ADG_IS_ENTITY(entity));
729 g_return_if_fail(cr != NULL);
731 adg_style_apply(adg_entity_style(entity, dress), cr);
735 * adg_entity_invalidate:
736 * @entity: an #AdgEntity
738 * Emits the "invalidate" signal on @entity and all its children, if any,
739 * so subsequent rendering will need a global recomputation.
741 void
742 adg_entity_invalidate(AdgEntity *entity)
744 g_return_if_fail(ADG_IS_ENTITY(entity));
746 g_signal_emit(entity, signals[INVALIDATE], 0, NULL);
750 * adg_entity_render:
751 * @entity: an #AdgEntity
752 * @cr: a #cairo_t drawing context
754 * Emits the "render" signal on @entity and all its children, if any,
755 * causing the rendering operation the @cr cairo context.
757 void
758 adg_entity_render(AdgEntity *entity, cairo_t *cr)
760 g_return_if_fail(ADG_IS_ENTITY(entity));
762 g_signal_emit(entity, signals[RENDER], 0, cr);
766 static gboolean
767 set_parent(AdgEntity *entity, AdgEntity *parent)
769 AdgEntityPrivate *data;
770 AdgEntity *old_parent;
772 data = entity->data;
773 old_parent = data->parent;
775 /* Check if parent has changed */
776 if (parent == old_parent)
777 return FALSE;
779 if (parent != NULL)
780 g_object_ref(parent);
782 data->parent = parent;
783 g_signal_emit(entity, signals[PARENT_SET], 0, old_parent);
785 if (old_parent != NULL)
786 g_object_unref(old_parent);
788 return TRUE;
791 static void
792 set_global_map(AdgEntity *entity, const AdgMatrix *map)
794 AdgEntityPrivate *data = entity->data;
796 if (map == NULL)
797 cairo_matrix_init_identity(&data->global_map);
798 else
799 adg_matrix_copy(&data->global_map, map);
802 static void
803 set_local_map(AdgEntity *entity, const AdgMatrix *map)
805 AdgEntityPrivate *data = entity->data;
807 if (map == NULL)
808 cairo_matrix_init_identity(&data->local_map);
809 else
810 adg_matrix_copy(&data->local_map, map);
813 static void
814 get_global_matrix(AdgEntity *entity, AdgMatrix *matrix)
816 AdgEntityPrivate *data = entity->data;
818 if (data->parent == NULL) {
819 adg_matrix_copy(matrix, &data->global_map);
820 } else {
821 adg_entity_get_global_matrix(data->parent, matrix);
822 cairo_matrix_multiply(matrix, &data->global_map, matrix);
826 static void
827 get_local_matrix(AdgEntity *entity, AdgMatrix *matrix)
829 AdgEntityPrivate *data = entity->data;
831 if (data->parent == NULL) {
832 adg_matrix_copy(matrix, &data->local_map);
833 } else {
834 adg_entity_get_local_matrix(data->parent, matrix);
835 cairo_matrix_multiply(matrix, &data->local_map, matrix);
839 static void
840 real_invalidate(AdgEntity *entity, gpointer user_data)
842 AdgEntityClass *klass;
843 AdgEntityPrivate *data;
845 g_assert(user_data == (gpointer) 0xdeadbeaf);
847 klass = ADG_ENTITY_GET_CLASS(entity);
848 if (klass->invalidate == NULL) {
849 /* Assume the entity does not have cache to be cleared */
850 } else if (!klass->invalidate(entity)) {
851 return;
854 data = entity->data;
855 ADG_UNSET(data->flags, RENDERED);
858 static void
859 real_render(AdgEntity *entity, cairo_t *cr, gpointer user_data)
861 AdgEntityClass *klass;
862 AdgEntityPrivate *data;
864 g_assert(user_data == (gpointer) 0xdeadbeaf);
866 klass = ADG_ENTITY_GET_CLASS(entity);
867 if (klass->render == NULL) {
868 /* The render method must be defined */
869 g_warning("%s: `render' method not implemented for type `%s'",
870 G_STRLOC, g_type_name(G_OBJECT_TYPE(entity)));
871 return;
874 data = entity->data;
876 cairo_save(cr);
877 cairo_transform(cr, &data->global_map);
879 if (klass->render(entity, cr))
880 ADG_SET(data->flags, RENDERED);
882 cairo_restore(cr);