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