3 * Copyright (C) 2010 Openismus GmbH
6 * Tristan Van Berkom <tristanvb@openismus.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
31 #include "gtkcelllayout.h"
32 #include "gtkcellarea.h"
33 #include "gtkcellareaiter.h"
34 #include "gtkprivate.h"
36 #include <gobject/gvaluecollector.h>
40 static void gtk_cell_area_dispose (GObject *object);
41 static void gtk_cell_area_finalize (GObject *object);
42 static void gtk_cell_area_set_property (GObject *object,
46 static void gtk_cell_area_get_property (GObject *object,
51 /* GtkCellAreaClass */
52 static void gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area,
53 GtkCellAreaIter *iter,
57 gint *natural_height);
58 static void gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area,
59 GtkCellAreaIter *iter,
65 /* GtkCellLayoutIface */
66 static void gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface);
67 static void gtk_cell_area_pack_default (GtkCellLayout *cell_layout,
68 GtkCellRenderer *renderer,
70 static void gtk_cell_area_clear (GtkCellLayout *cell_layout);
71 static void gtk_cell_area_add_attribute (GtkCellLayout *cell_layout,
72 GtkCellRenderer *renderer,
73 const gchar *attribute,
75 static void gtk_cell_area_set_cell_data_func (GtkCellLayout *cell_layout,
76 GtkCellRenderer *cell,
77 GtkCellLayoutDataFunc func,
79 GDestroyNotify destroy);
80 static void gtk_cell_area_clear_attributes (GtkCellLayout *cell_layout,
81 GtkCellRenderer *renderer);
82 static void gtk_cell_area_reorder (GtkCellLayout *cell_layout,
83 GtkCellRenderer *cell,
85 static GList *gtk_cell_area_get_cells (GtkCellLayout *cell_layout);
87 /* Attribute/Cell metadata */
89 const gchar *attribute;
96 GtkCellLayoutDataFunc func;
98 GDestroyNotify destroy;
101 static CellInfo *cell_info_new (GtkCellLayoutDataFunc func,
103 GDestroyNotify destroy);
104 static void cell_info_free (CellInfo *info);
105 static CellAttribute *cell_attribute_new (GtkCellRenderer *renderer,
106 const gchar *attribute,
108 static void cell_attribute_free (CellAttribute *attribute);
109 static gint cell_attribute_find (CellAttribute *cell_attribute,
110 const gchar *attribute);
112 /* Struct to pass data along while looping over
113 * cell renderers to apply attributes
121 struct _GtkCellAreaPrivate
123 GHashTable *cell_info;
128 /* Keep the paramspec pool internal, no need to deliver notifications
129 * on cells. at least no percieved need for now */
130 static GParamSpecPool *cell_property_pool = NULL;
132 #define PARAM_SPEC_PARAM_ID(pspec) ((pspec)->param_id)
133 #define PARAM_SPEC_SET_PARAM_ID(pspec, id) ((pspec)->param_id = (id))
143 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkCellArea, gtk_cell_area, G_TYPE_INITIALLY_UNOWNED,
144 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
145 gtk_cell_area_cell_layout_init));
148 gtk_cell_area_init (GtkCellArea *area)
150 GtkCellAreaPrivate *priv;
152 area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area,
157 priv->cell_info = g_hash_table_new_full (g_direct_hash,
160 (GDestroyNotify)cell_info_free);
162 priv->border.left = 0;
163 priv->border.right = 0;
164 priv->border.top = 0;
165 priv->border.bottom = 0;
169 gtk_cell_area_class_init (GtkCellAreaClass *class)
171 GObjectClass *object_class = G_OBJECT_CLASS (class);
174 object_class->dispose = gtk_cell_area_dispose;
175 object_class->finalize = gtk_cell_area_finalize;
176 object_class->get_property = gtk_cell_area_get_property;
177 object_class->set_property = gtk_cell_area_set_property;
181 class->remove = NULL;
182 class->forall = NULL;
184 class->render = NULL;
187 class->create_iter = NULL;
188 class->get_request_mode = NULL;
189 class->get_preferred_width = NULL;
190 class->get_preferred_height = NULL;
191 class->get_preferred_height_for_width = gtk_cell_area_real_get_preferred_height_for_width;
192 class->get_preferred_width_for_height = gtk_cell_area_real_get_preferred_width_for_height;
195 g_object_class_install_property (object_class,
197 g_param_spec_int ("margin-left",
198 P_("Margin on Left"),
199 P_("Pixels of extra space on the left side"),
203 GTK_PARAM_READWRITE));
205 g_object_class_install_property (object_class,
207 g_param_spec_int ("margin-right",
208 P_("Margin on Right"),
209 P_("Pixels of extra space on the right side"),
213 GTK_PARAM_READWRITE));
215 g_object_class_install_property (object_class,
217 g_param_spec_int ("margin-top",
219 P_("Pixels of extra space on the top side"),
223 GTK_PARAM_READWRITE));
225 g_object_class_install_property (object_class,
227 g_param_spec_int ("margin-bottom",
228 P_("Margin on Bottom"),
229 P_("Pixels of extra space on the bottom side"),
233 GTK_PARAM_READWRITE));
235 /* Pool for Cell Properties */
236 if (!cell_property_pool)
237 cell_property_pool = g_param_spec_pool_new (FALSE);
239 g_type_class_add_private (object_class, sizeof (GtkCellAreaPrivate));
242 /*************************************************************
244 *************************************************************/
246 cell_info_new (GtkCellLayoutDataFunc func,
248 GDestroyNotify destroy)
250 CellInfo *info = g_slice_new (CellInfo);
252 info->attributes = NULL;
255 info->destroy = destroy;
261 cell_info_free (CellInfo *info)
264 info->destroy (info->data);
266 g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
267 g_slist_free (info->attributes);
269 g_slice_free (CellInfo, info);
272 static CellAttribute *
273 cell_attribute_new (GtkCellRenderer *renderer,
274 const gchar *attribute,
279 /* Check if the attribute really exists and point to
280 * the property string installed on the cell renderer
281 * class (dont dup the string)
283 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (renderer), attribute);
287 CellAttribute *cell_attribute = g_slice_new (CellAttribute);
289 cell_attribute->attribute = pspec->name;
290 cell_attribute->column = column;
292 return cell_attribute;
299 cell_attribute_free (CellAttribute *attribute)
301 g_slice_free (CellAttribute, attribute);
304 /* GCompareFunc for g_slist_find_custom() */
306 cell_attribute_find (CellAttribute *cell_attribute,
307 const gchar *attribute)
309 return g_strcmp0 (cell_attribute->attribute, attribute);
312 /*************************************************************
314 *************************************************************/
316 gtk_cell_area_finalize (GObject *object)
318 GtkCellArea *area = GTK_CELL_AREA (object);
319 GtkCellAreaPrivate *priv = area->priv;
321 /* All cell renderers should already be removed at this point,
322 * just kill our hash table here.
324 g_hash_table_destroy (priv->cell_info);
326 G_OBJECT_CLASS (gtk_cell_area_parent_class)->finalize (object);
331 gtk_cell_area_dispose (GObject *object)
333 /* This removes every cell renderer that may be added to the GtkCellArea,
334 * subclasses should be breaking references to the GtkCellRenderers
337 gtk_cell_layout_clear (GTK_CELL_LAYOUT (object));
339 G_OBJECT_CLASS (gtk_cell_area_parent_class)->dispose (object);
343 gtk_cell_area_set_property (GObject *object,
348 GtkCellArea *area = GTK_CELL_AREA (object);
352 case PROP_MARGIN_LEFT:
353 gtk_cell_area_set_margin_left (area, g_value_get_int (value));
355 case PROP_MARGIN_RIGHT:
356 gtk_cell_area_set_margin_right (area, g_value_get_int (value));
358 case PROP_MARGIN_TOP:
359 gtk_cell_area_set_margin_top (area, g_value_get_int (value));
361 case PROP_MARGIN_BOTTOM:
362 gtk_cell_area_set_margin_bottom (area, g_value_get_int (value));
365 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
371 gtk_cell_area_get_property (GObject *object,
376 GtkCellArea *area = GTK_CELL_AREA (object);
377 GtkCellAreaPrivate *priv = area->priv;
381 case PROP_MARGIN_LEFT:
382 g_value_set_int (value, priv->border.left);
384 case PROP_MARGIN_RIGHT:
385 g_value_set_int (value, priv->border.right);
387 case PROP_MARGIN_TOP:
388 g_value_set_int (value, priv->border.top);
390 case PROP_MARGIN_BOTTOM:
391 g_value_set_int (value, priv->border.bottom);
394 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
399 /*************************************************************
401 *************************************************************/
403 gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area,
404 GtkCellAreaIter *iter,
407 gint *minimum_height,
408 gint *natural_height)
410 /* If the area doesnt do height-for-width, fallback on base preferred height */
411 GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, iter, widget, minimum_height, natural_height);
415 gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area,
416 GtkCellAreaIter *iter,
422 /* If the area doesnt do width-for-height, fallback on base preferred width */
423 GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, iter, widget, minimum_width, natural_width);
426 /*************************************************************
427 * GtkCellLayoutIface *
428 *************************************************************/
430 gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface)
432 iface->pack_start = gtk_cell_area_pack_default;
433 iface->pack_end = gtk_cell_area_pack_default;
434 iface->clear = gtk_cell_area_clear;
435 iface->add_attribute = gtk_cell_area_add_attribute;
436 iface->set_cell_data_func = gtk_cell_area_set_cell_data_func;
437 iface->clear_attributes = gtk_cell_area_clear_attributes;
438 iface->reorder = gtk_cell_area_reorder;
439 iface->get_cells = gtk_cell_area_get_cells;
443 gtk_cell_area_pack_default (GtkCellLayout *cell_layout,
444 GtkCellRenderer *renderer,
447 gtk_cell_area_add (GTK_CELL_AREA (cell_layout), renderer);
451 gtk_cell_area_clear (GtkCellLayout *cell_layout)
453 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
455 gtk_cell_layout_get_cells (cell_layout);
457 for (l = cells; l; l = l->next)
459 GtkCellRenderer *renderer = l->data;
460 gtk_cell_area_remove (area, renderer);
467 gtk_cell_area_add_attribute (GtkCellLayout *cell_layout,
468 GtkCellRenderer *renderer,
469 const gchar *attribute,
472 gtk_cell_area_attribute_connect (GTK_CELL_AREA (cell_layout),
473 renderer, attribute, column);
477 gtk_cell_area_set_cell_data_func (GtkCellLayout *cell_layout,
478 GtkCellRenderer *renderer,
479 GtkCellLayoutDataFunc func,
481 GDestroyNotify destroy)
483 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
484 GtkCellAreaPrivate *priv = area->priv;
487 info = g_hash_table_lookup (priv->cell_info, renderer);
491 if (info->destroy && info->data)
492 info->destroy (info->data);
497 info->data = func_data;
498 info->destroy = destroy;
504 info->destroy = NULL;
509 info = cell_info_new (func, func_data, destroy);
511 g_hash_table_insert (priv->cell_info, renderer, info);
516 gtk_cell_area_clear_attributes (GtkCellLayout *cell_layout,
517 GtkCellRenderer *renderer)
519 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
520 GtkCellAreaPrivate *priv = area->priv;
523 info = g_hash_table_lookup (priv->cell_info, renderer);
527 g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
528 g_slist_free (info->attributes);
530 info->attributes = NULL;
535 gtk_cell_area_reorder (GtkCellLayout *cell_layout,
536 GtkCellRenderer *cell,
539 g_warning ("GtkCellLayout::reorder not implemented for `%s'",
540 g_type_name (G_TYPE_FROM_INSTANCE (cell_layout)));
544 accum_cells (GtkCellRenderer *renderer,
547 *accum = g_list_prepend (*accum, renderer);
551 gtk_cell_area_get_cells (GtkCellLayout *cell_layout)
555 gtk_cell_area_forall (GTK_CELL_AREA (cell_layout),
556 (GtkCellCallback)accum_cells,
559 return g_list_reverse (cells);
563 /*************************************************************
565 *************************************************************/
567 gtk_cell_area_add (GtkCellArea *area,
568 GtkCellRenderer *renderer)
570 GtkCellAreaClass *class;
572 g_return_if_fail (GTK_IS_CELL_AREA (area));
573 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
575 class = GTK_CELL_AREA_GET_CLASS (area);
578 class->add (area, renderer);
580 g_warning ("GtkCellAreaClass::add not implemented for `%s'",
581 g_type_name (G_TYPE_FROM_INSTANCE (area)));
585 gtk_cell_area_remove (GtkCellArea *area,
586 GtkCellRenderer *renderer)
588 GtkCellAreaClass *class;
589 GtkCellAreaPrivate *priv;
591 g_return_if_fail (GTK_IS_CELL_AREA (area));
592 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
594 class = GTK_CELL_AREA_GET_CLASS (area);
597 /* Remove any custom attributes and custom cell data func here first */
598 g_hash_table_remove (priv->cell_info, renderer);
601 class->remove (area, renderer);
603 g_warning ("GtkCellAreaClass::remove not implemented for `%s'",
604 g_type_name (G_TYPE_FROM_INSTANCE (area)));
608 gtk_cell_area_forall (GtkCellArea *area,
609 GtkCellCallback callback,
610 gpointer callback_data)
612 GtkCellAreaClass *class;
614 g_return_if_fail (GTK_IS_CELL_AREA (area));
615 g_return_if_fail (callback != NULL);
617 class = GTK_CELL_AREA_GET_CLASS (area);
620 class->forall (area, callback, callback_data);
622 g_warning ("GtkCellAreaClass::forall not implemented for `%s'",
623 g_type_name (G_TYPE_FROM_INSTANCE (area)));
627 gtk_cell_area_event (GtkCellArea *area,
628 GtkCellAreaIter *iter,
631 const GdkRectangle *cell_area)
633 GtkCellAreaClass *class;
635 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
636 g_return_val_if_fail (GTK_IS_CELL_AREA_ITER (iter), 0);
637 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
638 g_return_val_if_fail (event != NULL, 0);
639 g_return_val_if_fail (cell_area != NULL, 0);
641 class = GTK_CELL_AREA_GET_CLASS (area);
644 return class->event (area, iter, widget, event, cell_area);
646 g_warning ("GtkCellAreaClass::event not implemented for `%s'",
647 g_type_name (G_TYPE_FROM_INSTANCE (area)));
652 gtk_cell_area_render (GtkCellArea *area,
653 GtkCellAreaIter *iter,
656 const GdkRectangle *cell_area)
658 GtkCellAreaClass *class;
660 g_return_if_fail (GTK_IS_CELL_AREA (area));
661 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
662 g_return_if_fail (GTK_IS_WIDGET (widget));
663 g_return_if_fail (cr != NULL);
664 g_return_if_fail (cell_area != NULL);
666 class = GTK_CELL_AREA_GET_CLASS (area);
669 class->render (area, iter, widget, cr, cell_area);
671 g_warning ("GtkCellAreaClass::render not implemented for `%s'",
672 g_type_name (G_TYPE_FROM_INSTANCE (area)));
677 gtk_cell_area_create_iter (GtkCellArea *area)
679 GtkCellAreaClass *class;
681 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
683 class = GTK_CELL_AREA_GET_CLASS (area);
685 if (class->create_iter)
686 return class->create_iter (area);
688 g_warning ("GtkCellAreaClass::create_iter not implemented for `%s'",
689 g_type_name (G_TYPE_FROM_INSTANCE (area)));
696 gtk_cell_area_get_request_mode (GtkCellArea *area)
698 GtkCellAreaClass *class;
700 g_return_val_if_fail (GTK_IS_CELL_AREA (area),
701 GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH);
703 class = GTK_CELL_AREA_GET_CLASS (area);
705 if (class->get_request_mode)
706 return class->get_request_mode (area);
708 g_warning ("GtkCellAreaClass::get_request_mode not implemented for `%s'",
709 g_type_name (G_TYPE_FROM_INSTANCE (area)));
711 return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
715 gtk_cell_area_get_preferred_width (GtkCellArea *area,
716 GtkCellAreaIter *iter,
721 GtkCellAreaClass *class;
723 g_return_if_fail (GTK_IS_CELL_AREA (area));
724 g_return_if_fail (GTK_IS_WIDGET (widget));
726 class = GTK_CELL_AREA_GET_CLASS (area);
728 if (class->get_preferred_width)
729 class->get_preferred_width (area, iter, widget, minimum_size, natural_size);
731 g_warning ("GtkCellAreaClass::get_preferred_width not implemented for `%s'",
732 g_type_name (G_TYPE_FROM_INSTANCE (area)));
736 gtk_cell_area_get_preferred_height_for_width (GtkCellArea *area,
737 GtkCellAreaIter *iter,
740 gint *minimum_height,
741 gint *natural_height)
743 GtkCellAreaClass *class;
745 g_return_if_fail (GTK_IS_CELL_AREA (area));
746 g_return_if_fail (GTK_IS_WIDGET (widget));
748 class = GTK_CELL_AREA_GET_CLASS (area);
749 class->get_preferred_height_for_width (area, iter, widget, width, minimum_height, natural_height);
753 gtk_cell_area_get_preferred_height (GtkCellArea *area,
754 GtkCellAreaIter *iter,
759 GtkCellAreaClass *class;
761 g_return_if_fail (GTK_IS_CELL_AREA (area));
762 g_return_if_fail (GTK_IS_WIDGET (widget));
764 class = GTK_CELL_AREA_GET_CLASS (area);
766 if (class->get_preferred_height)
767 class->get_preferred_height (area, iter, widget, minimum_size, natural_size);
769 g_warning ("GtkCellAreaClass::get_preferred_height not implemented for `%s'",
770 g_type_name (G_TYPE_FROM_INSTANCE (area)));
774 gtk_cell_area_get_preferred_width_for_height (GtkCellArea *area,
775 GtkCellAreaIter *iter,
781 GtkCellAreaClass *class;
783 g_return_if_fail (GTK_IS_CELL_AREA (area));
784 g_return_if_fail (GTK_IS_WIDGET (widget));
786 class = GTK_CELL_AREA_GET_CLASS (area);
787 class->get_preferred_width_for_height (area, iter, widget, height, minimum_width, natural_width);
792 gtk_cell_area_attribute_connect (GtkCellArea *area,
793 GtkCellRenderer *renderer,
794 const gchar *attribute,
797 GtkCellAreaPrivate *priv;
799 CellAttribute *cell_attribute;
801 g_return_if_fail (GTK_IS_CELL_AREA (area));
802 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
803 g_return_if_fail (attribute != NULL);
806 info = g_hash_table_lookup (priv->cell_info, renderer);
810 info = cell_info_new (NULL, NULL, NULL);
812 g_hash_table_insert (priv->cell_info, renderer, info);
818 /* Check we are not adding the same attribute twice */
819 if ((node = g_slist_find_custom (info->attributes, attribute,
820 (GCompareFunc)cell_attribute_find)) != NULL)
822 cell_attribute = node->data;
824 g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
825 "since `%s' is already attributed to column %d",
827 g_type_name (G_TYPE_FROM_INSTANCE (area)),
828 attribute, cell_attribute->column);
833 cell_attribute = cell_attribute_new (renderer, attribute, column);
837 g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
838 "since attribute does not exist",
840 g_type_name (G_TYPE_FROM_INSTANCE (area)));
844 info->attributes = g_slist_prepend (info->attributes, cell_attribute);
848 gtk_cell_area_attribute_disconnect (GtkCellArea *area,
849 GtkCellRenderer *renderer,
850 const gchar *attribute)
852 GtkCellAreaPrivate *priv;
854 CellAttribute *cell_attribute;
857 g_return_if_fail (GTK_IS_CELL_AREA (area));
858 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
859 g_return_if_fail (attribute != NULL);
862 info = g_hash_table_lookup (priv->cell_info, renderer);
866 node = g_slist_find_custom (info->attributes, attribute,
867 (GCompareFunc)cell_attribute_find);
870 cell_attribute = node->data;
872 cell_attribute_free (cell_attribute);
874 info->attributes = g_slist_delete_link (info->attributes, node);
880 apply_cell_attributes (GtkCellRenderer *renderer,
884 CellAttribute *attribute;
886 GValue value = { 0, };
888 /* Apply the attributes directly to the renderer */
889 for (list = info->attributes; list; list = list->next)
891 attribute = list->data;
893 gtk_tree_model_get_value (data->model, data->iter, attribute->column, &value);
894 g_object_set_property (G_OBJECT (renderer), attribute->attribute, &value);
895 g_value_unset (&value);
898 /* Call any GtkCellLayoutDataFunc that may have been set by the user
901 info->func (GTK_CELL_LAYOUT (data->area), renderer,
902 data->model, data->iter, info->data);
906 gtk_cell_area_apply_attributes (GtkCellArea *area,
907 GtkTreeModel *tree_model,
910 GtkCellAreaPrivate *priv;
913 g_return_if_fail (GTK_IS_CELL_AREA (area));
914 g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
915 g_return_if_fail (iter != NULL);
919 /* Go over any cells that have attributes or custom GtkCellLayoutDataFuncs and
920 * apply the data from the treemodel */
921 g_hash_table_foreach (priv->cell_info, (GHFunc)apply_cell_attributes, &data);
924 /* Cell Properties */
926 gtk_cell_area_class_install_cell_property (GtkCellAreaClass *aclass,
930 g_return_if_fail (GTK_IS_CELL_AREA_CLASS (aclass));
931 g_return_if_fail (G_IS_PARAM_SPEC (pspec));
932 if (pspec->flags & G_PARAM_WRITABLE)
933 g_return_if_fail (aclass->set_cell_property != NULL);
934 if (pspec->flags & G_PARAM_READABLE)
935 g_return_if_fail (aclass->get_cell_property != NULL);
936 g_return_if_fail (property_id > 0);
937 g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0); /* paranoid */
938 g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0);
940 if (g_param_spec_pool_lookup (cell_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (aclass), TRUE))
942 g_warning (G_STRLOC ": class `%s' already contains a cell property named `%s'",
943 G_OBJECT_CLASS_NAME (aclass), pspec->name);
946 g_param_spec_ref (pspec);
947 g_param_spec_sink (pspec);
948 PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
949 g_param_spec_pool_insert (cell_property_pool, pspec, G_OBJECT_CLASS_TYPE (aclass));
953 gtk_cell_area_class_find_cell_property (GtkCellAreaClass *aclass,
954 const gchar *property_name)
956 g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
957 g_return_val_if_fail (property_name != NULL, NULL);
959 return g_param_spec_pool_lookup (cell_property_pool,
961 G_OBJECT_CLASS_TYPE (aclass),
966 gtk_cell_area_class_list_cell_properties (GtkCellAreaClass *aclass,
972 g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
974 pspecs = g_param_spec_pool_list (cell_property_pool,
975 G_OBJECT_CLASS_TYPE (aclass),
984 gtk_cell_area_add_with_properties (GtkCellArea *area,
985 GtkCellRenderer *renderer,
986 const gchar *first_prop_name,
989 GtkCellAreaClass *class;
991 g_return_if_fail (GTK_IS_CELL_AREA (area));
992 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
994 class = GTK_CELL_AREA_GET_CLASS (area);
1000 class->add (area, renderer);
1002 va_start (var_args, first_prop_name);
1003 gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1007 g_warning ("GtkCellAreaClass::add not implemented for `%s'",
1008 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1012 gtk_cell_area_cell_set (GtkCellArea *area,
1013 GtkCellRenderer *renderer,
1014 const gchar *first_prop_name,
1019 g_return_if_fail (GTK_IS_CELL_AREA (area));
1020 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1022 va_start (var_args, first_prop_name);
1023 gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1028 gtk_cell_area_cell_get (GtkCellArea *area,
1029 GtkCellRenderer *renderer,
1030 const gchar *first_prop_name,
1035 g_return_if_fail (GTK_IS_CELL_AREA (area));
1036 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1038 va_start (var_args, first_prop_name);
1039 gtk_cell_area_cell_get_valist (area, renderer, first_prop_name, var_args);
1044 area_get_cell_property (GtkCellArea *area,
1045 GtkCellRenderer *renderer,
1049 GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1051 class->get_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), value, pspec);
1055 area_set_cell_property (GtkCellArea *area,
1056 GtkCellRenderer *renderer,
1058 const GValue *value)
1060 GValue tmp_value = { 0, };
1061 GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1063 /* provide a copy to work from, convert (if necessary) and validate */
1064 g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1065 if (!g_value_transform (value, &tmp_value))
1066 g_warning ("unable to set cell property `%s' of type `%s' from value of type `%s'",
1068 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1069 G_VALUE_TYPE_NAME (value));
1070 else if (g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION))
1072 gchar *contents = g_strdup_value_contents (value);
1074 g_warning ("value \"%s\" of type `%s' is invalid for property `%s' of type `%s'",
1076 G_VALUE_TYPE_NAME (value),
1078 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
1083 class->set_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec);
1085 g_value_unset (&tmp_value);
1089 gtk_cell_area_cell_set_valist (GtkCellArea *area,
1090 GtkCellRenderer *renderer,
1091 const gchar *first_property_name,
1096 g_return_if_fail (GTK_IS_CELL_AREA (area));
1097 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1099 name = first_property_name;
1102 GValue value = { 0, };
1103 gchar *error = NULL;
1105 g_param_spec_pool_lookup (cell_property_pool, name,
1106 G_OBJECT_TYPE (area), TRUE);
1109 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1110 G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1113 if (!(pspec->flags & G_PARAM_WRITABLE))
1115 g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1116 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1120 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1121 G_VALUE_COLLECT (&value, var_args, 0, &error);
1124 g_warning ("%s: %s", G_STRLOC, error);
1127 /* we purposely leak the value here, it might not be
1128 * in a sane state if an error condition occoured
1132 area_set_cell_property (area, renderer, pspec, &value);
1133 g_value_unset (&value);
1134 name = va_arg (var_args, gchar*);
1139 gtk_cell_area_cell_get_valist (GtkCellArea *area,
1140 GtkCellRenderer *renderer,
1141 const gchar *first_property_name,
1146 g_return_if_fail (GTK_IS_CELL_AREA (area));
1147 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1149 name = first_property_name;
1152 GValue value = { 0, };
1156 pspec = g_param_spec_pool_lookup (cell_property_pool, name,
1157 G_OBJECT_TYPE (area), TRUE);
1160 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1161 G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1164 if (!(pspec->flags & G_PARAM_READABLE))
1166 g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1167 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1171 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1172 area_get_cell_property (area, renderer, pspec, &value);
1173 G_VALUE_LCOPY (&value, var_args, 0, &error);
1176 g_warning ("%s: %s", G_STRLOC, error);
1178 g_value_unset (&value);
1181 g_value_unset (&value);
1182 name = va_arg (var_args, gchar*);
1187 gtk_cell_area_cell_set_property (GtkCellArea *area,
1188 GtkCellRenderer *renderer,
1189 const gchar *property_name,
1190 const GValue *value)
1194 g_return_if_fail (GTK_IS_CELL_AREA (area));
1195 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1196 g_return_if_fail (property_name != NULL);
1197 g_return_if_fail (G_IS_VALUE (value));
1199 pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1200 G_OBJECT_TYPE (area), TRUE);
1202 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1203 G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1204 else if (!(pspec->flags & G_PARAM_WRITABLE))
1205 g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1206 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1209 area_set_cell_property (area, renderer, pspec, value);
1214 gtk_cell_area_cell_get_property (GtkCellArea *area,
1215 GtkCellRenderer *renderer,
1216 const gchar *property_name,
1221 g_return_if_fail (GTK_IS_CELL_AREA (area));
1222 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1223 g_return_if_fail (property_name != NULL);
1224 g_return_if_fail (G_IS_VALUE (value));
1226 pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1227 G_OBJECT_TYPE (area), TRUE);
1229 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1230 G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1231 else if (!(pspec->flags & G_PARAM_READABLE))
1232 g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1233 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1236 GValue *prop_value, tmp_value = { 0, };
1238 /* auto-conversion of the callers value type
1240 if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
1242 g_value_reset (value);
1245 else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
1247 g_warning ("can't retrieve cell property `%s' of type `%s' as value of type `%s'",
1249 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1250 G_VALUE_TYPE_NAME (value));
1255 g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1256 prop_value = &tmp_value;
1259 area_get_cell_property (area, renderer, pspec, prop_value);
1261 if (prop_value != value)
1263 g_value_transform (prop_value, value);
1264 g_value_unset (&tmp_value);
1271 gtk_cell_area_get_margin_left (GtkCellArea *area)
1273 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1275 return area->priv->border.left;
1279 gtk_cell_area_set_margin_left (GtkCellArea *area,
1282 GtkCellAreaPrivate *priv;
1284 g_return_if_fail (GTK_IS_CELL_AREA (area));
1288 if (priv->border.left != margin)
1290 priv->border.left = margin;
1292 g_object_notify (G_OBJECT (area), "margin-left");
1297 gtk_cell_area_get_margin_right (GtkCellArea *area)
1299 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1301 return area->priv->border.right;
1305 gtk_cell_area_set_margin_right (GtkCellArea *area,
1308 GtkCellAreaPrivate *priv;
1310 g_return_if_fail (GTK_IS_CELL_AREA (area));
1314 if (priv->border.right != margin)
1316 priv->border.right = margin;
1318 g_object_notify (G_OBJECT (area), "margin-right");
1323 gtk_cell_area_get_margin_top (GtkCellArea *area)
1325 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1327 return area->priv->border.top;
1331 gtk_cell_area_set_margin_top (GtkCellArea *area,
1334 GtkCellAreaPrivate *priv;
1336 g_return_if_fail (GTK_IS_CELL_AREA (area));
1340 if (priv->border.top != margin)
1342 priv->border.top = margin;
1344 g_object_notify (G_OBJECT (area), "margin-top");
1349 gtk_cell_area_get_margin_bottom (GtkCellArea *area)
1351 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1353 return area->priv->border.bottom;
1357 gtk_cell_area_set_margin_bottom (GtkCellArea *area,
1360 GtkCellAreaPrivate *priv;
1362 g_return_if_fail (GTK_IS_CELL_AREA (area));
1366 if (priv->border.bottom != margin)
1368 priv->border.bottom = margin;
1370 g_object_notify (G_OBJECT (area), "margin-bottom");
1374 /* For convenience in area implementations */
1376 gtk_cell_area_inner_area (GtkCellArea *area,
1377 GdkRectangle *background_area,
1378 GdkRectangle *cell_area)
1380 GtkCellAreaPrivate *priv;
1382 g_return_if_fail (GTK_IS_CELL_AREA (area));
1383 g_return_if_fail (background_area != NULL);
1384 g_return_if_fail (cell_area != NULL);
1388 *cell_area = *background_area;
1390 cell_area->x += priv->border.left;
1391 cell_area->width -= (priv->border.left + priv->border.right);
1392 cell_area->y += priv->border.top;
1393 cell_area->height -= (priv->border.top + priv->border.bottom);