adg: provide example on how to customize a style
[adg.git] / src / adg / adg-table.c
blob31c588174df5e3d095e761d9f00c50b8adafb774
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2017 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-table
23 * @short_description: A tabular entity
25 * The #AdgTable is the entity to be used for rendering data arranged
26 * in tabular evironments.
28 * To define a table, you should add to it a serie of one or more
29 * #AdgTableRow by using the #AdgTableRow specific APIs.
31 * <note><para>
32 * By default, the #AdgEntity:local-mix property is set to
33 * #ADG_MIX_DISABLED on #AdgTable entities.
34 * </para></note>
36 * Since: 1.0
37 **/
39 /**
40 * AdgTable:
42 * All fields are private and should not be used directly.
43 * Use its public methods instead.
45 * Since: 1.0
46 **/
49 #include "adg-internal.h"
51 #include "adg-model.h"
52 #include "adg-trail.h"
53 #include "adg-style.h"
54 #include "adg-table-style.h"
55 #include "adg-path.h"
56 #include "adg-stroke.h"
57 #include "adg-container.h"
58 #include "adg-alignment.h"
59 #include "adg-entity-private.h"
60 #include "adg-dress.h"
61 #include "adg-param-dress.h"
63 #include "adg-table.h"
64 #include "adg-table-private.h"
65 #include "adg-table-row.h"
66 #include "adg-table-cell.h"
69 #define _ADG_OLD_OBJECT_CLASS ((GObjectClass *) adg_table_parent_class)
70 #define _ADG_OLD_ENTITY_CLASS ((AdgEntityClass *) adg_table_parent_class)
73 G_DEFINE_TYPE(AdgTable, adg_table, ADG_TYPE_ENTITY)
75 enum {
76 PROP_0,
77 PROP_TABLE_DRESS,
78 PROP_HAS_FRAME
81 typedef struct {
82 GCallback callback;
83 gpointer user_data;
84 } AdgClosure;
88 static void _adg_dispose (GObject *object);
89 static void _adg_finalize (GObject *object);
90 static void _adg_get_property (GObject *object,
91 guint param_id,
92 GValue *value,
93 GParamSpec *pspec);
94 static void _adg_set_property (GObject *object,
95 guint param_id,
96 const GValue *value,
97 GParamSpec *pspec);
98 static void _adg_destroy (AdgEntity *entity);
99 static void _adg_global_changed (AdgEntity *entity);
100 static void _adg_local_changed (AdgEntity *entity);
101 static void _adg_invalidate (AdgEntity *entity);
102 static void _adg_arrange (AdgEntity *entity);
103 static void _adg_arrange_grid (AdgEntity *entity);
104 static void _adg_arrange_frame (AdgEntity *entity,
105 const CpmlExtents *extents);
106 static void _adg_render (AdgEntity *entity,
107 cairo_t *cr);
108 static void _adg_propagate (AdgTable *table,
109 const gchar *detailed_signal,
110 ...);
111 static void _adg_foreach_row (AdgTableRow *table_row,
112 const AdgClosure *closure);
113 static void _adg_append_frame (AdgTableCell *table_cell,
114 AdgPath *path);
115 static void _adg_proxy_signal (AdgTableCell *table_cell,
116 AdgProxyData *proxy_data);
117 static gboolean _adg_value_match (gpointer key,
118 gpointer value,
119 gpointer user_data);
122 static void
123 adg_table_class_init(AdgTableClass *klass)
125 GObjectClass *gobject_class;
126 AdgEntityClass *entity_class;
127 GParamSpec *param;
129 gobject_class = (GObjectClass *) klass;
130 entity_class = (AdgEntityClass *) klass;
132 g_type_class_add_private(klass, sizeof(AdgTablePrivate));
134 gobject_class->dispose = _adg_dispose;
135 gobject_class->finalize = _adg_finalize;
136 gobject_class->get_property = _adg_get_property;
137 gobject_class->set_property = _adg_set_property;
139 entity_class->destroy = _adg_destroy;
140 entity_class->global_changed = _adg_global_changed;
141 entity_class->local_changed = _adg_local_changed;
142 entity_class->invalidate = _adg_invalidate;
143 entity_class->arrange = _adg_arrange;
144 entity_class->render = _adg_render;
146 param = adg_param_spec_dress("table-dress",
147 P_("Table Dress"),
148 P_("The dress to use for stroking this entity"),
149 ADG_DRESS_TABLE,
150 G_PARAM_READWRITE);
151 g_object_class_install_property(gobject_class, PROP_TABLE_DRESS, param);
153 param = g_param_spec_boolean("has-frame",
154 P_("Has Frame Flag"),
155 P_("If enabled, a frame using the proper dress found in this table style will be drawn around the table extents"),
156 TRUE,
157 G_PARAM_READWRITE);
158 g_object_class_install_property(gobject_class, PROP_HAS_FRAME, param);
161 static void
162 adg_table_init(AdgTable *table)
164 AdgTablePrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(table,
165 ADG_TYPE_TABLE,
166 AdgTablePrivate);
167 AdgEntityPrivate *entity_data = ((AdgEntity *) table)->data;
169 data->table_dress = ADG_DRESS_TABLE;
170 data->has_frame = TRUE;
172 data->table_style = NULL;
173 data->grid = NULL;
174 data->frame = NULL;
175 data->rows = NULL;
176 data->cell_names = NULL;
178 table->data = data;
180 /* Initialize to custom default some AdgEntity field by directly
181 * accessing the private struct to avoid notify signal emissions
183 entity_data->local_mix = ADG_MIX_DISABLED;
186 static void
187 _adg_dispose(GObject *object)
189 AdgTable *table = (AdgTable *) object;
190 AdgTablePrivate *data = table->data;
192 adg_table_invalidate_grid(table);
194 if (data->frame) {
195 g_object_unref(data->frame);
196 data->frame = NULL;
199 if (data->rows) {
200 adg_table_foreach_cell(table,
201 (GCallback) adg_table_cell_dispose, NULL);
202 data->rows = NULL;
205 if (_ADG_OLD_OBJECT_CLASS->dispose)
206 _ADG_OLD_OBJECT_CLASS->dispose(object);
209 static void
210 _adg_finalize(GObject *object)
212 AdgTable *table;
213 AdgTablePrivate *data;
215 table = (AdgTable *) object;
216 data = table->data;
218 if (data->rows) {
219 g_slist_foreach(data->rows, (GFunc) adg_table_row_free, NULL);
220 g_slist_free(data->rows);
223 if (data->cell_names)
224 g_hash_table_destroy(data->cell_names);
226 if (_ADG_OLD_OBJECT_CLASS->finalize)
227 _ADG_OLD_OBJECT_CLASS->finalize(object);
230 static void
231 _adg_get_property(GObject *object, guint prop_id,
232 GValue *value, GParamSpec *pspec)
234 AdgTablePrivate *data = ((AdgTable *) object)->data;
236 switch (prop_id) {
237 case PROP_TABLE_DRESS:
238 g_value_set_enum(value, data->table_dress);
239 break;
240 case PROP_HAS_FRAME:
241 g_value_set_boolean(value, data->has_frame);
242 break;
243 default:
244 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
245 break;
249 static void
250 _adg_set_property(GObject *object, guint prop_id,
251 const GValue *value, GParamSpec *pspec)
253 AdgTablePrivate *data = ((AdgTable *) object)->data;
255 switch (prop_id) {
256 case PROP_TABLE_DRESS:
257 data->table_dress = g_value_get_enum(value);
258 break;
259 case PROP_HAS_FRAME:
260 data->has_frame = g_value_get_boolean(value);
261 break;
262 default:
263 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
264 break;
270 * adg_table_new:
272 * Creates a new empty table entity.
274 * Returns: the newly created table entity
276 * Since: 1.0
278 AdgTable *
279 adg_table_new(void)
281 return g_object_new(ADG_TYPE_TABLE, NULL);
285 * adg_table_insert:
286 * @table: an #AdgTable
287 * @table_row: a valid #AdgTableRow
288 * @before_row: (allow-none): an #AdgTableRow or <constant>NULL</constant>
290 * Inserts @table_row inside the rows list of @table. If @before_row
291 * is specified, @table_row is inserted before it.
293 * Since: 1.0
295 void
296 adg_table_insert(AdgTable *table, AdgTableRow *table_row,
297 AdgTableRow *before_row)
299 AdgTablePrivate *data;
301 g_return_if_fail(ADG_IS_TABLE(table));
302 g_return_if_fail(table_row != NULL);
304 data = table->data;
306 if (before_row == NULL) {
307 data->rows = g_slist_append(data->rows, table_row);
308 } else {
309 GSList *before = g_slist_find(data->rows, before_row);
311 /* This MUST be present, otherwise something really bad happened */
312 g_return_if_fail(before != NULL);
314 data->rows = g_slist_insert_before(data->rows, before, table_row);
319 * adg_table_remove:
320 * @table: an #AdgTable
321 * @table_row: a valid #AdgTableRow
323 * Removes @table_row from list of rows of @table.
325 * Since: 1.0
327 void
328 adg_table_remove(AdgTable *table, AdgTableRow *table_row)
330 AdgTablePrivate *data;
332 g_return_if_fail(ADG_IS_TABLE(table));
333 g_return_if_fail(table_row != NULL);
335 data = table->data;
336 data->rows = g_slist_remove(data->rows, table_row);
340 * adg_table_foreach:
341 * @table: an #AdgTable
342 * @callback: (scope call): a callback
343 * @user_data: callback user data
345 * Invokes @callback on each row of @table.
346 * The callback should be declared as:
348 * <informalexample><programlisting language="C">
349 * void callback(AdgTableRow *table_row, gpointer user_data);
350 * </programlisting></informalexample>
352 * Since: 1.0
354 void
355 adg_table_foreach(AdgTable *table, GCallback callback, gpointer user_data)
357 AdgTablePrivate *data = table->data;
359 g_return_if_fail(table != NULL);
360 g_return_if_fail(callback != NULL);
362 g_slist_foreach(data->rows, (GFunc) callback, user_data);
366 * adg_table_foreach_cell:
367 * @table: an #AdgTable
368 * @callback: (scope call): a callback
369 * @user_data: callback user data
371 * Invokes @callback on each cell of @table.
372 * The callback should be declared as:
374 * <informalexample><programlisting language="C">
375 * void callback(AdgTableCell *table_cell, gpointer user_data);
376 * </programlisting></informalexample>
378 * Since: 1.0
380 void
381 adg_table_foreach_cell(AdgTable *table,
382 GCallback callback, gpointer user_data)
384 AdgClosure closure = { callback, user_data };
385 adg_table_foreach(table, (GCallback) _adg_foreach_row, &closure);
389 * adg_table_set_cell:
390 * @table: an #AdgTable
391 * @name: the name of the cell
392 * @table_cell: the named cell
394 * Binds @table_cell to @name, so it can be accessed by name later
395 * with adg_table_get_cell(). Internally the binding is handled with
396 * an hash table, so accessing the cell this way is O(1).
398 * If @name is <constant>NULL</constant>, any binding to @table_cell
399 * will be removed. This is quite inefficient because the whole hash
400 * table must be scanned.
402 * If @table_cell is <constant>NULL</constant>, the key with @name
403 * in the hash table will be removed.
405 * Both @name and @table_cell cannot be <constant>NULL</constant> at the same time.
407 * Since: 1.0
409 void
410 adg_table_set_cell(AdgTable *table, const gchar *name,
411 AdgTableCell *table_cell)
413 AdgTablePrivate *data;
415 g_return_if_fail(ADG_IS_TABLE(table));
416 g_return_if_fail(name != NULL || table_cell != NULL);
418 data = table->data;
420 if (data->cell_names == NULL) {
421 /* Check if trying to remove from an empty hash table */
422 if (name == NULL || table_cell == NULL)
423 return;
425 data->cell_names = g_hash_table_new_full(g_str_hash, g_str_equal,
426 g_free, NULL);
429 if (name == NULL) {
430 /* _adg_value_match() will return the key in user_data[1] */
431 gpointer user_data[] = { table_cell, NULL };
432 g_hash_table_find(data->cell_names, _adg_value_match, user_data);
433 g_hash_table_remove(data->cell_names, user_data[1]);
434 } else if (table_cell == NULL) {
435 g_hash_table_remove(data->cell_names, name);
436 } else {
437 g_hash_table_insert(data->cell_names, g_strdup(name), table_cell);
442 * adg_table_get_table_style:
443 * @table: an #AdgTable
445 * Gets the #AdgTableStyle explicitely set on @table. This is a kind
446 * of accessor function: for rendering purpose use adg_entity_style()
447 * instead. The returned object is owned by @table and should not be
448 * freed or modified.
450 * Returns: (transfer none): the requested style or <constant>NULL</constant> on errors.
452 * Since: 1.0
454 AdgStyle *
455 adg_table_get_table_style(AdgTable *table)
457 AdgTablePrivate *data;
459 g_return_val_if_fail(ADG_IS_TABLE(table), NULL);
461 data = table->data;
462 return (AdgStyle *) data->table_style;
466 * adg_table_get_cell:
467 * @table: an #AdgTable
468 * @name: the name of a cell
470 * Gets the cell named @name inside @table. Only named cells
471 * can be retrieved by this method.
473 * The returned cell is owned by @table and must not be
474 * modified or freed.
476 * Returns: (transfer none): the requested cell or <constant>NULL</constant> if not found.
478 * Since: 1.0
480 AdgTableCell *
481 adg_table_get_cell(AdgTable *table, const gchar *name)
483 AdgTablePrivate *data;
485 g_return_val_if_fail(ADG_IS_TABLE(table), NULL);
487 data = table->data;
489 if (data->cell_names == NULL)
490 return NULL;
492 return g_hash_table_lookup(data->cell_names, name);
496 * adg_table_set_table_dress:
497 * @table: an #AdgTable
498 * @dress: the new #AdgDress to use
500 * Sets a new table dress for rendering @table. The new dress
501 * must be related to the original dress for this property:
502 * you cannot set a dress used for line styles to a dress
503 * managing fonts.
505 * The check is done by calling adg_dress_are_related() with
506 * @dress and the previous dress as arguments. Check out its
507 * documentation for details on what is a related dress.
509 * Since: 1.0
511 void
512 adg_table_set_table_dress(AdgTable *table, AdgDress dress)
514 g_return_if_fail(ADG_IS_TABLE(table));
515 g_object_set(table, "table-dress", dress, NULL);
519 * adg_table_get_table_dress:
520 * @table: an #AdgTable
522 * Gets the table dress to be used in rendering @table.
524 * Returns: (transfer none): the current table dress.
526 * Since: 1.0
528 AdgDress
529 adg_table_get_table_dress(AdgTable *table)
531 AdgTablePrivate *data;
533 g_return_val_if_fail(ADG_IS_TABLE(table), ADG_DRESS_UNDEFINED);
535 data = table->data;
537 return data->table_dress;
541 * adg_table_switch_frame:
542 * @table: an #AdgTable
543 * @new_state: the new state of the frame
545 * Sets the #AdgTable:has-frame property: <constant>TRUE</constant>
546 * will draw a frame around the whole table using the
547 * #AdgTableStyle:frame-dress dress of the table style.
549 * Since: 1.0
551 void
552 adg_table_switch_frame(AdgTable *table, gboolean new_state)
554 g_return_if_fail(ADG_IS_TABLE(table));
555 g_object_set(table, "has-frame", new_state, NULL);
559 * adg_table_has_frame:
560 * @table: an #AdgTable
562 * Returns the state of the #AdgTable:has-frame property.
564 * Returns: the current state.
566 * Since: 1.0
568 gboolean
569 adg_table_has_frame(AdgTable *table)
571 AdgTablePrivate *data;
573 g_return_val_if_fail(ADG_IS_TABLE(table), FALSE);
575 data = table->data;
577 return data->has_frame;
581 * adg_table_invalidate_grid:
582 * @table: an #AdgTable
584 * <note><para>
585 * This method is only useful in table children implementation.
586 * </para></note>
588 * Clears the internal grid cache, effectively forcing its
589 * regeneration next time the #AdgEntity::arrange signal is emitted.
591 void
592 adg_table_invalidate_grid(AdgTable *table)
594 AdgTablePrivate *data;
596 g_return_if_fail(ADG_IS_TABLE(table));
598 data = table->data;
600 if (data->grid) {
601 g_object_unref(data->grid);
602 data->grid = NULL;
607 static void
608 _adg_destroy(AdgEntity *entity)
610 _adg_propagate((AdgTable *) entity, "destroy");
612 if (_ADG_OLD_ENTITY_CLASS->destroy)
613 _ADG_OLD_ENTITY_CLASS->destroy(entity);
616 static void
617 _adg_global_changed(AdgEntity *entity)
619 if (_ADG_OLD_ENTITY_CLASS->global_changed)
620 _ADG_OLD_ENTITY_CLASS->global_changed(entity);
622 _adg_propagate((AdgTable *) entity, "global-changed");
625 static void
626 _adg_local_changed(AdgEntity *entity)
628 if (_ADG_OLD_ENTITY_CLASS->local_changed)
629 _ADG_OLD_ENTITY_CLASS->local_changed(entity);
631 _adg_propagate((AdgTable *) entity, "local-changed");
634 static void
635 _adg_invalidate(AdgEntity *entity)
637 _adg_propagate((AdgTable *) entity, "invalidate");
640 static void
641 _adg_arrange(AdgEntity *entity)
643 AdgTable *table;
644 AdgTablePrivate *data;
645 CpmlExtents extents = { 0 };
646 CpmlExtents row_layout;
647 const CpmlExtents *row_extents;
648 const CpmlPair *spacing;
649 const CpmlPair *size;
650 GSList *row_node;
651 AdgTableRow *row;
653 table = (AdgTable *) entity;
654 data = table->data;
656 /* Resolve the table style */
657 if (data->table_style == NULL)
658 data->table_style = (AdgTableStyle *)
659 adg_entity_style(entity, data->table_dress);
661 spacing = adg_table_style_get_cell_spacing(data->table_style);
663 /* Compute the size of the table */
664 for (row_node = data->rows; row_node; row_node = row_node->next) {
665 row = row_node->data;
666 size = adg_table_row_size_request(row);
668 if (size->x > extents.size.x)
669 extents.size.x = size->x;
670 extents.size.y += size->y;
673 /* Arrange the layout of the table components */
674 row_layout.is_defined = 1;
675 row_layout.org.x = extents.org.x;
676 row_layout.org.y = extents.org.y + spacing->y;
677 row_layout.size.x = extents.size.x;
678 row_layout.size.y = -1;
679 for (row_node = data->rows; row_node; row_node = row_node->next) {
680 row = row_node->data;
681 row_extents = adg_table_row_arrange(row, &row_layout);
682 row_layout.org.y += row_extents->size.y + spacing->y;
685 _adg_arrange_grid(entity);
686 _adg_arrange_frame(entity, &extents);
688 extents.is_defined = TRUE;
689 cpml_extents_transform(&extents, adg_entity_get_global_matrix(entity));
690 cpml_extents_transform(&extents, adg_entity_get_local_matrix(entity));
691 adg_entity_set_extents(entity, &extents);
694 static void
695 _adg_arrange_grid(AdgEntity *entity)
697 AdgTable *table;
698 AdgTablePrivate *data;
699 AdgPath *path;
700 AdgTrail *trail;
701 AdgDress dress;
703 table = (AdgTable *) entity;
704 data = table->data;
706 if (data->grid)
707 return;
709 path = adg_path_new();
710 trail = (AdgTrail *) path;
712 adg_table_foreach_cell(table, (GCallback) _adg_append_frame, path);
714 if (!adg_trail_get_extents(trail)->is_defined)
715 return;
717 dress = adg_table_style_get_grid_dress(data->table_style);
718 data->grid = g_object_new(ADG_TYPE_STROKE,
719 "line-dress", dress,
720 "trail", trail,
721 "parent", entity,
722 NULL);
723 adg_entity_arrange((AdgEntity *) data->grid);
726 static void
727 _adg_arrange_frame(AdgEntity *entity, const CpmlExtents *extents)
729 AdgTablePrivate *data;
730 AdgPath *path;
731 AdgTrail *trail;
732 CpmlPair pair;
733 AdgDress dress;
735 data = ((AdgTable *) entity)->data;
737 if (data->frame || !data->has_frame)
738 return;
740 path = adg_path_new();
741 trail = (AdgTrail *) path;
743 cpml_pair_copy(&pair, &extents->org);
744 adg_path_move_to(path, &pair);
745 pair.x += extents->size.x;
746 adg_path_line_to(path, &pair);
747 pair.y += extents->size.y;
748 adg_path_line_to(path, &pair);
749 pair.x -= extents->size.x;
750 adg_path_line_to(path, &pair);
751 adg_path_close(path);
753 dress = adg_table_style_get_frame_dress(data->table_style);
754 data->frame = g_object_new(ADG_TYPE_STROKE,
755 "line-dress", dress,
756 "trail", trail,
757 "parent", entity,
758 NULL);
759 adg_entity_arrange((AdgEntity *) data->frame);
762 static void
763 _adg_render(AdgEntity *entity, cairo_t *cr)
765 AdgTablePrivate *data = ((AdgTable *) entity)->data;
767 adg_style_apply((AdgStyle *) data->table_style, entity, cr);
769 _adg_propagate((AdgTable *) entity, "render", cr);
772 static void
773 _adg_propagate(AdgTable *table, const gchar *detailed_signal, ...)
775 va_list var_copy;
776 AdgTablePrivate *data;
777 AdgProxyData proxy_data;
779 if (!g_signal_parse_name(detailed_signal, G_TYPE_FROM_INSTANCE(table),
780 &proxy_data.signal_id, &proxy_data.detail, FALSE)) {
781 g_return_if_reached();
784 va_start(proxy_data.var_args, detailed_signal);
785 data = table->data;
787 if (data->frame) {
788 G_VA_COPY(var_copy, proxy_data.var_args);
789 g_signal_emit_valist(data->frame, proxy_data.signal_id,
790 proxy_data.detail, var_copy);
793 if (data->grid) {
794 G_VA_COPY(var_copy, proxy_data.var_args);
795 g_signal_emit_valist(data->grid, proxy_data.signal_id,
796 proxy_data.detail, var_copy);
799 adg_table_foreach_cell(table, (GCallback) _adg_proxy_signal, &proxy_data);
800 va_end(proxy_data.var_args);
803 static void
804 _adg_foreach_row(AdgTableRow *table_row, const AdgClosure *closure)
806 adg_table_row_foreach(table_row, closure->callback, closure->user_data);
809 static void
810 _adg_append_frame(AdgTableCell *table_cell, AdgPath *path)
812 CpmlPair pair;
813 const CpmlExtents *extents;
815 if (! adg_table_cell_has_frame(table_cell))
816 return;
818 extents = adg_table_cell_get_extents(table_cell);
820 cpml_pair_copy(&pair, &extents->org);
821 adg_path_move_to(path, &pair);
822 pair.x += extents->size.x;
823 adg_path_line_to(path, &pair);
824 pair.y += extents->size.y;
825 adg_path_line_to(path, &pair);
826 pair.x -= extents->size.x;
827 adg_path_line_to(path, &pair);
828 adg_path_close(path);
831 static void
832 _adg_proxy_signal(AdgTableCell *table_cell, AdgProxyData *proxy_data)
834 AdgEntity *entity;
835 AdgAlignment *alignment;
836 va_list var_copy;
838 entity = adg_table_cell_title(table_cell);
839 if (entity) {
840 alignment = (AdgAlignment *) adg_entity_get_parent(entity);
841 G_VA_COPY(var_copy, proxy_data->var_args);
842 g_signal_emit_valist(alignment, proxy_data->signal_id,
843 proxy_data->detail, var_copy);
846 entity = adg_table_cell_value(table_cell);
847 if (entity) {
848 alignment = (AdgAlignment *) adg_entity_get_parent(entity);
849 G_VA_COPY(var_copy, proxy_data->var_args);
850 g_signal_emit_valist(alignment, proxy_data->signal_id,
851 proxy_data->detail, var_copy);
855 static gboolean
856 _adg_value_match(gpointer key, gpointer value, gpointer user_data)
858 gpointer *array = user_data;
860 if (value == array[0]) {
861 array[1] = key;
862 return TRUE;
864 return FALSE;