]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellarea.c
Merge branch 'master' into treeview-refactor
[~andy/gtk] / gtk / gtkcellarea.c
1 /* gtkcellarea.c
2  *
3  * Copyright (C) 2010 Openismus GmbH
4  *
5  * Authors:
6  *      Tristan Van Berkom <tristanvb@openismus.com>
7  *
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.
12  *
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.
17  *
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.
22  */
23
24 #include "gtkcelllayout.h"
25 #include "gtkcellarea.h"
26
27 /* GObjectClass */
28 static void      gtk_cell_area_dispose                             (GObject            *object);
29 static void      gtk_cell_area_finalize                            (GObject            *object);
30
31 /* GtkCellAreaClass */
32 static void      gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea        *area,
33                                                                     GtkWidget          *widget,
34                                                                     gint                width,
35                                                                     gint               *minimum_height,
36                                                                     gint               *natural_height);
37 static void      gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea        *area,
38                                                                     GtkWidget          *widget,
39                                                                     gint                height,
40                                                                     gint               *minimum_width,
41                                                                     gint               *natural_width);
42
43 /* GtkCellLayoutIface */
44 static void      gtk_cell_area_cell_layout_init              (GtkCellLayoutIface    *iface);
45 static void      gtk_cell_area_pack_default                  (GtkCellLayout         *cell_layout,
46                                                               GtkCellRenderer       *renderer,
47                                                               gboolean               expand);
48 static void      gtk_cell_area_clear                         (GtkCellLayout         *cell_layout);
49 static void      gtk_cell_area_add_attribute                 (GtkCellLayout         *cell_layout,
50                                                               GtkCellRenderer       *renderer,
51                                                               const gchar           *attribute,
52                                                               gint                   column);
53 static void      gtk_cell_area_set_cell_data_func            (GtkCellLayout         *cell_layout,
54                                                               GtkCellRenderer       *cell,
55                                                               GtkCellLayoutDataFunc  func,
56                                                               gpointer               func_data,
57                                                               GDestroyNotify         destroy);
58 static void      gtk_cell_area_clear_attributes              (GtkCellLayout         *cell_layout,
59                                                               GtkCellRenderer       *renderer);
60 static void      gtk_cell_area_reorder                       (GtkCellLayout         *cell_layout,
61                                                               GtkCellRenderer       *cell,
62                                                               gint                   position);
63 static GList    *gtk_cell_area_get_cells                     (GtkCellLayout         *cell_layout);
64
65 /* Attribute/Cell metadata */
66 typedef struct {
67   const gchar *attribute;
68   gint         column;
69 } CellAttribute;
70
71 typedef struct {
72   GSList                *attributes;
73
74   GtkCellLayoutDataFunc  func;
75   gpointer               data;
76   GDestroyNotify         destroy;
77 } CellInfo;
78
79 static CellInfo       *cell_info_new       (GtkCellLayoutDataFunc  func,
80                                             gpointer               data,
81                                             GDestroyNotify         destroy);
82 static void            cell_info_free      (CellInfo              *info);
83 static CellAttribute  *cell_attribute_new  (GtkCellRenderer       *renderer,
84                                             const gchar           *attribute,
85                                             gint                   column);
86 static void            cell_attribute_free (CellAttribute         *attribute);
87 static gint            cell_attribute_find (CellAttribute         *cell_attribute,
88                                             const gchar           *attribute);
89
90 /* Struct to pass data along while looping over 
91  * cell renderers to apply attributes
92  */
93 typedef struct {
94   GtkCellArea  *area;
95   GtkTreeModel *model;
96   GtkTreeIter  *iter;
97 } AttributeData;
98
99 struct _GtkCellAreaPrivate
100 {
101   GHashTable *cell_info;
102 };
103
104 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkCellArea, gtk_cell_area, G_TYPE_INITIALLY_UNOWNED,
105                                   G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
106                                                          gtk_cell_area_cell_layout_init));
107
108 static void
109 gtk_cell_area_init (GtkCellArea *area)
110 {
111   GtkCellAreaPrivate *priv;
112
113   area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area,
114                                             GTK_TYPE_CELL_AREA,
115                                             GtkCellAreaPrivate);
116   priv = area->priv;
117
118   priv->cell_info = g_hash_table_new_full (g_direct_hash, 
119                                            g_direct_equal,
120                                            NULL, 
121                                            (GDestroyNotify)cell_info_free);
122 }
123
124 static void 
125 gtk_cell_area_class_init (GtkCellAreaClass *class)
126 {
127   GObjectClass *object_class = G_OBJECT_CLASS (class);
128   
129   /* GObjectClass */
130   object_class->dispose  = gtk_cell_area_dispose;
131   object_class->finalize = gtk_cell_area_finalize;
132
133   /* general */
134   class->add     = NULL;
135   class->remove  = NULL;
136   class->forall  = NULL;
137   class->event   = NULL;
138   class->render  = NULL;
139
140   /* geometry */
141   class->get_request_mode               = NULL;
142   class->get_preferred_width            = NULL;
143   class->get_preferred_height           = NULL;
144   class->get_preferred_height_for_width = gtk_cell_area_real_get_preferred_height_for_width;
145   class->get_preferred_width_for_height = gtk_cell_area_real_get_preferred_width_for_height;
146
147   g_type_class_add_private (object_class, sizeof (GtkCellAreaPrivate));
148 }
149
150 /*************************************************************
151  *                    CellInfo Basics                        *
152  *************************************************************/
153 static CellInfo *
154 cell_info_new (GtkCellLayoutDataFunc  func,
155                gpointer               data,
156                GDestroyNotify         destroy)
157 {
158   CellInfo *info = g_slice_new (CellInfo);
159   
160   info->attributes = NULL;
161   info->func       = func;
162   info->data       = data;
163   info->destroy    = destroy;
164
165   return info;
166 }
167
168 static void
169 cell_info_free (CellInfo *info)
170 {
171   if (info->destroy)
172     info->destroy (info->data);
173
174   g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
175   g_slist_free (info->attributes);
176
177   g_slice_free (CellInfo, info);
178 }
179
180 static CellAttribute  *
181 cell_attribute_new  (GtkCellRenderer       *renderer,
182                      const gchar           *attribute,
183                      gint                   column)
184 {
185   GParamSpec *pspec;
186
187   /* Check if the attribute really exists and point to
188    * the property string installed on the cell renderer
189    * class (dont dup the string) 
190    */
191   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (renderer), attribute);
192
193   if (pspec)
194     {
195       CellAttribute *cell_attribute = g_slice_new (CellAttribute);
196
197       cell_attribute->attribute = pspec->name;
198       cell_attribute->column    = column;
199
200       return cell_attribute;
201     }
202
203   return NULL;
204 }
205
206 static void
207 cell_attribute_free (CellAttribute *attribute)
208 {
209   g_slice_free (CellAttribute, attribute);
210 }
211
212 /* GCompareFunc for g_slist_find_custom() */
213 static gint
214 cell_attribute_find (CellAttribute *cell_attribute,
215                      const gchar   *attribute)
216 {
217   return g_strcmp0 (cell_attribute->attribute, attribute);
218 }
219
220 /*************************************************************
221  *                      GObjectClass                         *
222  *************************************************************/
223 static void
224 gtk_cell_area_finalize (GObject *object)
225 {
226   GtkCellArea        *area   = GTK_CELL_AREA (object);
227   GtkCellAreaPrivate *priv   = area->priv;
228
229   /* All cell renderers should already be removed at this point,
230    * just kill our hash table here. 
231    */
232   g_hash_table_destroy (priv->cell_info);
233
234   G_OBJECT_CLASS (gtk_cell_area_parent_class)->finalize (object);
235 }
236
237
238 static void
239 gtk_cell_area_dispose (GObject *object)
240 {
241   /* This removes every cell renderer that may be added to the GtkCellArea,
242    * subclasses should be breaking references to the GtkCellRenderers 
243    * at this point.
244    */
245   gtk_cell_layout_clear (GTK_CELL_LAYOUT (object));
246
247   G_OBJECT_CLASS (gtk_cell_area_parent_class)->dispose (object);
248 }
249
250
251 /*************************************************************
252  *                    GtkCellAreaClass                       *
253  *************************************************************/
254 static void
255 gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea        *area,
256                                                    GtkWidget          *widget,
257                                                    gint                width,
258                                                    gint               *minimum_height,
259                                                    gint               *natural_height)
260 {
261   /* If the area doesnt do height-for-width, fallback on base preferred height */
262   GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, widget, minimum_height, natural_height);
263 }
264
265 static void
266 gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea        *area,
267                                                    GtkWidget          *widget,
268                                                    gint                height,
269                                                    gint               *minimum_width,
270                                                    gint               *natural_width)
271 {
272   /* If the area doesnt do width-for-height, fallback on base preferred width */
273   GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, widget, minimum_width, natural_width);
274 }
275
276 /*************************************************************
277  *                   GtkCellLayoutIface                      *
278  *************************************************************/
279 static void
280 gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface)
281 {
282   iface->pack_start         = gtk_cell_area_pack_default;
283   iface->pack_end           = gtk_cell_area_pack_default;
284   iface->clear              = gtk_cell_area_clear;
285   iface->add_attribute      = gtk_cell_area_add_attribute;
286   iface->set_cell_data_func = gtk_cell_area_set_cell_data_func;
287   iface->clear_attributes   = gtk_cell_area_clear_attributes;
288   iface->reorder            = gtk_cell_area_reorder;
289   iface->get_cells          = gtk_cell_area_get_cells;
290 }
291
292 static void
293 gtk_cell_area_pack_default (GtkCellLayout         *cell_layout,
294                             GtkCellRenderer       *renderer,
295                             gboolean               expand)
296 {
297   gtk_cell_area_add (GTK_CELL_AREA (cell_layout), renderer);
298 }
299
300 static void
301 gtk_cell_area_clear (GtkCellLayout *cell_layout)
302 {
303   GtkCellArea *area = GTK_CELL_AREA (cell_layout);
304   GList *l, *cells  =
305     gtk_cell_layout_get_cells (cell_layout);
306
307   for (l = cells; l; l = l->next)
308     {
309       GtkCellRenderer *renderer = l->data;
310       gtk_cell_area_remove (area, renderer);
311     }
312
313   g_list_free (cells);
314 }
315
316 static void
317 gtk_cell_area_add_attribute (GtkCellLayout         *cell_layout,
318                              GtkCellRenderer       *renderer,
319                              const gchar           *attribute,
320                              gint                   column)
321 {
322   gtk_cell_area_attribute_connect (GTK_CELL_AREA (cell_layout),
323                                    renderer, attribute, column);
324 }
325
326 static void
327 gtk_cell_area_set_cell_data_func (GtkCellLayout         *cell_layout,
328                                   GtkCellRenderer       *renderer,
329                                   GtkCellLayoutDataFunc  func,
330                                   gpointer               func_data,
331                                   GDestroyNotify         destroy)
332 {
333   GtkCellArea        *area   = GTK_CELL_AREA (cell_layout);
334   GtkCellAreaPrivate *priv   = area->priv;
335   CellInfo           *info;
336
337   info = g_hash_table_lookup (priv->cell_info, renderer);
338
339   if (info)
340     {
341       if (info->destroy && info->data)
342         info->destroy (info->data);
343
344       if (func)
345         {
346           info->func    = func;
347           info->data    = func_data;
348           info->destroy = destroy;
349         }
350       else
351         {
352           info->func    = NULL;
353           info->data    = NULL;
354           info->destroy = NULL;
355         }
356     }
357   else
358     {
359       info = cell_info_new (func, func_data, destroy);
360
361       g_hash_table_insert (priv->cell_info, renderer, info);
362     }
363 }
364
365 static void
366 gtk_cell_area_clear_attributes (GtkCellLayout         *cell_layout,
367                                 GtkCellRenderer       *renderer)
368 {
369   GtkCellArea        *area = GTK_CELL_AREA (cell_layout);
370   GtkCellAreaPrivate *priv = area->priv;
371   CellInfo           *info;
372
373   info = g_hash_table_lookup (priv->cell_info, renderer);
374
375   if (info)
376     {
377       g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
378       g_slist_free (info->attributes);
379
380       info->attributes = NULL;
381     }
382 }
383
384 static void 
385 gtk_cell_area_reorder (GtkCellLayout   *cell_layout,
386                        GtkCellRenderer *cell,
387                        gint             position)
388 {
389   g_warning ("GtkCellLayout::reorder not implemented for `%s'", 
390              g_type_name (G_TYPE_FROM_INSTANCE (cell_layout)));
391 }
392
393 static void
394 accum_cells (GtkCellRenderer *renderer,
395              GList          **accum)
396 {
397   *accum = g_list_prepend (*accum, renderer);
398 }
399
400 static GList *
401 gtk_cell_area_get_cells (GtkCellLayout *cell_layout)
402 {
403   GList *cells = NULL;
404
405   gtk_cell_area_forall (GTK_CELL_AREA (cell_layout), 
406                         (GtkCellCallback)accum_cells,
407                         &cells);
408
409   return g_list_reverse (cells);
410 }
411
412
413 /*************************************************************
414  *                            API                            *
415  *************************************************************/
416
417 void
418 gtk_cell_area_add (GtkCellArea        *area,
419                    GtkCellRenderer    *renderer)
420 {
421   GtkCellAreaClass *class;
422
423   g_return_if_fail (GTK_IS_CELL_AREA (area));
424   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
425
426   class = GTK_CELL_AREA_GET_CLASS (area);
427
428   if (class->add)
429     class->add (area, renderer);
430   else
431     g_warning ("GtkCellAreaClass::add not implemented for `%s'", 
432                g_type_name (G_TYPE_FROM_INSTANCE (area)));
433 }
434
435 void
436 gtk_cell_area_remove (GtkCellArea        *area,
437                       GtkCellRenderer    *renderer)
438 {
439   GtkCellAreaClass   *class;
440   GtkCellAreaPrivate *priv;
441
442   g_return_if_fail (GTK_IS_CELL_AREA (area));
443   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
444
445   class = GTK_CELL_AREA_GET_CLASS (area);
446   priv  = area->priv;
447
448   /* Remove any custom attributes and custom cell data func here first */
449   g_hash_table_remove (priv->cell_info, renderer);
450
451   if (class->remove)
452     class->remove (area, renderer);
453   else
454     g_warning ("GtkCellAreaClass::remove not implemented for `%s'", 
455                g_type_name (G_TYPE_FROM_INSTANCE (area)));
456 }
457
458 void
459 gtk_cell_area_forall (GtkCellArea        *area,
460                       GtkCellCallback     callback,
461                       gpointer            callback_data)
462 {
463   GtkCellAreaClass *class;
464
465   g_return_if_fail (GTK_IS_CELL_AREA (area));
466   g_return_if_fail (callback != NULL);
467
468   class = GTK_CELL_AREA_GET_CLASS (area);
469
470   if (class->forall)
471     class->forall (area, callback, callback_data);
472   else
473     g_warning ("GtkCellAreaClass::forall not implemented for `%s'", 
474                g_type_name (G_TYPE_FROM_INSTANCE (area)));
475 }
476
477 gint
478 gtk_cell_area_event (GtkCellArea        *area,
479                      GtkWidget          *widget,
480                      GdkEvent           *event,
481                      const GdkRectangle *cell_area)
482 {
483   GtkCellAreaClass *class;
484
485   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
486   g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
487   g_return_val_if_fail (event != NULL, 0);
488   g_return_val_if_fail (cell_area != NULL, 0);
489
490   class = GTK_CELL_AREA_GET_CLASS (area);
491
492   if (class->event)
493     return class->event (area, widget, event, cell_area);
494
495   g_warning ("GtkCellAreaClass::event not implemented for `%s'", 
496              g_type_name (G_TYPE_FROM_INSTANCE (area)));
497   return 0;
498 }
499
500 void
501 gtk_cell_area_render (GtkCellArea        *area,
502                       cairo_t            *cr,
503                       GtkWidget          *widget,
504                       const GdkRectangle *cell_area)
505 {
506   GtkCellAreaClass *class;
507
508   g_return_if_fail (GTK_IS_CELL_AREA (area));
509   g_return_if_fail (cr != NULL);
510   g_return_if_fail (GTK_IS_WIDGET (widget));
511   g_return_if_fail (cell_area != NULL);
512
513   class = GTK_CELL_AREA_GET_CLASS (area);
514
515   if (class->render)
516     class->render (area, cr, widget, cell_area);
517   else
518     g_warning ("GtkCellAreaClass::render not implemented for `%s'", 
519                g_type_name (G_TYPE_FROM_INSTANCE (area)));
520 }
521
522 /* Geometry */
523 GtkSizeRequestMode 
524 gtk_cell_area_get_request_mode (GtkCellArea *area)
525 {
526   GtkCellAreaClass *class;
527
528   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 
529                         GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH);
530
531   class = GTK_CELL_AREA_GET_CLASS (area);
532
533   if (class->get_request_mode)
534     return class->get_request_mode (area);
535
536   g_warning ("GtkCellAreaClass::get_request_mode not implemented for `%s'", 
537              g_type_name (G_TYPE_FROM_INSTANCE (area)));
538   
539   return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
540 }
541
542 void
543 gtk_cell_area_get_preferred_width (GtkCellArea        *area,
544                                    GtkWidget          *widget,
545                                    gint               *minimum_size,
546                                    gint               *natural_size)
547 {
548   GtkCellAreaClass *class;
549
550   g_return_if_fail (GTK_IS_CELL_AREA (area));
551   g_return_if_fail (GTK_IS_WIDGET (widget));
552
553   class = GTK_CELL_AREA_GET_CLASS (area);
554
555   if (class->get_preferred_width)
556     class->get_preferred_width (area, widget, minimum_size, natural_size);
557   else
558     g_warning ("GtkCellAreaClass::get_preferred_width not implemented for `%s'", 
559                g_type_name (G_TYPE_FROM_INSTANCE (area)));
560 }
561
562 void
563 gtk_cell_area_get_preferred_height_for_width (GtkCellArea        *area,
564                                               GtkWidget          *widget,
565                                               gint                width,
566                                               gint               *minimum_height,
567                                               gint               *natural_height)
568 {
569   GtkCellAreaClass *class;
570
571   g_return_if_fail (GTK_IS_CELL_AREA (area));
572   g_return_if_fail (GTK_IS_WIDGET (widget));
573
574   class = GTK_CELL_AREA_GET_CLASS (area);
575   class->get_preferred_height_for_width (area, widget, width, minimum_height, natural_height);
576 }
577
578 void
579 gtk_cell_area_get_preferred_height (GtkCellArea        *area,
580                                     GtkWidget          *widget,
581                                     gint               *minimum_size,
582                                     gint               *natural_size)
583 {
584   GtkCellAreaClass *class;
585
586   g_return_if_fail (GTK_IS_CELL_AREA (area));
587   g_return_if_fail (GTK_IS_WIDGET (widget));
588
589   class = GTK_CELL_AREA_GET_CLASS (area);
590
591   if (class->get_preferred_height)
592     class->get_preferred_height (area, widget, minimum_size, natural_size);
593   else
594     g_warning ("GtkCellAreaClass::get_preferred_height not implemented for `%s'", 
595                g_type_name (G_TYPE_FROM_INSTANCE (area)));
596 }
597
598 void
599 gtk_cell_area_get_preferred_width_for_height (GtkCellArea        *area,
600                                               GtkWidget          *widget,
601                                               gint                height,
602                                               gint               *minimum_width,
603                                               gint               *natural_width)
604 {
605   GtkCellAreaClass *class;
606
607   g_return_if_fail (GTK_IS_CELL_AREA (area));
608   g_return_if_fail (GTK_IS_WIDGET (widget));
609
610   class = GTK_CELL_AREA_GET_CLASS (area);
611   class->get_preferred_width_for_height (area, widget, height, minimum_width, natural_width);
612 }
613
614 void
615 gtk_cell_area_attribute_connect (GtkCellArea        *area,
616                                  GtkCellRenderer    *renderer,
617                                  const gchar        *attribute,
618                                  gint                column)
619
620   GtkCellAreaPrivate *priv;
621   CellInfo           *info;
622   CellAttribute      *cell_attribute;
623
624   g_return_if_fail (GTK_IS_CELL_AREA (area));
625   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
626   g_return_if_fail (attribute != NULL);
627
628   priv = area->priv;
629   info = g_hash_table_lookup (priv->cell_info, renderer);
630
631   if (!info)
632     {
633       info = cell_info_new (NULL, NULL, NULL);
634
635       g_hash_table_insert (priv->cell_info, renderer, info);
636     }
637   else
638     {
639       GSList *node;
640
641       /* Check we are not adding the same attribute twice */
642       if ((node = g_slist_find_custom (info->attributes, attribute,
643                                        (GCompareFunc)cell_attribute_find)) != NULL)
644         {
645           cell_attribute = node->data;
646
647           g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
648                      "since `%s' is already attributed to column %d", 
649                      attribute,
650                      g_type_name (G_TYPE_FROM_INSTANCE (area)),
651                      attribute, cell_attribute->column);
652           return;
653         }
654     }
655
656   cell_attribute = cell_attribute_new (renderer, attribute, column);
657
658   if (!cell_attribute)
659     {
660       g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
661                  "since attribute does not exist", 
662                  attribute,
663                  g_type_name (G_TYPE_FROM_INSTANCE (area)));
664       return;
665     }
666
667   info->attributes = g_slist_prepend (info->attributes, cell_attribute);
668 }
669
670 void 
671 gtk_cell_area_attribute_disconnect (GtkCellArea        *area,
672                                     GtkCellRenderer    *renderer,
673                                     const gchar        *attribute)
674 {
675   GtkCellAreaPrivate *priv;
676   CellInfo           *info;
677   CellAttribute      *cell_attribute;
678   GSList             *node;
679
680   g_return_if_fail (GTK_IS_CELL_AREA (area));
681   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
682   g_return_if_fail (attribute != NULL);
683
684   priv = area->priv;
685   info = g_hash_table_lookup (priv->cell_info, renderer);
686
687   if (info)
688     {
689       node = g_slist_find_custom (info->attributes, attribute,
690                                   (GCompareFunc)cell_attribute_find);
691       if (node)
692         {
693           cell_attribute = node->data;
694
695           cell_attribute_free (cell_attribute);
696
697           info->attributes = g_slist_delete_link (info->attributes, node);
698         }
699     }
700 }
701
702 static void
703 apply_cell_attributes (GtkCellRenderer *renderer,
704                        CellInfo        *info,
705                        AttributeData   *data)
706 {
707   CellAttribute *attribute;
708   GSList        *list;
709   GValue         value = { 0, };
710
711   /* Apply the attributes directly to the renderer */
712   for (list = info->attributes; list; list = list->next)
713     {
714       attribute = list->data;
715
716       gtk_tree_model_get_value (data->model, data->iter, attribute->column, &value);
717       g_object_set_property (G_OBJECT (renderer), attribute->attribute, &value);
718       g_value_unset (&value);
719     }
720
721   /* Call any GtkCellLayoutDataFunc that may have been set by the user
722    */
723   if (info->func)
724     info->func (GTK_CELL_LAYOUT (data->area), renderer,
725                 data->model, data->iter, info->data);
726 }
727
728 void
729 gtk_cell_area_apply_attributes (GtkCellArea  *area,
730                                 GtkTreeModel *tree_model,
731                                 GtkTreeIter  *iter)
732 {
733   GtkCellAreaPrivate *priv;
734   AttributeData       data;
735
736   g_return_if_fail (GTK_IS_CELL_AREA (area));
737   g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
738   g_return_if_fail (iter != NULL);
739
740   priv = area->priv;
741
742   /* Go over any cells that have attributes or custom GtkCellLayoutDataFuncs and
743    * apply the data from the treemodel */
744   g_hash_table_foreach (priv->cell_info, (GHFunc)apply_cell_attributes, &data);
745 }