doc: update copyright line for 2021
[adg.git] / src / adg / adg-table.c
blobd1aea5167c38aa4da76cf9e88f509f046b94d8a3
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2021 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: (nullable): the name of the cell
375 * @table_cell: (transfer none) (nullable): 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 g_hash_table_foreach_remove(data->cell_names, _adg_value_match, table_cell);
414 } else if (table_cell == NULL) {
415 g_hash_table_remove(data->cell_names, name);
416 } else {
417 g_hash_table_insert(data->cell_names, g_strdup(name), table_cell);
422 * adg_table_get_table_style:
423 * @table: an #AdgTable
425 * Gets the #AdgTableStyle explicitely set on @table. This is a kind
426 * of accessor function: for rendering purpose use adg_entity_style()
427 * instead. The returned object is owned by @table and should not be
428 * freed or modified.
430 * Returns: (transfer none): the requested style or <constant>NULL</constant> on errors.
432 * Since: 1.0
434 AdgStyle *
435 adg_table_get_table_style(AdgTable *table)
437 AdgTablePrivate *data;
439 g_return_val_if_fail(ADG_IS_TABLE(table), NULL);
441 data = adg_table_get_instance_private(table);
442 return (AdgStyle *) data->table_style;
446 * adg_table_get_cell:
447 * @table: an #AdgTable
448 * @name: the name of a cell
450 * Gets the cell named @name inside @table. Only named cells
451 * can be retrieved by this method.
453 * The returned cell is owned by @table and must not be
454 * modified or freed.
456 * Returns: (transfer none): the requested cell or <constant>NULL</constant> if not found.
458 * Since: 1.0
460 AdgTableCell *
461 adg_table_get_cell(AdgTable *table, const gchar *name)
463 AdgTablePrivate *data;
465 g_return_val_if_fail(ADG_IS_TABLE(table), NULL);
467 data = adg_table_get_instance_private(table);
468 if (data->cell_names == NULL)
469 return NULL;
471 return g_hash_table_lookup(data->cell_names, name);
475 * adg_table_set_table_dress:
476 * @table: an #AdgTable
477 * @dress: the new #AdgDress to use
479 * Sets a new table dress for rendering @table. The new dress
480 * must be related to the original dress for this property:
481 * you cannot set a dress used for line styles to a dress
482 * managing fonts.
484 * The check is done by calling adg_dress_are_related() with
485 * @dress and the previous dress as arguments. Check out its
486 * documentation for details on what is a related dress.
488 * Since: 1.0
490 void
491 adg_table_set_table_dress(AdgTable *table, AdgDress dress)
493 g_return_if_fail(ADG_IS_TABLE(table));
494 g_object_set(table, "table-dress", dress, NULL);
498 * adg_table_get_table_dress:
499 * @table: an #AdgTable
501 * Gets the table dress to be used in rendering @table.
503 * Returns: (transfer none): the current table dress.
505 * Since: 1.0
507 AdgDress
508 adg_table_get_table_dress(AdgTable *table)
510 AdgTablePrivate *data;
512 g_return_val_if_fail(ADG_IS_TABLE(table), ADG_DRESS_UNDEFINED);
514 data = adg_table_get_instance_private(table);
515 return data->table_dress;
519 * adg_table_switch_frame:
520 * @table: an #AdgTable
521 * @new_state: the new state of the frame
523 * Sets the #AdgTable:has-frame property: <constant>TRUE</constant>
524 * will draw a frame around the whole table using the
525 * #AdgTableStyle:frame-dress dress of the table style.
527 * Since: 1.0
529 void
530 adg_table_switch_frame(AdgTable *table, gboolean new_state)
532 g_return_if_fail(ADG_IS_TABLE(table));
533 g_object_set(table, "has-frame", new_state, NULL);
537 * adg_table_has_frame:
538 * @table: an #AdgTable
540 * Returns the state of the #AdgTable:has-frame property.
542 * Returns: the current state.
544 * Since: 1.0
546 gboolean
547 adg_table_has_frame(AdgTable *table)
549 AdgTablePrivate *data;
551 g_return_val_if_fail(ADG_IS_TABLE(table), FALSE);
553 data = adg_table_get_instance_private(table);
554 return data->has_frame;
558 * adg_table_invalidate_grid:
559 * @table: an #AdgTable
561 * <note><para>
562 * This method is only useful in table children implementation.
563 * </para></note>
565 * Clears the internal grid cache, effectively forcing its
566 * regeneration next time the #AdgEntity::arrange signal is emitted.
568 void
569 adg_table_invalidate_grid(AdgTable *table)
571 AdgTablePrivate *data;
573 g_return_if_fail(ADG_IS_TABLE(table));
575 data = adg_table_get_instance_private(table);
576 if (data->grid) {
577 g_object_unref(data->grid);
578 data->grid = NULL;
583 static void
584 _adg_destroy(AdgEntity *entity)
586 _adg_propagate((AdgTable *) entity, "destroy");
588 if (_ADG_OLD_ENTITY_CLASS->destroy)
589 _ADG_OLD_ENTITY_CLASS->destroy(entity);
592 static void
593 _adg_global_changed(AdgEntity *entity)
595 if (_ADG_OLD_ENTITY_CLASS->global_changed)
596 _ADG_OLD_ENTITY_CLASS->global_changed(entity);
598 _adg_propagate((AdgTable *) entity, "global-changed");
601 static void
602 _adg_local_changed(AdgEntity *entity)
604 if (_ADG_OLD_ENTITY_CLASS->local_changed)
605 _ADG_OLD_ENTITY_CLASS->local_changed(entity);
607 _adg_propagate((AdgTable *) entity, "local-changed");
610 static void
611 _adg_invalidate(AdgEntity *entity)
613 _adg_propagate((AdgTable *) entity, "invalidate");
616 static void
617 _adg_arrange(AdgEntity *entity)
619 AdgTable *table = (AdgTable *) entity;
620 AdgTablePrivate *data = adg_table_get_instance_private(table);
621 CpmlExtents extents = { 0 };
622 CpmlExtents row_layout;
623 const CpmlExtents *row_extents;
624 const CpmlPair *spacing;
625 const CpmlPair *size;
626 GSList *row_node;
627 AdgTableRow *row;
629 /* Resolve the table style */
630 if (data->table_style == NULL)
631 data->table_style = (AdgTableStyle *)
632 adg_entity_style(entity, data->table_dress);
634 spacing = adg_table_style_get_cell_spacing(data->table_style);
636 /* Compute the size of the table */
637 for (row_node = data->rows; row_node; row_node = row_node->next) {
638 row = row_node->data;
639 size = adg_table_row_size_request(row);
641 if (size->x > extents.size.x)
642 extents.size.x = size->x;
643 extents.size.y += size->y;
646 /* Arrange the layout of the table components */
647 row_layout.is_defined = 1;
648 row_layout.org.x = extents.org.x;
649 row_layout.org.y = extents.org.y + spacing->y;
650 row_layout.size.x = extents.size.x;
651 row_layout.size.y = -1;
652 for (row_node = data->rows; row_node; row_node = row_node->next) {
653 row = row_node->data;
654 row_extents = adg_table_row_arrange(row, &row_layout);
655 row_layout.org.y += row_extents->size.y + spacing->y;
658 _adg_arrange_grid(entity);
659 _adg_arrange_frame(entity, &extents);
661 extents.is_defined = TRUE;
662 cpml_extents_transform(&extents, adg_entity_get_global_matrix(entity));
663 cpml_extents_transform(&extents, adg_entity_get_local_matrix(entity));
664 adg_entity_set_extents(entity, &extents);
667 static void
668 _adg_arrange_grid(AdgEntity *entity)
670 AdgTable *table = (AdgTable *) entity;
671 AdgTablePrivate *data = adg_table_get_instance_private(table);
672 AdgPath *path;
673 AdgTrail *trail;
674 AdgDress dress;
676 if (data->grid)
677 return;
679 path = adg_path_new();
680 trail = (AdgTrail *) path;
682 adg_table_foreach_cell(table, (GCallback) _adg_append_frame, path);
684 if (!adg_trail_get_extents(trail)->is_defined)
685 return;
687 dress = adg_table_style_get_grid_dress(data->table_style);
688 data->grid = g_object_new(ADG_TYPE_STROKE,
689 "line-dress", dress,
690 "trail", trail,
691 "parent", entity,
692 NULL);
693 adg_entity_arrange((AdgEntity *) data->grid);
696 static void
697 _adg_arrange_frame(AdgEntity *entity, const CpmlExtents *extents)
699 AdgTablePrivate *data = adg_table_get_instance_private((AdgTable *) entity);
700 AdgPath *path;
701 AdgTrail *trail;
702 CpmlPair pair;
703 AdgDress dress;
705 if (data->frame || !data->has_frame)
706 return;
708 path = adg_path_new();
709 trail = (AdgTrail *) path;
711 cpml_pair_copy(&pair, &extents->org);
712 adg_path_move_to(path, &pair);
713 pair.x += extents->size.x;
714 adg_path_line_to(path, &pair);
715 pair.y += extents->size.y;
716 adg_path_line_to(path, &pair);
717 pair.x -= extents->size.x;
718 adg_path_line_to(path, &pair);
719 adg_path_close(path);
721 dress = adg_table_style_get_frame_dress(data->table_style);
722 data->frame = g_object_new(ADG_TYPE_STROKE,
723 "line-dress", dress,
724 "trail", trail,
725 "parent", entity,
726 NULL);
727 adg_entity_arrange((AdgEntity *) data->frame);
730 static void
731 _adg_render(AdgEntity *entity, cairo_t *cr)
733 AdgTablePrivate *data = adg_table_get_instance_private((AdgTable *) entity);
735 adg_style_apply((AdgStyle *) data->table_style, entity, cr);
737 _adg_propagate((AdgTable *) entity, "render", cr);
740 static void
741 _adg_propagate(AdgTable *table, const gchar *detailed_signal, ...)
743 va_list var_copy;
744 AdgTablePrivate *data;
745 AdgProxyData proxy_data;
747 if (!g_signal_parse_name(detailed_signal, G_TYPE_FROM_INSTANCE(table),
748 &proxy_data.signal_id, &proxy_data.detail, FALSE)) {
749 g_return_if_reached();
752 va_start(proxy_data.var_args, detailed_signal);
753 data = adg_table_get_instance_private(table);
755 if (data->frame) {
756 G_VA_COPY(var_copy, proxy_data.var_args);
757 g_signal_emit_valist(data->frame, proxy_data.signal_id,
758 proxy_data.detail, var_copy);
761 if (data->grid) {
762 G_VA_COPY(var_copy, proxy_data.var_args);
763 g_signal_emit_valist(data->grid, proxy_data.signal_id,
764 proxy_data.detail, var_copy);
767 adg_table_foreach_cell(table, (GCallback) _adg_proxy_signal, &proxy_data);
768 va_end(proxy_data.var_args);
771 static void
772 _adg_foreach_row(AdgTableRow *table_row, const AdgClosure *closure)
774 adg_table_row_foreach(table_row, closure->callback, closure->user_data);
777 static void
778 _adg_append_frame(AdgTableCell *table_cell, AdgPath *path)
780 CpmlPair pair;
781 const CpmlExtents *extents;
783 if (! adg_table_cell_has_frame(table_cell))
784 return;
786 extents = adg_table_cell_get_extents(table_cell);
788 cpml_pair_copy(&pair, &extents->org);
789 adg_path_move_to(path, &pair);
790 pair.x += extents->size.x;
791 adg_path_line_to(path, &pair);
792 pair.y += extents->size.y;
793 adg_path_line_to(path, &pair);
794 pair.x -= extents->size.x;
795 adg_path_line_to(path, &pair);
796 adg_path_close(path);
799 static void
800 _adg_proxy_signal(AdgTableCell *table_cell, AdgProxyData *proxy_data)
802 AdgEntity *entity;
803 AdgAlignment *alignment;
804 va_list var_copy;
806 entity = adg_table_cell_title(table_cell);
807 if (entity) {
808 alignment = (AdgAlignment *) adg_entity_get_parent(entity);
809 G_VA_COPY(var_copy, proxy_data->var_args);
810 g_signal_emit_valist(alignment, proxy_data->signal_id,
811 proxy_data->detail, var_copy);
814 entity = adg_table_cell_value(table_cell);
815 if (entity) {
816 alignment = (AdgAlignment *) adg_entity_get_parent(entity);
817 G_VA_COPY(var_copy, proxy_data->var_args);
818 g_signal_emit_valist(alignment, proxy_data->signal_id,
819 proxy_data->detail, var_copy);
823 static gboolean
824 _adg_value_match(gpointer key, gpointer value, gpointer user_data)
826 return value == user_data;