]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellview.c
GtkCellView: Add gtk_cell_view_set_background_rgba()
[~andy/gtk] / gtk / gtkcellview.c
1 /* gtkellview.c
2  * Copyright (C) 2002, 2003  Kristian Rietveld <kris@gtk.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library 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.
8  *
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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21 #include <string.h>
22 #include "gtkcellview.h"
23 #include "gtkcelllayout.h"
24 #include "gtkintl.h"
25 #include "gtkcellrenderertext.h"
26 #include "gtkcellrendererpixbuf.h"
27 #include "gtkprivate.h"
28 #include "gtksizerequest.h"
29 #include <gobject/gmarshal.h>
30 #include "gtkbuildable.h"
31
32
33 typedef struct _GtkCellViewCellInfo GtkCellViewCellInfo;
34 struct _GtkCellViewCellInfo
35 {
36   GtkCellRenderer *cell;
37
38   gint requested_width;
39   gint natural_width;
40   gint real_width;
41   guint expand : 1;
42   guint pack : 1;
43
44   GSList *attributes;
45
46   GtkCellLayoutDataFunc func;
47   gpointer func_data;
48   GDestroyNotify destroy;
49 };
50
51 struct _GtkCellViewPrivate
52 {
53   GtkTreeModel *model;
54   GtkTreeRowReference *displayed_row;
55   GList *cell_list;
56   gint spacing;
57
58   GdkRGBA background;
59   gboolean background_set;
60 };
61
62
63 static void        gtk_cell_view_cell_layout_init         (GtkCellLayoutIface *iface);
64 static void        gtk_cell_view_get_property             (GObject           *object,
65                                                            guint             param_id,
66                                                            GValue           *value,
67                                                            GParamSpec       *pspec);
68 static void        gtk_cell_view_set_property             (GObject          *object,
69                                                            guint             param_id,
70                                                            const GValue     *value,
71                                                            GParamSpec       *pspec);
72 static void        gtk_cell_view_finalize                 (GObject          *object);
73 static void        gtk_cell_view_size_allocate            (GtkWidget        *widget,
74                                                            GtkAllocation    *allocation);
75 static gboolean    gtk_cell_view_draw                     (GtkWidget        *widget,
76                                                            cairo_t          *cr);
77 static void        gtk_cell_view_set_value                (GtkCellView     *cell_view,
78                                                            GtkCellRenderer *renderer,
79                                                            gchar           *property,
80                                                            GValue          *value);
81 static GtkCellViewCellInfo *gtk_cell_view_get_cell_info   (GtkCellView      *cellview,
82                                                            GtkCellRenderer  *renderer);
83 static void        gtk_cell_view_set_cell_data            (GtkCellView      *cell_view);
84
85
86 static void        gtk_cell_view_cell_layout_pack_start        (GtkCellLayout         *layout,
87                                                                 GtkCellRenderer       *renderer,
88                                                                 gboolean               expand);
89 static void        gtk_cell_view_cell_layout_pack_end          (GtkCellLayout         *layout,
90                                                                 GtkCellRenderer       *renderer,
91                                                                 gboolean               expand);
92 static void        gtk_cell_view_cell_layout_add_attribute     (GtkCellLayout         *layout,
93                                                                 GtkCellRenderer       *renderer,
94                                                                 const gchar           *attribute,
95                                                                 gint                   column);
96 static void       gtk_cell_view_cell_layout_clear              (GtkCellLayout         *layout);
97 static void       gtk_cell_view_cell_layout_clear_attributes   (GtkCellLayout         *layout,
98                                                                 GtkCellRenderer       *renderer);
99 static void       gtk_cell_view_cell_layout_set_cell_data_func (GtkCellLayout         *layout,
100                                                                 GtkCellRenderer       *cell,
101                                                                 GtkCellLayoutDataFunc  func,
102                                                                 gpointer               func_data,
103                                                                 GDestroyNotify         destroy);
104 static void       gtk_cell_view_cell_layout_reorder            (GtkCellLayout         *layout,
105                                                                 GtkCellRenderer       *cell,
106                                                                 gint                   position);
107 static GList *    gtk_cell_view_cell_layout_get_cells          (GtkCellLayout         *layout);
108
109 /* buildable */
110 static void       gtk_cell_view_buildable_init                 (GtkBuildableIface     *iface);
111 static gboolean   gtk_cell_view_buildable_custom_tag_start     (GtkBuildable          *buildable,
112                                                                 GtkBuilder            *builder,
113                                                                 GObject               *child,
114                                                                 const gchar           *tagname,
115                                                                 GMarkupParser         *parser,
116                                                                 gpointer              *data);
117 static void       gtk_cell_view_buildable_custom_tag_end       (GtkBuildable          *buildable,
118                                                                 GtkBuilder            *builder,
119                                                                 GObject               *child,
120                                                                 const gchar           *tagname,
121                                                                 gpointer              *data);
122
123 static void       gtk_cell_view_get_preferred_width            (GtkWidget             *widget,
124                                                                 gint                  *minimum_size,
125                                                                 gint                  *natural_size);
126 static void       gtk_cell_view_get_preferred_height           (GtkWidget             *widget,
127                                                                 gint                  *minimum_size,
128                                                                 gint                  *natural_size);
129 static void       gtk_cell_view_get_preferred_width_for_height (GtkWidget             *widget,
130                                                                 gint                   avail_size,
131                                                                 gint                  *minimum_size,
132                                                                 gint                  *natural_size);
133 static void       gtk_cell_view_get_preferred_height_for_width (GtkWidget             *widget,
134                                                                 gint                   avail_size,
135                                                                 gint                  *minimum_size,
136                                                                 gint                  *natural_size);
137
138 static GtkBuildableIface *parent_buildable_iface;
139
140
141 enum
142 {
143   PROP_0,
144   PROP_BACKGROUND,
145   PROP_BACKGROUND_GDK,
146   PROP_BACKGROUND_RGBA,
147   PROP_BACKGROUND_SET,
148   PROP_MODEL
149 };
150
151 G_DEFINE_TYPE_WITH_CODE (GtkCellView, gtk_cell_view, GTK_TYPE_WIDGET, 
152                          G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
153                                                 gtk_cell_view_cell_layout_init)
154                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
155                                                 gtk_cell_view_buildable_init))
156
157
158 static void
159 gtk_cell_view_class_init (GtkCellViewClass *klass)
160 {
161   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
162   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
163
164   gobject_class->get_property = gtk_cell_view_get_property;
165   gobject_class->set_property = gtk_cell_view_set_property;
166   gobject_class->finalize = gtk_cell_view_finalize;
167
168   widget_class->draw                           = gtk_cell_view_draw;
169   widget_class->size_allocate                  = gtk_cell_view_size_allocate;
170   widget_class->get_preferred_width            = gtk_cell_view_get_preferred_width;
171   widget_class->get_preferred_height           = gtk_cell_view_get_preferred_height;
172   widget_class->get_preferred_width_for_height = gtk_cell_view_get_preferred_width_for_height;
173   widget_class->get_preferred_height_for_width = gtk_cell_view_get_preferred_height_for_width;
174
175   /* properties */
176   g_object_class_install_property (gobject_class,
177                                    PROP_BACKGROUND,
178                                    g_param_spec_string ("background",
179                                                         P_("Background color name"),
180                                                         P_("Background color as a string"),
181                                                         NULL,
182                                                         GTK_PARAM_WRITABLE));
183   g_object_class_install_property (gobject_class,
184                                    PROP_BACKGROUND_GDK,
185                                    g_param_spec_boxed ("background-gdk",
186                                                       P_("Background color"),
187                                                       P_("Background color as a GdkColor"),
188                                                       GDK_TYPE_COLOR,
189                                                       GTK_PARAM_READWRITE));
190   /**
191    * GtkCellView:background-rgba
192    *
193    * The background color as a #GdkRGBA
194    *
195    * Since: 3.0
196    */
197   g_object_class_install_property (gobject_class,
198                                    PROP_BACKGROUND_RGBA,
199                                    g_param_spec_boxed ("background-rgba",
200                                                       P_("Background RGBA color"),
201                                                       P_("Background color as a GdkRGBA"),
202                                                       GDK_TYPE_RGBA,
203                                                       GTK_PARAM_READWRITE));
204
205   /**
206    * GtkCellView:model
207    *
208    * The model for cell view
209    *
210    * since 2.10
211    */
212   g_object_class_install_property (gobject_class,
213                                    PROP_MODEL,
214                                    g_param_spec_object  ("model",
215                                                          P_("CellView model"),
216                                                          P_("The model for cell view"),
217                                                          GTK_TYPE_TREE_MODEL,
218                                                          GTK_PARAM_READWRITE));
219   
220 #define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (gobject_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, GTK_PARAM_READWRITE))
221
222   ADD_SET_PROP ("background-set", PROP_BACKGROUND_SET,
223                 P_("Background set"),
224                 P_("Whether this tag affects the background color"));
225
226   g_type_class_add_private (gobject_class, sizeof (GtkCellViewPrivate));
227 }
228
229 static void
230 gtk_cell_view_buildable_init (GtkBuildableIface *iface)
231 {
232   parent_buildable_iface = g_type_interface_peek_parent (iface);
233   iface->add_child = _gtk_cell_layout_buildable_add_child;
234   iface->custom_tag_start = gtk_cell_view_buildable_custom_tag_start;
235   iface->custom_tag_end = gtk_cell_view_buildable_custom_tag_end;
236 }
237
238 static void
239 gtk_cell_view_cell_layout_init (GtkCellLayoutIface *iface)
240 {
241   iface->pack_start = gtk_cell_view_cell_layout_pack_start;
242   iface->pack_end = gtk_cell_view_cell_layout_pack_end;
243   iface->clear = gtk_cell_view_cell_layout_clear;
244   iface->add_attribute = gtk_cell_view_cell_layout_add_attribute;
245   iface->set_cell_data_func = gtk_cell_view_cell_layout_set_cell_data_func;
246   iface->clear_attributes = gtk_cell_view_cell_layout_clear_attributes;
247   iface->reorder = gtk_cell_view_cell_layout_reorder;
248   iface->get_cells = gtk_cell_view_cell_layout_get_cells;
249 }
250
251 static void
252 gtk_cell_view_get_property (GObject    *object,
253                             guint       param_id,
254                             GValue     *value,
255                             GParamSpec *pspec)
256 {
257   GtkCellView *view = GTK_CELL_VIEW (object);
258
259   switch (param_id)
260     {
261       case PROP_BACKGROUND_GDK:
262         {
263           GdkColor color;
264
265           color.red = (guint) (view->priv->background.red * 65535);
266           color.green = (guint) (view->priv->background.green * 65535);
267           color.blue = (guint) (view->priv->background.blue * 65535);
268           color.pixel = 0;
269
270           g_value_set_boxed (value, &color);
271         }
272         break;
273       case PROP_BACKGROUND_RGBA:
274         g_value_set_boxed (value, &view->priv->background);
275         break;
276       case PROP_BACKGROUND_SET:
277         g_value_set_boolean (value, view->priv->background_set);
278         break;
279       case PROP_MODEL:
280         g_value_set_object (value, view->priv->model);
281         break;
282       default:
283         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
284         break;
285     }
286 }
287
288 static void
289 gtk_cell_view_set_property (GObject      *object,
290                             guint         param_id,
291                             const GValue *value,
292                             GParamSpec   *pspec)
293 {
294   GtkCellView *view = GTK_CELL_VIEW (object);
295
296   switch (param_id)
297     {
298       case PROP_BACKGROUND:
299         {
300           GdkColor color;
301
302           if (!g_value_get_string (value))
303             gtk_cell_view_set_background_color (view, NULL);
304           else if (gdk_color_parse (g_value_get_string (value), &color))
305             gtk_cell_view_set_background_color (view, &color);
306           else
307             g_warning ("Don't know color `%s'", g_value_get_string (value));
308
309           g_object_notify (object, "background-gdk");
310         }
311         break;
312       case PROP_BACKGROUND_GDK:
313         gtk_cell_view_set_background_color (view, g_value_get_boxed (value));
314         break;
315       case PROP_BACKGROUND_RGBA:
316         gtk_cell_view_set_background_rgba (view, g_value_get_boxed (value));
317         break;
318       case PROP_BACKGROUND_SET:
319         view->priv->background_set = g_value_get_boolean (value);
320         break;
321       case PROP_MODEL:
322         gtk_cell_view_set_model (view, g_value_get_object (value));
323         break;
324     default:
325         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
326         break;
327     }
328 }
329
330 static void
331 gtk_cell_view_init (GtkCellView *cellview)
332 {
333   GtkCellViewPrivate *priv;
334
335   cellview->priv = G_TYPE_INSTANCE_GET_PRIVATE (cellview,
336                                                 GTK_TYPE_CELL_VIEW,
337                                                 GtkCellViewPrivate);
338   priv = cellview->priv;
339
340   gtk_widget_set_has_window (GTK_WIDGET (cellview), FALSE);
341 }
342
343 static void
344 gtk_cell_view_finalize (GObject *object)
345 {
346   GtkCellView *cellview = GTK_CELL_VIEW (object);
347
348   gtk_cell_view_cell_layout_clear (GTK_CELL_LAYOUT (cellview));
349
350   if (cellview->priv->model)
351      g_object_unref (cellview->priv->model);
352
353   if (cellview->priv->displayed_row)
354      gtk_tree_row_reference_free (cellview->priv->displayed_row);
355
356   G_OBJECT_CLASS (gtk_cell_view_parent_class)->finalize (object);
357 }
358
359 static void
360 gtk_cell_view_size_allocate (GtkWidget     *widget,
361                              GtkAllocation *allocation)
362 {
363   GtkCellView      *cellview;
364   GtkRequestedSize *sizes;
365   GList            *list;
366   gint              n_visible_cells, n_expand_cells;
367   gint              avail_width = 0;
368   gint              extra_per_cell, extra_extra, i;
369   gboolean          first_cell = TRUE;
370
371   gtk_widget_set_allocation (widget, allocation);
372
373   cellview = GTK_CELL_VIEW (widget);
374
375   avail_width = allocation->width;
376
377   /* Count visible/expand children */
378   for (n_visible_cells = 0, n_expand_cells = 0, list = cellview->priv->cell_list; 
379        list; list = list->next)
380     {
381       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
382
383       n_visible_cells++;
384
385       if (info->expand)
386         n_expand_cells++;
387     }
388
389   sizes = g_new0 (GtkRequestedSize, n_visible_cells);
390
391   /* checking how much extra space we have */
392   for (i = 0, list = cellview->priv->cell_list; list; list = list->next)
393     {
394       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
395
396       if (!gtk_cell_renderer_get_visible (info->cell))
397         continue;
398
399       sizes[i].data = info;
400       sizes[i].minimum_size = info->requested_width;
401       sizes[i].natural_size = info->natural_width;
402
403       if (!first_cell)
404         avail_width -= cellview->priv->spacing;
405
406       avail_width -= sizes[i].minimum_size;
407
408       first_cell = FALSE;
409
410       i++;
411     }
412
413   avail_width = gtk_distribute_natural_allocation (MAX (0, avail_width), n_visible_cells, sizes);
414
415   /* Deal with any expand space... */
416   if (n_expand_cells > 0)
417     {
418       extra_per_cell = avail_width / n_expand_cells;
419       extra_extra    = avail_width % n_expand_cells;
420     }
421   else
422     /* Everything just left-aligned if no cells expand */
423     extra_per_cell = extra_extra = 0;
424
425   for (i = 0, list = cellview->priv->cell_list; list; list = list->next)
426     {
427       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
428
429       if (!gtk_cell_renderer_get_visible (info->cell))
430         continue;
431
432       info->real_width = sizes[i].minimum_size;
433
434       if (info->expand)
435         {
436           info->real_width += extra_per_cell;
437
438           if (extra_extra)
439             {
440               info->real_width++;
441               extra_extra--;
442             }
443         }
444       
445       /* increment index into sizes for visible children */
446       i++;
447     }
448
449   g_free (sizes);
450 }
451
452 static gboolean
453 gtk_cell_view_draw (GtkWidget *widget,
454                     cairo_t   *cr)
455 {
456   GList *list;
457   GtkCellView *cellview;
458   GdkRectangle area;
459   GtkCellRendererState state;
460   gboolean rtl = (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL);
461   GtkPackType packing;
462   int width;
463
464   cellview = GTK_CELL_VIEW (widget);
465
466   /* render cells */
467   area.x = 0;
468   area.y = 0;
469   area.width = width = gtk_widget_get_allocated_width (widget);
470   area.height = gtk_widget_get_allocated_height (widget);
471
472   /* "blank" background */
473   if (cellview->priv->background_set)
474     {
475       gdk_cairo_rectangle (cr, &area);
476       gdk_cairo_set_source_rgba (cr, &cellview->priv->background);
477       cairo_fill (cr);
478     }
479
480   /* set cell data (if available) */
481   if (cellview->priv->displayed_row)
482     gtk_cell_view_set_cell_data (cellview);
483   else if (cellview->priv->model)
484     return FALSE;
485
486   if (gtk_widget_get_state (widget) == GTK_STATE_PRELIGHT)
487     state = GTK_CELL_RENDERER_PRELIT;
488   else if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
489     state = GTK_CELL_RENDERER_INSENSITIVE;
490   else
491     state = 0;
492       
493   for (packing = GTK_PACK_START; packing <= GTK_PACK_END; ++packing)
494     {
495       if (packing == GTK_PACK_START)
496         area.x = rtl ? width : 0;
497       else
498         area.x = rtl ? 0 : width;
499
500       for (list = cellview->priv->cell_list; list; list = list->next)
501         {
502           GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
503
504           if (info->pack != packing)
505             continue;
506
507           if (!gtk_cell_renderer_get_visible (info->cell))
508             continue;
509
510           area.width = info->real_width;
511
512           if ((packing == GTK_PACK_START && rtl) ||
513               (packing == GTK_PACK_END && !rtl))
514             area.x -= area.width;
515
516           gtk_cell_renderer_render (info->cell,
517                                     cr,
518                                     widget,
519                                     /* FIXME! */
520                                     &area, &area, state);
521
522           if ((packing == GTK_PACK_START && !rtl) ||
523               (packing == GTK_PACK_END && rtl))
524             {
525               area.x += area.width;
526               area.x += cellview->priv->spacing;
527             }
528           else
529             area.x -= cellview->priv->spacing;
530         }
531     }
532
533   return FALSE;
534 }
535
536 static GtkCellViewCellInfo *
537 gtk_cell_view_get_cell_info (GtkCellView     *cellview,
538                              GtkCellRenderer *renderer)
539 {
540   GList *i;
541
542   for (i = cellview->priv->cell_list; i; i = i->next)
543     {
544       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
545
546       if (info->cell == renderer)
547         return info;
548     }
549
550   return NULL;
551 }
552
553 static void
554 gtk_cell_view_set_cell_data (GtkCellView *cell_view)
555 {
556   GList *i;
557   GtkTreeIter iter;
558   GtkTreePath *path;
559
560   g_return_if_fail (cell_view->priv->displayed_row != NULL);
561
562   path = gtk_tree_row_reference_get_path (cell_view->priv->displayed_row);
563   if (!path)
564     return;
565
566   gtk_tree_model_get_iter (cell_view->priv->model, &iter, path);
567   gtk_tree_path_free (path);
568
569   for (i = cell_view->priv->cell_list; i; i = i->next)
570     {
571       GSList *j;
572       GtkCellViewCellInfo *info = i->data;
573
574       g_object_freeze_notify (G_OBJECT (info->cell));
575
576       for (j = info->attributes; j && j->next; j = j->next->next)
577         {
578           gchar *property = j->data;
579           gint column = GPOINTER_TO_INT (j->next->data);
580           GValue value = {0, };
581
582           gtk_tree_model_get_value (cell_view->priv->model, &iter,
583                                     column, &value);
584           g_object_set_property (G_OBJECT (info->cell),
585                                  property, &value);
586           g_value_unset (&value);
587         }
588
589       if (info->func)
590         (* info->func) (GTK_CELL_LAYOUT (cell_view),
591                         info->cell,
592                         cell_view->priv->model,
593                         &iter,
594                         info->func_data);
595
596       g_object_thaw_notify (G_OBJECT (info->cell));
597     }
598 }
599
600 /* GtkCellLayout implementation */
601 static void
602 gtk_cell_view_cell_layout_pack_start (GtkCellLayout   *layout,
603                                       GtkCellRenderer *renderer,
604                                       gboolean         expand)
605 {
606   GtkCellViewCellInfo *info;
607   GtkCellView *cellview = GTK_CELL_VIEW (layout);
608
609   g_return_if_fail (!gtk_cell_view_get_cell_info (cellview, renderer));
610
611   g_object_ref_sink (renderer);
612
613   info = g_slice_new0 (GtkCellViewCellInfo);
614   info->cell = renderer;
615   info->expand = expand ? TRUE : FALSE;
616   info->pack = GTK_PACK_START;
617
618   cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info);
619
620   gtk_widget_queue_resize (GTK_WIDGET (cellview));
621 }
622
623 static void
624 gtk_cell_view_cell_layout_pack_end (GtkCellLayout   *layout,
625                                     GtkCellRenderer *renderer,
626                                     gboolean         expand)
627 {
628   GtkCellViewCellInfo *info;
629   GtkCellView *cellview = GTK_CELL_VIEW (layout);
630
631   g_return_if_fail (!gtk_cell_view_get_cell_info (cellview, renderer));
632
633   g_object_ref_sink (renderer);
634
635   info = g_slice_new0 (GtkCellViewCellInfo);
636   info->cell = renderer;
637   info->expand = expand ? TRUE : FALSE;
638   info->pack = GTK_PACK_END;
639
640   cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info);
641
642   gtk_widget_queue_resize (GTK_WIDGET (cellview));
643 }
644
645 static void
646 gtk_cell_view_cell_layout_add_attribute (GtkCellLayout   *layout,
647                                          GtkCellRenderer *renderer,
648                                          const gchar     *attribute,
649                                          gint             column)
650 {
651   GtkCellViewCellInfo *info;
652   GtkCellView *cellview = GTK_CELL_VIEW (layout);
653
654   info = gtk_cell_view_get_cell_info (cellview, renderer);
655   g_return_if_fail (info != NULL);
656
657   info->attributes = g_slist_prepend (info->attributes,
658                                       GINT_TO_POINTER (column));
659   info->attributes = g_slist_prepend (info->attributes,
660                                       g_strdup (attribute));
661 }
662
663 static void
664 gtk_cell_view_cell_layout_clear (GtkCellLayout *layout)
665 {
666   GtkCellView *cellview = GTK_CELL_VIEW (layout);
667
668   while (cellview->priv->cell_list)
669     {
670       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)cellview->priv->cell_list->data;
671
672       gtk_cell_view_cell_layout_clear_attributes (layout, info->cell);
673       g_object_unref (info->cell);
674       g_slice_free (GtkCellViewCellInfo, info);
675       cellview->priv->cell_list = g_list_delete_link (cellview->priv->cell_list, 
676                                                       cellview->priv->cell_list);
677     }
678 }
679
680 static void
681 gtk_cell_view_cell_layout_set_cell_data_func (GtkCellLayout         *layout,
682                                               GtkCellRenderer       *cell,
683                                               GtkCellLayoutDataFunc  func,
684                                               gpointer               func_data,
685                                               GDestroyNotify         destroy)
686 {
687   GtkCellView *cellview = GTK_CELL_VIEW (layout);
688   GtkCellViewCellInfo *info;
689
690   info = gtk_cell_view_get_cell_info (cellview, cell);
691   g_return_if_fail (info != NULL);
692
693   if (info->destroy)
694     {
695       GDestroyNotify d = info->destroy;
696
697       info->destroy = NULL;
698       d (info->func_data);
699     }
700
701   info->func = func;
702   info->func_data = func_data;
703   info->destroy = destroy;
704 }
705
706 static void
707 gtk_cell_view_cell_layout_clear_attributes (GtkCellLayout   *layout,
708                                             GtkCellRenderer *renderer)
709 {
710   GtkCellView *cellview = GTK_CELL_VIEW (layout);
711   GtkCellViewCellInfo *info;
712   GSList *list;
713
714   info = gtk_cell_view_get_cell_info (cellview, renderer);
715   if (info != NULL)
716     {
717       list = info->attributes;
718       while (list && list->next)
719         {
720           g_free (list->data);
721           list = list->next->next;
722         }
723       
724       g_slist_free (info->attributes);
725       info->attributes = NULL;
726     }
727 }
728
729 static void
730 gtk_cell_view_cell_layout_reorder (GtkCellLayout   *layout,
731                                    GtkCellRenderer *cell,
732                                    gint             position)
733 {
734   GtkCellView *cellview = GTK_CELL_VIEW (layout);
735   GtkCellViewCellInfo *info;
736   GList *link;
737
738   info = gtk_cell_view_get_cell_info (cellview, cell);
739
740   g_return_if_fail (info != NULL);
741   g_return_if_fail (position >= 0);
742
743   link = g_list_find (cellview->priv->cell_list, info);
744
745   g_return_if_fail (link != NULL);
746
747   cellview->priv->cell_list = g_list_delete_link (cellview->priv->cell_list,
748                                                   link);
749   cellview->priv->cell_list = g_list_insert (cellview->priv->cell_list,
750                                              info, position);
751
752   gtk_widget_queue_draw (GTK_WIDGET (cellview));
753 }
754
755 /**
756  * gtk_cell_view_new:
757  *
758  * Creates a new #GtkCellView widget.
759  *
760  * Return value: A newly created #GtkCellView widget.
761  *
762  * Since: 2.6
763  */
764 GtkWidget *
765 gtk_cell_view_new (void)
766 {
767   GtkCellView *cellview;
768
769   cellview = g_object_new (gtk_cell_view_get_type (), NULL);
770
771   return GTK_WIDGET (cellview);
772 }
773
774 /**
775  * gtk_cell_view_new_with_text:
776  * @text: the text to display in the cell view
777  *
778  * Creates a new #GtkCellView widget, adds a #GtkCellRendererText 
779  * to it, and makes its show @text.
780  *
781  * Return value: A newly created #GtkCellView widget.
782  *
783  * Since: 2.6
784  */
785 GtkWidget *
786 gtk_cell_view_new_with_text (const gchar *text)
787 {
788   GtkCellView *cellview;
789   GtkCellRenderer *renderer;
790   GValue value = {0, };
791
792   cellview = GTK_CELL_VIEW (gtk_cell_view_new ());
793
794   renderer = gtk_cell_renderer_text_new ();
795   gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview),
796                                         renderer, TRUE);
797
798   g_value_init (&value, G_TYPE_STRING);
799   g_value_set_string (&value, text);
800   gtk_cell_view_set_value (cellview, renderer, "text", &value);
801   g_value_unset (&value);
802
803   return GTK_WIDGET (cellview);
804 }
805
806 /**
807  * gtk_cell_view_new_with_markup:
808  * @markup: the text to display in the cell view
809  *
810  * Creates a new #GtkCellView widget, adds a #GtkCellRendererText 
811  * to it, and makes it show @markup. The text can be
812  * marked up with the <link linkend="PangoMarkupFormat">Pango text 
813  * markup language</link>.
814  *
815  * Return value: A newly created #GtkCellView widget.
816  *
817  * Since: 2.6
818  */
819 GtkWidget *
820 gtk_cell_view_new_with_markup (const gchar *markup)
821 {
822   GtkCellView *cellview;
823   GtkCellRenderer *renderer;
824   GValue value = {0, };
825
826   cellview = GTK_CELL_VIEW (gtk_cell_view_new ());
827
828   renderer = gtk_cell_renderer_text_new ();
829   gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview),
830                                         renderer, TRUE);
831
832   g_value_init (&value, G_TYPE_STRING);
833   g_value_set_string (&value, markup);
834   gtk_cell_view_set_value (cellview, renderer, "markup", &value);
835   g_value_unset (&value);
836
837   return GTK_WIDGET (cellview);
838 }
839
840 /**
841  * gtk_cell_view_new_with_pixbuf:
842  * @pixbuf: the image to display in the cell view
843  *
844  * Creates a new #GtkCellView widget, adds a #GtkCellRendererPixbuf 
845  * to it, and makes its show @pixbuf. 
846  *
847  * Return value: A newly created #GtkCellView widget.
848  *
849  * Since: 2.6
850  */
851 GtkWidget *
852 gtk_cell_view_new_with_pixbuf (GdkPixbuf *pixbuf)
853 {
854   GtkCellView *cellview;
855   GtkCellRenderer *renderer;
856   GValue value = {0, };
857
858   cellview = GTK_CELL_VIEW (gtk_cell_view_new ());
859
860   renderer = gtk_cell_renderer_pixbuf_new ();
861   gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview),
862                                         renderer, TRUE);
863
864   g_value_init (&value, GDK_TYPE_PIXBUF);
865   g_value_set_object (&value, pixbuf);
866   gtk_cell_view_set_value (cellview, renderer, "pixbuf", &value);
867   g_value_unset (&value);
868
869   return GTK_WIDGET (cellview);
870 }
871
872 /**
873  * gtk_cell_view_set_value:
874  * @cell_view: a #GtkCellView widget
875  * @renderer: one of the renderers of @cell_view
876  * @property: the name of the property of @renderer to set
877  * @value: the new value to set the property to
878  * 
879  * Sets a property of a cell renderer of @cell_view, and
880  * makes sure the display of @cell_view is updated.
881  *
882  * Since: 2.6
883  */
884 static void
885 gtk_cell_view_set_value (GtkCellView     *cell_view,
886                          GtkCellRenderer *renderer,
887                          gchar           *property,
888                          GValue          *value)
889 {
890   g_object_set_property (G_OBJECT (renderer), property, value);
891
892   /* force resize and redraw */
893   gtk_widget_queue_resize (GTK_WIDGET (cell_view));
894   gtk_widget_queue_draw (GTK_WIDGET (cell_view));
895 }
896
897 /**
898  * gtk_cell_view_set_model:
899  * @cell_view: a #GtkCellView
900  * @model: (allow-none): a #GtkTreeModel
901  *
902  * Sets the model for @cell_view.  If @cell_view already has a model
903  * set, it will remove it before setting the new model.  If @model is
904  * %NULL, then it will unset the old model.
905  *
906  * Since: 2.6
907  */
908 void
909 gtk_cell_view_set_model (GtkCellView  *cell_view,
910                          GtkTreeModel *model)
911 {
912   g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
913   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
914
915   if (cell_view->priv->model)
916     {
917       if (cell_view->priv->displayed_row)
918         gtk_tree_row_reference_free (cell_view->priv->displayed_row);
919       cell_view->priv->displayed_row = NULL;
920
921       g_object_unref (cell_view->priv->model);
922       cell_view->priv->model = NULL;
923     }
924
925   cell_view->priv->model = model;
926
927   if (cell_view->priv->model)
928     g_object_ref (cell_view->priv->model);
929 }
930
931 /**
932  * gtk_cell_view_get_model:
933  * @cell_view: a #GtkCellView
934  *
935  * Returns the model for @cell_view. If no model is used %NULL is
936  * returned.
937  *
938  * Returns: (transfer none): a #GtkTreeModel used or %NULL
939  *
940  * Since: 2.16
941  **/
942 GtkTreeModel *
943 gtk_cell_view_get_model (GtkCellView *cell_view)
944 {
945   g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), NULL);
946
947   return cell_view->priv->model;
948 }
949
950 /**
951  * gtk_cell_view_set_displayed_row:
952  * @cell_view: a #GtkCellView
953  * @path: (allow-none): a #GtkTreePath or %NULL to unset.
954  *
955  * Sets the row of the model that is currently displayed
956  * by the #GtkCellView. If the path is unset, then the
957  * contents of the cellview "stick" at their last value;
958  * this is not normally a desired result, but may be
959  * a needed intermediate state if say, the model for
960  * the #GtkCellView becomes temporarily empty.
961  *
962  * Since: 2.6
963  **/
964 void
965 gtk_cell_view_set_displayed_row (GtkCellView *cell_view,
966                                  GtkTreePath *path)
967 {
968   g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
969   g_return_if_fail (GTK_IS_TREE_MODEL (cell_view->priv->model));
970
971   if (cell_view->priv->displayed_row)
972     gtk_tree_row_reference_free (cell_view->priv->displayed_row);
973
974   if (path)
975     {
976       cell_view->priv->displayed_row =
977         gtk_tree_row_reference_new (cell_view->priv->model, path);
978     }
979   else
980     cell_view->priv->displayed_row = NULL;
981
982   /* force resize and redraw */
983   gtk_widget_queue_resize (GTK_WIDGET (cell_view));
984   gtk_widget_queue_draw (GTK_WIDGET (cell_view));
985 }
986
987 /**
988  * gtk_cell_view_get_displayed_row:
989  * @cell_view: a #GtkCellView
990  *
991  * Returns a #GtkTreePath referring to the currently 
992  * displayed row. If no row is currently displayed, 
993  * %NULL is returned.
994  *
995  * Returns: the currently displayed row or %NULL
996  *
997  * Since: 2.6
998  */
999 GtkTreePath *
1000 gtk_cell_view_get_displayed_row (GtkCellView *cell_view)
1001 {
1002   g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), NULL);
1003
1004   if (!cell_view->priv->displayed_row)
1005     return NULL;
1006
1007   return gtk_tree_row_reference_get_path (cell_view->priv->displayed_row);
1008 }
1009
1010 /**
1011  * gtk_cell_view_get_size_of_row:
1012  * @cell_view: a #GtkCellView
1013  * @path: a #GtkTreePath 
1014  * @requisition: return location for the size 
1015  *
1016  * Sets @requisition to the size needed by @cell_view to display 
1017  * the model row pointed to by @path.
1018  * 
1019  * Return value: %TRUE
1020  *
1021  * Since: 2.6
1022  * 
1023  * Deprecated: 3.0: Use gtk_cell_view_get_desired_width_of_row() and
1024  * gtk_cell_view_get_desired_height_for_width_of_row() instead.
1025  */
1026 gboolean
1027 gtk_cell_view_get_size_of_row (GtkCellView    *cell_view,
1028                                GtkTreePath    *path,
1029                                GtkRequisition *requisition)
1030 {
1031   GtkRequisition req;
1032
1033   g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), FALSE);
1034   g_return_val_if_fail (path != NULL, FALSE);
1035
1036   /* Return the minimum height for the minimum width */
1037   gtk_cell_view_get_desired_width_of_row (cell_view, path, &req.width, NULL);
1038   gtk_cell_view_get_desired_height_for_width_of_row (cell_view, path, req.width, &req.height, NULL);
1039
1040   if (requisition)
1041     *requisition = req;
1042
1043   return TRUE;
1044 }
1045
1046
1047 /**
1048  * gtk_cell_view_get_desired_width_of_row:
1049  * @cell_view: a #GtkCellView
1050  * @path: a #GtkTreePath 
1051  * @minimum_size: location to store the minimum size 
1052  * @natural_size: location to store the natural size 
1053  *
1054  * Sets @minimum_size and @natural_size to the width desired by @cell_view 
1055  * to display the model row pointed to by @path.
1056  * 
1057  * Since: 3.0
1058  */
1059 void
1060 gtk_cell_view_get_desired_width_of_row (GtkCellView     *cell_view,
1061                                         GtkTreePath     *path,
1062                                         gint            *minimum_size,
1063                                         gint            *natural_size)
1064 {
1065   GtkTreeRowReference *tmp;
1066
1067   g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
1068   g_return_if_fail (path != NULL);
1069   g_return_if_fail (minimum_size != NULL || natural_size != NULL);
1070
1071   tmp = cell_view->priv->displayed_row;
1072   cell_view->priv->displayed_row =
1073     gtk_tree_row_reference_new (cell_view->priv->model, path);
1074
1075   gtk_cell_view_get_preferred_width (GTK_WIDGET (cell_view), minimum_size, natural_size);
1076
1077   gtk_tree_row_reference_free (cell_view->priv->displayed_row);
1078   cell_view->priv->displayed_row = tmp;
1079
1080   /* Restore active size (this will restore the cellrenderer info->width/requested_width's) */
1081   gtk_cell_view_get_preferred_width (GTK_WIDGET (cell_view), NULL, NULL);
1082 }
1083
1084
1085 /**
1086  * gtk_cell_view_get_desired_height_for_width_of_row:
1087  * @cell_view: a #GtkCellView
1088  * @path: a #GtkTreePath 
1089  * @avail_size: available width
1090  * @minimum_size: location to store the minimum height 
1091  * @natural_size: location to store the natural height
1092  *
1093  * Sets @minimum_size and @natural_size to the height desired by @cell_view 
1094  * if it were allocated a width of @avail_size to display the model row 
1095  * pointed to by @path.
1096  * 
1097  * Since: 3.0
1098  */
1099 void
1100 gtk_cell_view_get_desired_height_for_width_of_row (GtkCellView     *cell_view,
1101                                                    GtkTreePath     *path,
1102                                                    gint             avail_size,
1103                                                    gint            *minimum_size,
1104                                                    gint            *natural_size)
1105 {
1106   GtkTreeRowReference *tmp;
1107
1108   g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
1109   g_return_if_fail (path != NULL);
1110   g_return_if_fail (minimum_size != NULL || natural_size != NULL);
1111
1112   tmp = cell_view->priv->displayed_row;
1113   cell_view->priv->displayed_row =
1114     gtk_tree_row_reference_new (cell_view->priv->model, path);
1115
1116   /* Then get the collective height_for_width based on the cached values */
1117   gtk_cell_view_get_preferred_height_for_width (GTK_WIDGET (cell_view), avail_size, minimum_size, natural_size);
1118
1119   gtk_tree_row_reference_free (cell_view->priv->displayed_row);
1120   cell_view->priv->displayed_row = tmp;
1121
1122   /* Restore active size (this will restore the cellrenderer info->width/requested_width's) */
1123   gtk_cell_view_get_preferred_width (GTK_WIDGET (cell_view), NULL, NULL);
1124 }
1125
1126 /**
1127  * gtk_cell_view_set_background_color:
1128  * @cell_view: a #GtkCellView
1129  * @color: the new background color
1130  *
1131  * Sets the background color of @view.
1132  *
1133  * Since: 2.6
1134  */
1135 void
1136 gtk_cell_view_set_background_color (GtkCellView    *cell_view,
1137                                     const GdkColor *color)
1138 {
1139   g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
1140
1141   if (color)
1142     {
1143       if (!cell_view->priv->background_set)
1144         {
1145           cell_view->priv->background_set = TRUE;
1146           g_object_notify (G_OBJECT (cell_view), "background-set");
1147         }
1148
1149       cell_view->priv->background.red = color->red / 65535.;
1150       cell_view->priv->background.green = color->green / 65535.;
1151       cell_view->priv->background.blue = color->blue / 65535.;
1152       cell_view->priv->background.alpha = 1;
1153     }
1154   else
1155     {
1156       if (cell_view->priv->background_set)
1157         {
1158           cell_view->priv->background_set = FALSE;
1159           g_object_notify (G_OBJECT (cell_view), "background-set");
1160         }
1161     }
1162
1163   gtk_widget_queue_draw (GTK_WIDGET (cell_view));
1164 }
1165
1166 /**
1167  * gtk_cell_view_set_background_rgba:
1168  * @cell_view: a #GtkCellView
1169  * @rgba: the new background color
1170  *
1171  * Sets the background color of @cell_view.
1172  *
1173  * Since: 3.0
1174  */
1175 void
1176 gtk_cell_view_set_background_rgba (GtkCellView   *cell_view,
1177                                    const GdkRGBA *rgba)
1178 {
1179   g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
1180
1181   if (rgba)
1182     {
1183       if (!cell_view->priv->background_set)
1184         {
1185           cell_view->priv->background_set = TRUE;
1186           g_object_notify (G_OBJECT (cell_view), "background-set");
1187         }
1188
1189       cell_view->priv->background = *rgba;
1190     }
1191   else
1192     {
1193       if (cell_view->priv->background_set)
1194         {
1195           cell_view->priv->background_set = FALSE;
1196           g_object_notify (G_OBJECT (cell_view), "background-set");
1197         }
1198     }
1199
1200   gtk_widget_queue_draw (GTK_WIDGET (cell_view));
1201 }
1202
1203 static GList *
1204 gtk_cell_view_cell_layout_get_cells (GtkCellLayout *layout)
1205 {
1206   GtkCellView *cell_view = GTK_CELL_VIEW (layout);
1207   GList *retval = NULL, *list;
1208
1209   g_return_val_if_fail (cell_view != NULL, NULL);
1210
1211   gtk_cell_view_set_cell_data (cell_view);
1212
1213   for (list = cell_view->priv->cell_list; list; list = list->next)
1214     {
1215       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
1216
1217       retval = g_list_prepend (retval, info->cell);
1218     }
1219
1220   return g_list_reverse (retval);
1221 }
1222
1223 static gboolean
1224 gtk_cell_view_buildable_custom_tag_start (GtkBuildable  *buildable,
1225                                           GtkBuilder    *builder,
1226                                           GObject       *child,
1227                                           const gchar   *tagname,
1228                                           GMarkupParser *parser,
1229                                           gpointer      *data)
1230 {
1231   if (parent_buildable_iface->custom_tag_start &&
1232       parent_buildable_iface->custom_tag_start (buildable, builder, child,
1233                                                 tagname, parser, data))
1234     return TRUE;
1235
1236   return _gtk_cell_layout_buildable_custom_tag_start (buildable, builder, child,
1237                                                       tagname, parser, data);
1238 }
1239
1240 static void
1241 gtk_cell_view_buildable_custom_tag_end (GtkBuildable *buildable,
1242                                         GtkBuilder   *builder,
1243                                         GObject      *child,
1244                                         const gchar  *tagname,
1245                                         gpointer     *data)
1246 {
1247   if (strcmp (tagname, "attributes") == 0)
1248     _gtk_cell_layout_buildable_custom_tag_end (buildable, builder, child, tagname,
1249                                                data);
1250   else if (parent_buildable_iface->custom_tag_end)
1251     parent_buildable_iface->custom_tag_end (buildable, builder, child, tagname,
1252                                             data);
1253 }
1254
1255 static void
1256 gtk_cell_view_get_preferred_width  (GtkWidget *widget,
1257                                     gint      *minimum_size,
1258                                     gint      *natural_size)
1259 {
1260   GList *list;
1261   gint cell_min, cell_nat;
1262   gboolean first_cell = TRUE;
1263   GtkCellView *cellview = GTK_CELL_VIEW (widget);
1264   gint minimum, natural;
1265
1266   minimum = natural = 0;
1267
1268   if (cellview->priv->displayed_row)
1269     gtk_cell_view_set_cell_data (cellview);
1270
1271   for (list = cellview->priv->cell_list; list; list = list->next)
1272     {
1273       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
1274
1275       if (gtk_cell_renderer_get_visible (info->cell))
1276         {
1277           
1278           if (!first_cell)
1279             {
1280               minimum += cellview->priv->spacing;
1281               natural += cellview->priv->spacing;
1282             }
1283
1284           gtk_cell_renderer_get_preferred_width (info->cell,
1285                                                  GTK_WIDGET (cellview), &cell_min, &cell_nat);
1286           
1287           info->requested_width = cell_min;
1288           info->natural_width   = cell_nat;
1289           
1290           minimum += info->requested_width;
1291           natural += info->natural_width;
1292
1293           first_cell = FALSE;
1294         }
1295     }
1296
1297   if (minimum_size)
1298     *minimum_size = minimum;
1299
1300   if (natural_size)
1301     *natural_size = natural;
1302 }
1303
1304 static void       
1305 gtk_cell_view_get_preferred_height (GtkWidget *widget,
1306                                     gint      *minimum_size,
1307                                     gint      *natural_size)
1308 {
1309   gint minimum_width;
1310
1311   /* CellViews only need to respond to height-for-width mode (cellview is pretty much
1312    * an implementation detail of GtkComboBox) */
1313   gtk_cell_view_get_preferred_width (widget, &minimum_width, NULL);
1314   gtk_cell_view_get_preferred_height_for_width (widget, minimum_width, minimum_size, natural_size);
1315 }
1316
1317 static void       
1318 gtk_cell_view_get_preferred_width_for_height (GtkWidget *widget,
1319                                               gint       for_size,
1320                                               gint      *minimum_size,
1321                                               gint      *natural_size)
1322 {
1323   /* CellViews only need to respond to height-for-width mode (cellview is pretty much
1324    * an implementation detail of GtkComboBox) */
1325   gtk_cell_view_get_preferred_width (widget, minimum_size, natural_size);
1326 }
1327
1328 static void       
1329 gtk_cell_view_get_preferred_height_for_width (GtkWidget *widget,
1330                                               gint       for_size,
1331                                               gint      *minimum_size,
1332                                               gint      *natural_size)
1333 {
1334   GtkCellView      *cellview = GTK_CELL_VIEW (widget);
1335   GList            *list;
1336   GtkRequestedSize *sizes;
1337   GArray           *array;
1338   gint              minimum, natural, avail_size;
1339   gboolean          first_cell = TRUE;
1340   gint              n_expand_cells = 0;
1341   gint              extra_per_cell, extra_extra, i;
1342
1343   minimum = natural = 0;
1344   avail_size = for_size;
1345
1346   array = g_array_new (0, TRUE, sizeof (GtkRequestedSize));
1347
1348   if (cellview->priv->displayed_row)
1349     gtk_cell_view_set_cell_data (cellview);
1350
1351   /* First allocate the right width to all cells */
1352   for (list = cellview->priv->cell_list; list; list = list->next)
1353     {
1354       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
1355
1356       if (gtk_cell_renderer_get_visible (info->cell))
1357         {
1358           GtkRequestedSize requested;
1359
1360           gtk_cell_renderer_get_preferred_width (GTK_CELL_RENDERER (info->cell),
1361                                                  GTK_WIDGET (cellview), 
1362                                                  &requested.minimum_size, 
1363                                                  &requested.natural_size);
1364
1365           requested.data = info;
1366           g_array_append_val (array, requested);
1367
1368           avail_size -= requested.minimum_size;
1369
1370           if (!first_cell)
1371             avail_size -= cellview->priv->spacing;
1372
1373           first_cell = FALSE;
1374
1375           if (info->expand)
1376             n_expand_cells++;
1377         }
1378     }
1379
1380   sizes      = (GtkRequestedSize *)array->data;
1381   avail_size = gtk_distribute_natural_allocation (MAX (0, avail_size), array->len, sizes);
1382
1383   /* Deal with any expand space... */
1384   if (n_expand_cells > 0)
1385     {
1386       extra_per_cell = avail_size / n_expand_cells;
1387       extra_extra    = avail_size % n_expand_cells;
1388     }
1389   else
1390     /* Everything just left-aligned if no cells expand */
1391     extra_per_cell = extra_extra = 0;
1392
1393   /* Now get the height for the real width of each cell */
1394   for (i = 0, list = cellview->priv->cell_list; list; list = list->next)
1395     {
1396       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
1397       gint cell_minimum, cell_natural;
1398
1399       if (gtk_cell_renderer_get_visible (info->cell))
1400         {
1401           gint cell_width = sizes[i].minimum_size;
1402
1403           g_assert (sizes[i].data == info);
1404
1405           if (info->expand)
1406             {
1407               cell_width += extra_per_cell;
1408               if (extra_extra)
1409                 {
1410                   cell_width++;
1411                   extra_extra--;
1412                 }
1413             }
1414
1415           /* Get the height for the real width of this cell */
1416           gtk_cell_renderer_get_preferred_height_for_width (GTK_CELL_RENDERER (info->cell),
1417                                                             GTK_WIDGET (widget),
1418                                                             cell_width, &cell_minimum, &cell_natural);
1419
1420           minimum = MAX (minimum, cell_minimum);
1421           natural = MAX (natural, cell_natural);
1422
1423           /* increment sizes[] index for visible cells */
1424           i++;
1425         }
1426     }
1427
1428   g_array_free (array, TRUE);
1429
1430   if (minimum_size)
1431     *minimum_size = minimum;
1432   if (natural_size)
1433     *natural_size = natural;
1434 }