adg: use G_PRIVATE_ADD and friends
[adg.git] / src / adg / adg-table.c
blob05a8f1780b8277fd9005eeb2569b161e369e2e2a
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2019 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-dress.h"
60 #include "adg-param-dress.h"
62 #include "adg-table.h"
63 #include "adg-table-private.h"
64 #include "adg-table-row.h"
65 #include "adg-table-cell.h"
68 #define _ADG_OLD_OBJECT_CLASS ((GObjectClass *) adg_table_parent_class)
69 #define _ADG_OLD_ENTITY_CLASS ((AdgEntityClass *) adg_table_parent_class)
72 G_DEFINE_TYPE_WITH_PRIVATE(AdgTable, adg_table, ADG_TYPE_ENTITY)
74 enum {
75 PROP_0,
76 PROP_TABLE_DRESS,
77 PROP_HAS_FRAME
80 typedef struct {
81 GCallback callback;
82 gpointer user_data;
83 } AdgClosure;
87 static void _adg_dispose (GObject *object);
88 static void _adg_finalize (GObject *object);
89 static void _adg_get_property (GObject *object,
90 guint param_id,
91 GValue *value,
92 GParamSpec *pspec);
93 static void _adg_set_property (GObject *object,
94 guint param_id,
95 const GValue *value,
96 GParamSpec *pspec);
97 static void _adg_destroy (AdgEntity *entity);
98 static void _adg_global_changed (AdgEntity *entity);
99 static void _adg_local_changed (AdgEntity *entity);
100 static void _adg_invalidate (AdgEntity *entity);
101 static void _adg_arrange (AdgEntity *entity);
102 static void _adg_arrange_grid (AdgEntity *entity);
103 static void _adg_arrange_frame (AdgEntity *entity,
104 const CpmlExtents *extents);
105 static void _adg_render (AdgEntity *entity,
106 cairo_t *cr);
107 static void _adg_propagate (AdgTable *table,
108 const gchar *detailed_signal,
109 ...);
110 static void _adg_foreach_row (AdgTableRow *table_row,
111 const AdgClosure *closure);
112 static void _adg_append_frame (AdgTableCell *table_cell,
113 AdgPath *path);
114 static void _adg_proxy_signal (AdgTableCell *table_cell,
115 AdgProxyData *proxy_data);
116 static gboolean _adg_value_match (gpointer key,
117 gpointer value,
118 gpointer user_data);
121 static void
122 adg_table_class_init(AdgTableClass *klass)
124 GObjectClass *gobject_class;
125 AdgEntityClass *entity_class;
126 GParamSpec *param;
128 gobject_class = (GObjectClass *) klass;
129 entity_class = (AdgEntityClass *) klass;
131 gobject_class->dispose = _adg_dispose;
132 gobject_class->finalize = _adg_finalize;
133 gobject_class->get_property = _adg_get_property;
134 gobject_class->set_property = _adg_set_property;
136 entity_class->destroy = _adg_destroy;
137 entity_class->global_changed = _adg_global_changed;
138 entity_class->local_changed = _adg_local_changed;
139 entity_class->invalidate = _adg_invalidate;
140 entity_class->arrange = _adg_arrange;
141 entity_class->render = _adg_render;
143 param = adg_param_spec_dress("table-dress",
144 P_("Table Dress"),
145 P_("The dress to use for stroking this entity"),
146 ADG_DRESS_TABLE,
147 G_PARAM_READWRITE);
148 g_object_class_install_property(gobject_class, PROP_TABLE_DRESS, param);
150 param = g_param_spec_boolean("has-frame",
151 P_("Has Frame Flag"),
152 P_("If enabled, a frame using the proper dress found in this table style will be drawn around the table extents"),
153 TRUE,
154 G_PARAM_READWRITE);
155 g_object_class_install_property(gobject_class, PROP_HAS_FRAME, param);
158 static void
159 adg_table_init(AdgTable *table)
161 AdgTablePrivate *data = adg_table_get_instance_private(table);
162 data->table_dress = ADG_DRESS_TABLE;
163 data->has_frame = TRUE;
164 data->table_style = NULL;
165 data->grid = NULL;
166 data->frame = NULL;
167 data->rows = NULL;
168 data->cell_names = NULL;
169 adg_entity_set_local_mix((AdgEntity *) table, ADG_MIX_DISABLED);
172 static void
173 _adg_dispose(GObject *object)
175 AdgTable *table = (AdgTable *) object;
176 AdgTablePrivate *data = adg_table_get_instance_private(table);
178 adg_table_invalidate_grid(table);
180 if (data->frame) {
181 g_object_unref(data->frame);
182 data->frame = NULL;
185 if (data->rows) {
186 adg_table_foreach_cell(table,
187 (GCallback) adg_table_cell_dispose, NULL);
188 data->rows = NULL;
191 if (_ADG_OLD_OBJECT_CLASS->dispose)
192 _ADG_OLD_OBJECT_CLASS->dispose(object);
195 static void
196 _adg_finalize(GObject *object)
198 AdgTablePrivate *data = adg_table_get_instance_private((AdgTable *) object);
200 if (data->rows) {
201 g_slist_foreach(data->rows, (GFunc) adg_table_row_free, NULL);
202 g_slist_free(data->rows);
205 if (data->cell_names)
206 g_hash_table_destroy(data->cell_names);
208 if (_ADG_OLD_OBJECT_CLASS->finalize)
209 _ADG_OLD_OBJECT_CLASS->finalize(object);
212 static void
213 _adg_get_property(GObject *object, guint prop_id,
214 GValue *value, GParamSpec *pspec)
216 AdgTablePrivate *data = adg_table_get_instance_private((AdgTable *) object);
218 switch (prop_id) {
219 case PROP_TABLE_DRESS:
220 g_value_set_enum(value, data->table_dress);
221 break;
222 case PROP_HAS_FRAME:
223 g_value_set_boolean(value, data->has_frame);
224 break;
225 default:
226 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
227 break;
231 static void
232 _adg_set_property(GObject *object, guint prop_id,
233 const GValue *value, GParamSpec *pspec)
235 AdgTablePrivate *data = adg_table_get_instance_private((AdgTable *) object);
237 switch (prop_id) {
238 case PROP_TABLE_DRESS:
239 data->table_dress = g_value_get_enum(value);
240 break;
241 case PROP_HAS_FRAME:
242 data->has_frame = g_value_get_boolean(value);
243 break;
244 default:
245 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
246 break;
252 * adg_table_new:
254 * Creates a new empty table entity.
256 * Returns: the newly created table entity
258 * Since: 1.0
260 AdgTable *
261 adg_table_new(void)
263 return g_object_new(ADG_TYPE_TABLE, NULL);
267 * adg_table_insert:
268 * @table: an #AdgTable
269 * @table_row: a valid #AdgTableRow
270 * @before_row: (allow-none): an #AdgTableRow or <constant>NULL</constant>
272 * Inserts @table_row inside the rows list of @table. If @before_row
273 * is specified, @table_row is inserted before it.
275 * Since: 1.0
277 void
278 adg_table_insert(AdgTable *table, AdgTableRow *table_row,
279 AdgTableRow *before_row)
281 AdgTablePrivate *data;
283 g_return_if_fail(ADG_IS_TABLE(table));
284 g_return_if_fail(table_row != NULL);
286 data = adg_table_get_instance_private(table);
288 if (before_row == NULL) {
289 data->rows = g_slist_append(data->rows, table_row);
290 } else {
291 GSList *before = g_slist_find(data->rows, before_row);
293 /* This MUST be present, otherwise something really bad happened */
294 g_return_if_fail(before != NULL);
296 data->rows = g_slist_insert_before(data->rows, before, table_row);
301 * adg_table_remove:
302 * @table: an #AdgTable
303 * @table_row: a valid #AdgTableRow
305 * Removes @table_row from list of rows of @table.
307 * Since: 1.0
309 void
310 adg_table_remove(AdgTable *table, AdgTableRow *table_row)
312 AdgTablePrivate *data;
314 g_return_if_fail(ADG_IS_TABLE(table));
315 g_return_if_fail(table_row != NULL);
317 data = adg_table_get_instance_private(table);
318 data->rows = g_slist_remove(data->rows, table_row);
322 * adg_table_foreach:
323 * @table: an #AdgTable
324 * @callback: (scope call): a callback
325 * @user_data: callback user data
327 * Invokes @callback on each row of @table.
328 * The callback should be declared as:
330 * <informalexample><programlisting language="C">
331 * void callback(AdgTableRow *table_row, gpointer user_data);
332 * </programlisting></informalexample>
334 * Since: 1.0
336 void
337 adg_table_foreach(AdgTable *table, GCallback callback, gpointer user_data)
339 AdgTablePrivate *data;
341 g_return_if_fail(table != NULL);
342 g_return_if_fail(callback != NULL);
344 data = adg_table_get_instance_private(table);
345 g_slist_foreach(data->rows, (GFunc) callback, user_data);
349 * adg_table_foreach_cell:
350 * @table: an #AdgTable
351 * @callback: (scope call): a callback
352 * @user_data: callback user data
354 * Invokes @callback on each cell of @table.
355 * The callback should be declared as:
357 * <informalexample><programlisting language="C">
358 * void callback(AdgTableCell *table_cell, gpointer user_data);
359 * </programlisting></informalexample>
361 * Since: 1.0
363 void
364 adg_table_foreach_cell(AdgTable *table,
365 GCallback callback, gpointer user_data)
367 AdgClosure closure = { callback, user_data };
368 adg_table_foreach(table, (GCallback) _adg_foreach_row, &closure);
372 * adg_table_set_cell:
373 * @table: an #AdgTable
374 * @name: the name of the cell
375 * @table_cell: the named cell
377 * Binds @table_cell to @name, so it can be accessed by name later
378 * with adg_table_get_cell(). Internally the binding is handled with
379 * an hash table, so accessing the cell this way is O(1).
381 * If @name is <constant>NULL</constant>, any binding to @table_cell
382 * will be removed. This is quite inefficient because the whole hash
383 * table must be scanned.
385 * If @table_cell is <constant>NULL</constant>, the key with @name
386 * in the hash table will be removed.
388 * Both @name and @table_cell cannot be <constant>NULL</constant> at the same time.
390 * Since: 1.0
392 void
393 adg_table_set_cell(AdgTable *table, const gchar *name,
394 AdgTableCell *table_cell)
396 AdgTablePrivate *data;
398 g_return_if_fail(ADG_IS_TABLE(table));
399 g_return_if_fail(name != NULL || table_cell != NULL);
401 data = adg_table_get_instance_private(table);
403 if (data->cell_names == NULL) {
404 /* Check if trying to remove from an empty hash table */
405 if (name == NULL || table_cell == NULL)
406 return;
408 data->cell_names = g_hash_table_new_full(g_str_hash, g_str_equal,
409 g_free, NULL);
412 if (name == NULL) {
413 /* _adg_value_match() will return the key in user_data[1] */
414 gpointer user_data[] = { table_cell, NULL };
415 g_hash_table_find(data->cell_names, _adg_value_match, user_data);
416 g_hash_table_remove(data->cell_names, user_data[1]);
417 } else if (table_cell == NULL) {
418 g_hash_table_remove(data->cell_names, name);
419 } else {
420 g_hash_table_insert(data->cell_names, g_strdup(name), table_cell);
425 * adg_table_get_table_style:
426 * @table: an #AdgTable
428 * Gets the #AdgTableStyle explicitely set on @table. This is a kind
429 * of accessor function: for rendering purpose use adg_entity_style()
430 * instead. The returned object is owned by @table and should not be
431 * freed or modified.
433 * Returns: (transfer none): the requested style or <constant>NULL</constant> on errors.
435 * Since: 1.0
437 AdgStyle *
438 adg_table_get_table_style(AdgTable *table)
440 AdgTablePrivate *data;
442 g_return_val_if_fail(ADG_IS_TABLE(table), NULL);
444 data = adg_table_get_instance_private(table);
445 return (AdgStyle *) data->table_style;
449 * adg_table_get_cell:
450 * @table: an #AdgTable
451 * @name: the name of a cell
453 * Gets the cell named @name inside @table. Only named cells
454 * can be retrieved by this method.
456 * The returned cell is owned by @table and must not be
457 * modified or freed.
459 * Returns: (transfer none): the requested cell or <constant>NULL</constant> if not found.
461 * Since: 1.0
463 AdgTableCell *
464 adg_table_get_cell(AdgTable *table, const gchar *name)
466 AdgTablePrivate *data;
468 g_return_val_if_fail(ADG_IS_TABLE(table), NULL);
470 data = adg_table_get_instance_private(table);
471 if (data->cell_names == NULL)
472 return NULL;
474 return g_hash_table_lookup(data->cell_names, name);
478 * adg_table_set_table_dress:
479 * @table: an #AdgTable
480 * @dress: the new #AdgDress to use
482 * Sets a new table dress for rendering @table. The new dress
483 * must be related to the original dress for this property:
484 * you cannot set a dress used for line styles to a dress
485 * managing fonts.
487 * The check is done by calling adg_dress_are_related() with
488 * @dress and the previous dress as arguments. Check out its
489 * documentation for details on what is a related dress.
491 * Since: 1.0
493 void
494 adg_table_set_table_dress(AdgTable *table, AdgDress dress)
496 g_return_if_fail(ADG_IS_TABLE(table));
497 g_object_set(table, "table-dress", dress, NULL);
501 * adg_table_get_table_dress:
502 * @table: an #AdgTable
504 * Gets the table dress to be used in rendering @table.
506 * Returns: (transfer none): the current table dress.
508 * Since: 1.0
510 AdgDress
511 adg_table_get_table_dress(AdgTable *table)
513 AdgTablePrivate *data;
515 g_return_val_if_fail(ADG_IS_TABLE(table), ADG_DRESS_UNDEFINED);
517 data = adg_table_get_instance_private(table);
518 return data->table_dress;
522 * adg_table_switch_frame:
523 * @table: an #AdgTable
524 * @new_state: the new state of the frame
526 * Sets the #AdgTable:has-frame property: <constant>TRUE</constant>
527 * will draw a frame around the whole table using the
528 * #AdgTableStyle:frame-dress dress of the table style.
530 * Since: 1.0
532 void
533 adg_table_switch_frame(AdgTable *table, gboolean new_state)
535 g_return_if_fail(ADG_IS_TABLE(table));
536 g_object_set(table, "has-frame", new_state, NULL);
540 * adg_table_has_frame:
541 * @table: an #AdgTable
543 * Returns the state of the #AdgTable:has-frame property.
545 * Returns: the current state.
547 * Since: 1.0
549 gboolean
550 adg_table_has_frame(AdgTable *table)
552 AdgTablePrivate *data;
554 g_return_val_if_fail(ADG_IS_TABLE(table), FALSE);
556 data = adg_table_get_instance_private(table);
557 return data->has_frame;
561 * adg_table_invalidate_grid:
562 * @table: an #AdgTable
564 * <note><para>
565 * This method is only useful in table children implementation.
566 * </para></note>
568 * Clears the internal grid cache, effectively forcing its
569 * regeneration next time the #AdgEntity::arrange signal is emitted.
571 void
572 adg_table_invalidate_grid(AdgTable *table)
574 AdgTablePrivate *data;
576 g_return_if_fail(ADG_IS_TABLE(table));
578 data = adg_table_get_instance_private(table);
579 if (data->grid) {
580 g_object_unref(data->grid);
581 data->grid = NULL;
586 static void
587 _adg_destroy(AdgEntity *entity)
589 _adg_propagate((AdgTable *) entity, "destroy");
591 if (_ADG_OLD_ENTITY_CLASS->destroy)
592 _ADG_OLD_ENTITY_CLASS->destroy(entity);
595 static void
596 _adg_global_changed(AdgEntity *entity)
598 if (_ADG_OLD_ENTITY_CLASS->global_changed)
599 _ADG_OLD_ENTITY_CLASS->global_changed(entity);
601 _adg_propagate((AdgTable *) entity, "global-changed");
604 static void
605 _adg_local_changed(AdgEntity *entity)
607 if (_ADG_OLD_ENTITY_CLASS->local_changed)
608 _ADG_OLD_ENTITY_CLASS->local_changed(entity);
610 _adg_propagate((AdgTable *) entity, "local-changed");
613 static void
614 _adg_invalidate(AdgEntity *entity)
616 _adg_propagate((AdgTable *) entity, "invalidate");
619 static void
620 _adg_arrange(AdgEntity *entity)
622 AdgTable *table = (AdgTable *) entity;
623 AdgTablePrivate *data = adg_table_get_instance_private(table);
624 CpmlExtents extents = { 0 };
625 CpmlExtents row_layout;
626 const CpmlExtents *row_extents;
627 const CpmlPair *spacing;
628 const CpmlPair *size;
629 GSList *row_node;
630 AdgTableRow *row;
632 /* Resolve the table style */
633 if (data->table_style == NULL)
634 data->table_style = (AdgTableStyle *)
635 adg_entity_style(entity, data->table_dress);
637 spacing = adg_table_style_get_cell_spacing(data->table_style);
639 /* Compute the size of the table */
640 for (row_node = data->rows; row_node; row_node = row_node->next) {
641 row = row_node->data;
642 size = adg_table_row_size_request(row);
644 if (size->x > extents.size.x)
645 extents.size.x = size->x;
646 extents.size.y += size->y;
649 /* Arrange the layout of the table components */
650 row_layout.is_defined = 1;
651 row_layout.org.x = extents.org.x;
652 row_layout.org.y = extents.org.y + spacing->y;
653 row_layout.size.x = extents.size.x;
654 row_layout.size.y = -1;
655 for (row_node = data->rows; row_node; row_node = row_node->next) {
656 row = row_node->data;
657 row_extents = adg_table_row_arrange(row, &row_layout);
658 row_layout.org.y += row_extents->size.y + spacing->y;
661 _adg_arrange_grid(entity);
662 _adg_arrange_frame(entity, &extents);
664 extents.is_defined = TRUE;
665 cpml_extents_transform(&extents, adg_entity_get_global_matrix(entity));
666 cpml_extents_transform(&extents, adg_entity_get_local_matrix(entity));
667 adg_entity_set_extents(entity, &extents);
670 static void
671 _adg_arrange_grid(AdgEntity *entity)
673 AdgTable *table = (AdgTable *) entity;
674 AdgTablePrivate *data = adg_table_get_instance_private(table);
675 AdgPath *path;
676 AdgTrail *trail;
677 AdgDress dress;
679 if (data->grid)
680 return;
682 path = adg_path_new();
683 trail = (AdgTrail *) path;
685 adg_table_foreach_cell(table, (GCallback) _adg_append_frame, path);
687 if (!adg_trail_get_extents(trail)->is_defined)
688 return;
690 dress = adg_table_style_get_grid_dress(data->table_style);
691 data->grid = g_object_new(ADG_TYPE_STROKE,
692 "line-dress", dress,
693 "trail", trail,
694 "parent", entity,
695 NULL);
696 adg_entity_arrange((AdgEntity *) data->grid);
699 static void
700 _adg_arrange_frame(AdgEntity *entity, const CpmlExtents *extents)
702 AdgTablePrivate *data = adg_table_get_instance_private((AdgTable *) entity);
703 AdgPath *path;
704 AdgTrail *trail;
705 CpmlPair pair;
706 AdgDress dress;
708 if (data->frame || !data->has_frame)
709 return;
711 path = adg_path_new();
712 trail = (AdgTrail *) path;
714 cpml_pair_copy(&pair, &extents->org);
715 adg_path_move_to(path, &pair);
716 pair.x += extents->size.x;
717 adg_path_line_to(path, &pair);
718 pair.y += extents->size.y;
719 adg_path_line_to(path, &pair);
720 pair.x -= extents->size.x;
721 adg_path_line_to(path, &pair);
722 adg_path_close(path);
724 dress = adg_table_style_get_frame_dress(data->table_style);
725 data->frame = g_object_new(ADG_TYPE_STROKE,
726 "line-dress", dress,
727 "trail", trail,
728 "parent", entity,
729 NULL);
730 adg_entity_arrange((AdgEntity *) data->frame);
733 static void
734 _adg_render(AdgEntity *entity, cairo_t *cr)
736 AdgTablePrivate *data = adg_table_get_instance_private((AdgTable *) entity);
738 adg_style_apply((AdgStyle *) data->table_style, entity, cr);
740 _adg_propagate((AdgTable *) entity, "render", cr);
743 static void
744 _adg_propagate(AdgTable *table, const gchar *detailed_signal, ...)
746 va_list var_copy;
747 AdgTablePrivate *data;
748 AdgProxyData proxy_data;
750 if (!g_signal_parse_name(detailed_signal, G_TYPE_FROM_INSTANCE(table),
751 &proxy_data.signal_id, &proxy_data.detail, FALSE)) {
752 g_return_if_reached();
755 va_start(proxy_data.var_args, detailed_signal);
756 data = adg_table_get_instance_private(table);
758 if (data->frame) {
759 G_VA_COPY(var_copy, proxy_data.var_args);
760 g_signal_emit_valist(data->frame, proxy_data.signal_id,
761 proxy_data.detail, var_copy);
764 if (data->grid) {
765 G_VA_COPY(var_copy, proxy_data.var_args);
766 g_signal_emit_valist(data->grid, proxy_data.signal_id,
767 proxy_data.detail, var_copy);
770 adg_table_foreach_cell(table, (GCallback) _adg_proxy_signal, &proxy_data);
771 va_end(proxy_data.var_args);
774 static void
775 _adg_foreach_row(AdgTableRow *table_row, const AdgClosure *closure)
777 adg_table_row_foreach(table_row, closure->callback, closure->user_data);
780 static void
781 _adg_append_frame(AdgTableCell *table_cell, AdgPath *path)
783 CpmlPair pair;
784 const CpmlExtents *extents;
786 if (! adg_table_cell_has_frame(table_cell))
787 return;
789 extents = adg_table_cell_get_extents(table_cell);
791 cpml_pair_copy(&pair, &extents->org);
792 adg_path_move_to(path, &pair);
793 pair.x += extents->size.x;
794 adg_path_line_to(path, &pair);
795 pair.y += extents->size.y;
796 adg_path_line_to(path, &pair);
797 pair.x -= extents->size.x;
798 adg_path_line_to(path, &pair);
799 adg_path_close(path);
802 static void
803 _adg_proxy_signal(AdgTableCell *table_cell, AdgProxyData *proxy_data)
805 AdgEntity *entity;
806 AdgAlignment *alignment;
807 va_list var_copy;
809 entity = adg_table_cell_title(table_cell);
810 if (entity) {
811 alignment = (AdgAlignment *) adg_entity_get_parent(entity);
812 G_VA_COPY(var_copy, proxy_data->var_args);
813 g_signal_emit_valist(alignment, proxy_data->signal_id,
814 proxy_data->detail, var_copy);
817 entity = adg_table_cell_value(table_cell);
818 if (entity) {
819 alignment = (AdgAlignment *) adg_entity_get_parent(entity);
820 G_VA_COPY(var_copy, proxy_data->var_args);
821 g_signal_emit_valist(alignment, proxy_data->signal_id,
822 proxy_data->detail, var_copy);
826 static gboolean
827 _adg_value_match(gpointer key, gpointer value, gpointer user_data)
829 gpointer *array = user_data;
831 if (value == array[0]) {
832 array[1] = key;
833 return TRUE;
835 return FALSE;