]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellview.c
Don't leak tree model and tree row reference. (#148125, Crispin Flowerday)
[~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 "gtkcellview.h"
22 #include "gtkcelllayout.h"
23 #include "gtkintl.h"
24 #include "gtksignal.h"
25 #include "gtkcellrenderertext.h"
26 #include "gtkcellrendererpixbuf.h"
27 #include <gobject/gmarshal.h>
28
29 typedef struct _GtkCellViewCellInfo GtkCellViewCellInfo;
30 struct _GtkCellViewCellInfo
31 {
32   GtkCellRenderer *cell;
33
34   gint requested_width;
35   gint real_width;
36   guint expand : 1;
37   guint pack : 1;
38
39   GSList *attributes;
40
41   GtkCellLayoutDataFunc func;
42   gpointer func_data;
43   GDestroyNotify destroy;
44 };
45
46 struct _GtkCellViewPrivate
47 {
48   GtkTreeModel *model;
49   GtkTreeRowReference *displayed_row;
50   GList *cell_list;
51   gint spacing;
52
53   GdkColor background;
54   gboolean background_set;
55 };
56
57
58 static void        gtk_cell_view_class_init               (GtkCellViewClass *klass);
59 static void        gtk_cell_view_cell_layout_init         (GtkCellLayoutIface *iface);
60 static void        gtk_cell_view_get_property             (GObject           *object,
61                                                            guint             param_id,
62                                                            GValue           *value,
63                                                            GParamSpec       *pspec);
64 static void        gtk_cell_view_set_property             (GObject          *object,
65                                                            guint             param_id,
66                                                            const GValue     *value,
67                                                            GParamSpec       *pspec);
68 static void        gtk_cell_view_init                     (GtkCellView      *cellview);
69 static void        gtk_cell_view_finalize                 (GObject          *object);
70 static void        gtk_cell_view_style_set                (GtkWidget        *widget,
71                                                            GtkStyle         *previous_style);
72 static void        gtk_cell_view_size_request             (GtkWidget        *widget,
73                                                            GtkRequisition   *requisition);
74 static void        gtk_cell_view_size_allocate            (GtkWidget        *widget,
75                                                            GtkAllocation    *allocation);
76 static gboolean    gtk_cell_view_expose                   (GtkWidget        *widget,
77                                                            GdkEventExpose   *event);
78 static void        gtk_cell_view_set_valuesv              (GtkCellView      *cellview,
79                                                            GtkCellRenderer  *renderer,
80                                                            va_list           args);
81 static GtkCellViewCellInfo *gtk_cell_view_get_cell_info   (GtkCellView      *cellview,
82                                                            GtkCellRenderer  *renderer);
83
84
85 static void        gtk_cell_view_cell_layout_pack_start        (GtkCellLayout         *layout,
86                                                                 GtkCellRenderer       *renderer,
87                                                                 gboolean               expand);
88 static void        gtk_cell_view_cell_layout_pack_end          (GtkCellLayout         *layout,
89                                                                 GtkCellRenderer       *renderer,
90                                                                 gboolean               expand);
91 static void        gtk_cell_view_cell_layout_add_attribute     (GtkCellLayout         *layout,
92                                                                 GtkCellRenderer       *renderer,
93                                                                 const gchar           *attribute,
94                                                                 gint                   column);
95 static void       gtk_cell_view_cell_layout_clear              (GtkCellLayout         *layout);
96 static void       gtk_cell_view_cell_layout_clear_attributes   (GtkCellLayout         *layout,
97                                                                 GtkCellRenderer       *renderer);
98 static void       gtk_cell_view_cell_layout_set_cell_data_func (GtkCellLayout         *layout,
99                                                                 GtkCellRenderer       *cell,
100                                                                 GtkCellLayoutDataFunc  func,
101                                                                 gpointer               func_data,
102                                                                 GDestroyNotify         destroy);
103 static void       gtk_cell_view_cell_layout_reorder            (GtkCellLayout         *layout,
104                                                                 GtkCellRenderer       *cell,
105                                                                 gint                   position);
106
107
108 #define GTK_CELL_VIEW_GET_PRIVATE(obj)    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_CELL_VIEW, GtkCellViewPrivate))
109
110 enum
111 {
112   PROP_0,
113   PROP_BACKGROUND,
114   PROP_BACKGROUND_GDK,
115   PROP_BACKGROUND_SET
116 };
117
118 static GtkObjectClass *parent_class = NULL;
119
120
121 GType
122 gtk_cell_view_get_type (void)
123 {
124   static GType cell_view_type = 0;
125
126   if (!cell_view_type)
127     {
128       static const GTypeInfo cell_view_info =
129         {
130           sizeof (GtkCellViewClass),
131           NULL, /* base_init */
132           NULL, /* base_finalize */
133           (GClassInitFunc) gtk_cell_view_class_init,
134           NULL, /* class_finalize */
135           NULL, /* class_data */
136           sizeof (GtkCellView),
137           0,
138           (GInstanceInitFunc) gtk_cell_view_init
139         };
140
141       static const GInterfaceInfo cell_layout_info =
142        {
143          (GInterfaceInitFunc) gtk_cell_view_cell_layout_init,
144          NULL,
145          NULL
146        };
147
148       cell_view_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkCellView",
149                                                &cell_view_info, 0);
150
151       g_type_add_interface_static (cell_view_type, GTK_TYPE_CELL_LAYOUT,
152                                    &cell_layout_info);
153     }
154
155   return cell_view_type;
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   parent_class = g_type_class_peek_parent (klass);
165
166   gobject_class->get_property = gtk_cell_view_get_property;
167   gobject_class->set_property = gtk_cell_view_set_property;
168   gobject_class->finalize = gtk_cell_view_finalize;
169
170   widget_class->expose_event = gtk_cell_view_expose;
171   widget_class->size_allocate = gtk_cell_view_size_allocate;
172   widget_class->size_request = gtk_cell_view_size_request;
173   widget_class->style_set = gtk_cell_view_style_set;
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                                                         G_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                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
190
191 #define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (gobject_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, G_PARAM_READABLE | G_PARAM_WRITABLE))
192
193   ADD_SET_PROP ("background_set", PROP_BACKGROUND_SET,
194                 P_("Background set"),
195                 P_("Whether this tag affects the background color"));
196
197   g_type_class_add_private (gobject_class, sizeof (GtkCellViewPrivate));
198 }
199
200 static void
201 gtk_cell_view_cell_layout_init (GtkCellLayoutIface *iface)
202 {
203   iface->pack_start = gtk_cell_view_cell_layout_pack_start;
204   iface->pack_end = gtk_cell_view_cell_layout_pack_end;
205   iface->clear = gtk_cell_view_cell_layout_clear;
206   iface->add_attribute = gtk_cell_view_cell_layout_add_attribute;
207   iface->set_cell_data_func = gtk_cell_view_cell_layout_set_cell_data_func;
208   iface->clear_attributes = gtk_cell_view_cell_layout_clear_attributes;
209   iface->reorder = gtk_cell_view_cell_layout_reorder;
210 }
211
212 static void
213 gtk_cell_view_get_property (GObject    *object,
214                             guint       param_id,
215                             GValue     *value,
216                             GParamSpec *pspec)
217 {
218   GtkCellView *view = GTK_CELL_VIEW (object);
219
220   switch (param_id)
221     {
222       case PROP_BACKGROUND_GDK:
223         {
224           GdkColor color;
225
226           color = view->priv->background;
227
228           g_value_set_boxed (value, &color);
229         }
230         break;
231       case PROP_BACKGROUND_SET:
232         g_value_set_boolean (value, view->priv->background_set);
233         break;
234       default:
235         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
236         break;
237     }
238 }
239
240 static void
241 gtk_cell_view_set_property (GObject      *object,
242                             guint         param_id,
243                             const GValue *value,
244                             GParamSpec   *pspec)
245 {
246   GtkCellView *view = GTK_CELL_VIEW (object);
247
248   switch (param_id)
249     {
250       case PROP_BACKGROUND:
251         {
252           GdkColor color;
253
254           if (!g_value_get_string (value))
255             gtk_cell_view_set_background_color (view, NULL);
256           else if (gdk_color_parse (g_value_get_string (value), &color))
257             gtk_cell_view_set_background_color (view, &color);
258           else
259             g_warning ("Don't know color `%s'", g_value_get_string (value));
260
261           g_object_notify (object, "background_gdk");
262         }
263         break;
264       case PROP_BACKGROUND_GDK:
265         gtk_cell_view_set_background_color (view, g_value_get_boxed (value));
266         break;
267       case PROP_BACKGROUND_SET:
268         view->priv->background_set = g_value_get_boolean (value);
269         break;
270       default:
271         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
272         break;
273     }
274 }
275
276 static void
277 gtk_cell_view_init (GtkCellView *cellview)
278 {
279   GTK_WIDGET_SET_FLAGS (cellview, GTK_NO_WINDOW);
280
281   cellview->priv = GTK_CELL_VIEW_GET_PRIVATE (cellview);
282 }
283
284 static void
285 gtk_cell_view_style_set (GtkWidget *widget,
286                          GtkStyle  *previous_style)
287 {
288   if (previous_style && GTK_WIDGET_REALIZED (widget))
289     gdk_window_set_background (widget->window,
290                                &widget->style->base[GTK_WIDGET_STATE (widget)]);
291 }
292
293 static void
294 gtk_cell_view_finalize (GObject *object)
295 {
296   GtkCellView *cellview = GTK_CELL_VIEW (object);
297
298   gtk_cell_view_cell_layout_clear (GTK_CELL_LAYOUT (cellview));
299
300   if (cellview->priv->model)
301      g_object_unref (cellview->priv->model);
302
303   if (cellview->priv->displayed_row)
304      gtk_tree_row_reference_free (cellview->priv->displayed_row);
305
306   if (G_OBJECT_CLASS (parent_class)->finalize)
307     (* G_OBJECT_CLASS (parent_class)->finalize) (object);
308 }
309
310 static void
311 gtk_cell_view_size_request (GtkWidget      *widget,
312                             GtkRequisition *requisition)
313 {
314   GList *i;
315   gboolean first_cell = TRUE;
316   GtkCellView *cellview;
317
318   cellview = GTK_CELL_VIEW (widget);
319
320   requisition->width = 0;
321   requisition->height = 0;
322
323   if (cellview->priv->displayed_row)
324     gtk_cell_view_set_cell_data (cellview);
325
326   for (i = cellview->priv->cell_list; i; i = i->next)
327     {
328       gint width, height;
329       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
330
331       if (!info->cell->visible)
332         continue;
333
334       if (!first_cell)
335         requisition->width += cellview->priv->spacing;
336
337       gtk_cell_renderer_get_size (info->cell, widget, NULL, NULL, NULL,
338                                   &width, &height);
339
340       info->requested_width = width;
341       requisition->width += width;
342       requisition->height = MAX (requisition->height, height);
343
344       first_cell = FALSE;
345     }
346 }
347
348 static void
349 gtk_cell_view_size_allocate (GtkWidget     *widget,
350                              GtkAllocation *allocation)
351 {
352   GList *i;
353   gint expand_cell_count = 0;
354   gint full_requested_width = 0;
355   gint extra_space;
356   GtkCellView *cellview;
357
358   widget->allocation = *allocation;
359
360   cellview = GTK_CELL_VIEW (widget);
361
362   /* checking how much extra space we have */
363   for (i = cellview->priv->cell_list; i; i = i->next)
364     {
365       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
366
367       if (!info->cell->visible)
368         continue;
369
370       if (info->expand)
371         expand_cell_count++;
372
373       full_requested_width += info->requested_width;
374     }
375
376   extra_space = widget->allocation.width - full_requested_width;
377   if (extra_space < 0)
378     extra_space = 0;
379   else if (extra_space > 0 && expand_cell_count > 0)
380     extra_space /= expand_cell_count;
381
382   /* iterate list for PACK_START cells */
383   for (i = cellview->priv->cell_list; i; i = i->next)
384     {
385       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
386
387       if (info->pack == GTK_PACK_END)
388         continue;
389
390       if (!info->cell->visible)
391         continue;
392
393       info->real_width = info->requested_width + (info->expand?extra_space:0);
394     }
395
396   /* iterate list for PACK_END cells */
397   for (i = cellview->priv->cell_list; i; i = i->next)
398     {
399       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
400
401       if (info->pack == GTK_PACK_START)
402         continue;
403
404       if (!info->cell->visible)
405         continue;
406
407       info->real_width = info->requested_width + (info->expand?extra_space:0);
408     }
409 }
410
411 static gboolean
412 gtk_cell_view_expose (GtkWidget      *widget,
413                       GdkEventExpose *event)
414 {
415   GList *i;
416   GtkCellView *cellview;
417   GdkRectangle area;
418   GtkCellRendererState state;
419   gboolean rtl = (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL);
420
421   cellview = GTK_CELL_VIEW (widget);
422
423   if (! GTK_WIDGET_DRAWABLE (widget))
424     return FALSE;
425
426   /* "blank" background */
427   if (cellview->priv->background_set)
428     {
429       GdkGC *gc;
430
431       gc = gdk_gc_new (GTK_WIDGET (cellview)->window);
432       gdk_gc_set_rgb_fg_color (gc, &cellview->priv->background);
433
434       gdk_draw_rectangle (GTK_WIDGET (cellview)->window,
435                           gc,
436                           TRUE,
437
438                           /*0, 0,*/
439                           widget->allocation.x,
440                           widget->allocation.y,
441
442                           widget->allocation.width,
443                           widget->allocation.height);
444
445       g_object_unref (G_OBJECT (gc));
446     }
447
448   /* set cell data (if available) */
449   if (cellview->priv->displayed_row)
450     gtk_cell_view_set_cell_data (cellview);
451   else if (cellview->priv->model)
452     return FALSE;
453
454   /* render cells */
455   area = widget->allocation;
456
457   /* we draw on our very own window, initialize x and y to zero */
458   area.x = widget->allocation.x + (rtl ? widget->allocation.width : 0); 
459   area.y = widget->allocation.y;
460
461   if (GTK_WIDGET_STATE (widget) == GTK_STATE_PRELIGHT)
462     state = GTK_CELL_RENDERER_PRELIT;
463   else
464     state = 0;
465       
466   /* PACK_START */
467   for (i = cellview->priv->cell_list; i; i = i->next)
468     {
469       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
470
471       if (info->pack == GTK_PACK_END)
472         continue;
473
474       if (!info->cell->visible)
475         continue;
476
477       area.width = info->real_width;
478       if (rtl)                                             
479          area.x -= area.width;
480
481       gtk_cell_renderer_render (info->cell,
482                                 event->window,
483                                 widget,
484                                 /* FIXME! */
485                                 &area, &area, &event->area, state);
486
487       if (!rtl)                                           
488          area.x += info->real_width;
489     }
490
491    area.x = rtl ? widget->allocation.x : (widget->allocation.x + widget->allocation.width);  
492
493   /* PACK_END */
494   for (i = cellview->priv->cell_list; i; i = i->next)
495     {
496       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
497
498       if (info->pack == GTK_PACK_START)
499         continue;
500
501       if (!info->cell->visible)
502         continue;
503
504       area.width = info->real_width;
505       if (!rtl)
506          area.x -= area.width;   
507
508       gtk_cell_renderer_render (info->cell,
509                                 widget->window,
510                                 widget,
511                                 /* FIXME ! */
512                                 &area, &area, &event->area, state);
513       if (rtl)
514          area.x += info->real_width;
515     }
516
517   return FALSE;
518 }
519
520 static GtkCellViewCellInfo *
521 gtk_cell_view_get_cell_info (GtkCellView     *cellview,
522                              GtkCellRenderer *renderer)
523 {
524   GList *i;
525
526   for (i = cellview->priv->cell_list; i; i = i->next)
527     {
528       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
529
530       if (info->cell == renderer)
531         return info;
532     }
533
534   return NULL;
535 }
536
537 void
538 gtk_cell_view_set_cell_data (GtkCellView *cellview)
539 {
540   GList *i;
541   GtkTreeIter iter;
542   GtkTreePath *path;
543
544   g_return_if_fail (cellview->priv->displayed_row != NULL);
545
546   path = gtk_tree_row_reference_get_path (cellview->priv->displayed_row);
547   gtk_tree_model_get_iter (cellview->priv->model, &iter, path);
548   gtk_tree_path_free (path);
549
550   for (i = cellview->priv->cell_list; i; i = i->next)
551     {
552       GSList *j;
553       GtkCellViewCellInfo *info = i->data;
554
555       g_object_freeze_notify (G_OBJECT (info->cell));
556
557       for (j = info->attributes; j && j->next; j = j->next->next)
558         {
559           gchar *property = j->data;
560           gint column = GPOINTER_TO_INT (j->next->data);
561           GValue value = {0, };
562
563           gtk_tree_model_get_value (cellview->priv->model, &iter,
564                                     column, &value);
565           g_object_set_property (G_OBJECT (info->cell),
566                                  property, &value);
567           g_value_unset (&value);
568         }
569
570       if (info->func)
571         (* info->func) (GTK_CELL_LAYOUT (cellview),
572                         info->cell,
573                         cellview->priv->model,
574                         &iter,
575                         info->func_data);
576
577       g_object_thaw_notify (G_OBJECT (info->cell));
578     }
579 }
580
581 /* GtkCellLayout implementation */
582 static void
583 gtk_cell_view_cell_layout_pack_start (GtkCellLayout   *layout,
584                                       GtkCellRenderer *renderer,
585                                       gboolean         expand)
586 {
587   GtkCellViewCellInfo *info;
588   GtkCellView *cellview = GTK_CELL_VIEW (layout);
589
590   g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
591   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
592   g_return_if_fail (!gtk_cell_view_get_cell_info (cellview, renderer));
593
594   g_object_ref (G_OBJECT (renderer));
595   gtk_object_sink (GTK_OBJECT (renderer));
596
597   info = g_new0 (GtkCellViewCellInfo, 1);
598   info->cell = renderer;
599   info->expand = expand ? TRUE : FALSE;
600   info->pack = GTK_PACK_START;
601
602   cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info);
603 }
604
605 static void
606 gtk_cell_view_cell_layout_pack_end (GtkCellLayout   *layout,
607                                     GtkCellRenderer *renderer,
608                                     gboolean         expand)
609 {
610   GtkCellViewCellInfo *info;
611   GtkCellView *cellview = GTK_CELL_VIEW (layout);
612
613   g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
614   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
615   g_return_if_fail (!gtk_cell_view_get_cell_info (cellview, renderer));
616
617   g_object_ref (G_OBJECT (renderer));
618   gtk_object_sink (GTK_OBJECT (renderer));
619
620   info = g_new0 (GtkCellViewCellInfo, 1);
621   info->cell = renderer;
622   info->expand = expand ? TRUE : FALSE;
623   info->pack = GTK_PACK_END;
624
625   cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info);
626 }
627
628 static void
629 gtk_cell_view_cell_layout_add_attribute (GtkCellLayout   *layout,
630                                          GtkCellRenderer *renderer,
631                                          const gchar     *attribute,
632                                          gint             column)
633 {
634   GtkCellViewCellInfo *info;
635   GtkCellView *cellview = GTK_CELL_VIEW (layout);
636
637   g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
638   info = gtk_cell_view_get_cell_info (cellview, renderer);
639   g_return_if_fail (info != NULL);
640
641   info->attributes = g_slist_prepend (info->attributes,
642                                       GINT_TO_POINTER (column));
643   info->attributes = g_slist_prepend (info->attributes,
644                                       g_strdup (attribute));
645 }
646
647 static void
648 gtk_cell_view_cell_layout_clear (GtkCellLayout *layout)
649 {
650   GtkCellView *cellview = GTK_CELL_VIEW (layout);
651
652   g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
653
654   while (cellview->priv->cell_list)
655     {
656       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)cellview->priv->cell_list->data;
657
658       gtk_cell_view_cell_layout_clear_attributes (layout, info->cell);
659       g_object_unref (G_OBJECT (info->cell));
660       g_free (info);
661       cellview->priv->cell_list = g_list_delete_link (cellview->priv->cell_list, 
662                                                       cellview->priv->cell_list);
663     }
664 }
665
666 static void
667 gtk_cell_view_cell_layout_set_cell_data_func (GtkCellLayout         *layout,
668                                               GtkCellRenderer       *cell,
669                                               GtkCellLayoutDataFunc  func,
670                                               gpointer               func_data,
671                                               GDestroyNotify         destroy)
672 {
673   GtkCellView *cellview = GTK_CELL_VIEW (layout);
674   GtkCellViewCellInfo *info;
675
676   g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
677
678   info = gtk_cell_view_get_cell_info (cellview, cell);
679   g_return_if_fail (info != NULL);
680
681   if (info->destroy)
682     {
683       GDestroyNotify d = info->destroy;
684
685       info->destroy = NULL;
686       d (info->func_data);
687     }
688
689   info->func = func;
690   info->func_data = func_data;
691   info->destroy = destroy;
692 }
693
694 static void
695 gtk_cell_view_cell_layout_clear_attributes (GtkCellLayout   *layout,
696                                             GtkCellRenderer *renderer)
697 {
698   GtkCellViewCellInfo *info;
699   GtkCellView *cellview = GTK_CELL_VIEW (layout);
700   GSList *list;
701
702   g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
703   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
704
705   info = gtk_cell_view_get_cell_info (cellview, renderer);
706   g_return_if_fail (info != NULL);
707
708   list = info->attributes;
709   while (list && list->next)
710     {
711       g_free (list->data);
712       list = list->next->next;
713     }
714
715   g_slist_free (info->attributes);
716   info->attributes = NULL;
717 }
718
719 static void
720 gtk_cell_view_cell_layout_reorder (GtkCellLayout   *layout,
721                                    GtkCellRenderer *cell,
722                                    gint             position)
723 {
724   GList *link;
725   GtkCellViewCellInfo *info;
726   GtkCellView *cellview = GTK_CELL_VIEW (layout);
727
728   g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
729   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
730
731   info = gtk_cell_view_get_cell_info (cellview, cell);
732
733   g_return_if_fail (info != NULL);
734   g_return_if_fail (position >= 0);
735
736   link = g_list_find (cellview->priv->cell_list, info);
737
738   g_return_if_fail (link != NULL);
739
740   cellview->priv->cell_list = g_list_remove_link (cellview->priv->cell_list,
741                                                   link);
742   cellview->priv->cell_list = g_list_insert (cellview->priv->cell_list,
743                                              info, position);
744
745   gtk_widget_queue_draw (GTK_WIDGET (cellview));
746 }
747
748 /* public API */
749 GtkWidget *
750 gtk_cell_view_new (void)
751 {
752   GtkCellView *cellview;
753
754   cellview = GTK_CELL_VIEW (g_object_new (gtk_cell_view_get_type (), NULL));
755
756   return GTK_WIDGET (cellview);
757 }
758
759 GtkWidget *
760 gtk_cell_view_new_with_text (const gchar *text)
761 {
762   GtkCellView *cellview;
763   GtkCellRenderer *renderer;
764   GValue value = {0, };
765
766   cellview = GTK_CELL_VIEW (gtk_cell_view_new ());
767
768   renderer = gtk_cell_renderer_text_new ();
769   gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview),
770                                         renderer, TRUE);
771
772   g_value_init (&value, G_TYPE_STRING);
773   g_value_set_string (&value, text);
774   gtk_cell_view_set_values (cellview, renderer, "text", &value, NULL);
775   g_value_unset (&value);
776
777   return GTK_WIDGET (cellview);
778 }
779
780 GtkWidget *
781 gtk_cell_view_new_with_markup (const gchar *markup)
782 {
783   GtkCellView *cellview;
784   GtkCellRenderer *renderer;
785   GValue value = {0, };
786
787   cellview = GTK_CELL_VIEW (gtk_cell_view_new ());
788
789   renderer = gtk_cell_renderer_text_new ();
790   gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview),
791                                         renderer, TRUE);
792
793   g_value_init (&value, G_TYPE_STRING);
794   g_value_set_string (&value, markup);
795   gtk_cell_view_set_values (cellview, renderer, "markup", &value, NULL);
796   g_value_unset (&value);
797
798   return GTK_WIDGET (cellview);
799 }
800
801 GtkWidget *
802 gtk_cell_view_new_with_pixbuf (GdkPixbuf *pixbuf)
803 {
804   GtkCellView *cellview;
805   GtkCellRenderer *renderer;
806   GValue value = {0, };
807
808   cellview = GTK_CELL_VIEW (gtk_cell_view_new ());
809
810   renderer = gtk_cell_renderer_pixbuf_new ();
811   gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview),
812                                         renderer, TRUE);
813
814   g_value_init (&value, GDK_TYPE_PIXBUF);
815   g_value_set_object (&value, pixbuf);
816   gtk_cell_view_set_values (cellview, renderer, "pixbuf", &value, NULL);
817   g_value_unset (&value);
818
819   return GTK_WIDGET (cellview);
820 }
821
822 void
823 gtk_cell_view_set_value (GtkCellView     *cell_view,
824                          GtkCellRenderer *renderer,
825                          gchar           *property,
826                          GValue          *value)
827 {
828   g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
829   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
830
831   g_object_set_property (G_OBJECT (renderer), property, value);
832
833   /* force resize and redraw */
834   gtk_widget_queue_resize (GTK_WIDGET (cell_view));
835   gtk_widget_queue_draw (GTK_WIDGET (cell_view));
836 }
837
838 static void
839 gtk_cell_view_set_valuesv (GtkCellView     *cell_view,
840                            GtkCellRenderer *renderer,
841                            va_list          args)
842 {
843   gchar *attribute;
844   GValue *value;
845
846   attribute = va_arg (args, gchar *);
847
848   while (attribute)
849     {
850       value = va_arg (args, GValue *);
851       gtk_cell_view_set_value (cell_view, renderer, attribute, value);
852       attribute = va_arg (args, gchar *);
853     }
854 }
855
856 void
857 gtk_cell_view_set_values (GtkCellView     *cell_view,
858                           GtkCellRenderer *renderer,
859                           ...)
860 {
861   va_list args;
862
863   g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
864   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
865   g_return_if_fail (gtk_cell_view_get_cell_info (cell_view, renderer));
866
867   va_start (args, renderer);
868   gtk_cell_view_set_valuesv (cell_view, renderer, args);
869   va_end (args);
870 }
871
872 void
873 gtk_cell_view_set_model (GtkCellView  *cell_view,
874                          GtkTreeModel *model)
875 {
876   g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
877   g_return_if_fail (GTK_IS_TREE_MODEL (model));
878
879   if (cell_view->priv->model)
880     {
881       if (cell_view->priv->displayed_row)
882         gtk_tree_row_reference_free (cell_view->priv->displayed_row);
883       cell_view->priv->displayed_row = NULL;
884
885       g_object_unref (G_OBJECT (cell_view->priv->model));
886       cell_view->priv->model = NULL;
887     }
888
889   cell_view->priv->model = model;
890
891   if (cell_view->priv->model)
892     g_object_ref (G_OBJECT (cell_view->priv->model));
893 }
894
895 /**
896  * gtk_cell_view_set_displayed_row:
897  * @cell_view: a #GtkCellView
898  * @path: a #GtkTreePath or %NULL to unset.
899  * 
900  * Sets the row of the model that is currently displayed
901  * by the #GtkCellView. If the path is unset, then the
902  * contents of the cellview "stick" at their last value;
903  * this is not normally a desired result, but may be
904  * a needed intermediate state if say, the model for
905  * the #GtkCellView becomes temporarily empty.
906  **/
907 void
908 gtk_cell_view_set_displayed_row (GtkCellView *cell_view,
909                                  GtkTreePath *path)
910 {
911   g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
912   g_return_if_fail (GTK_IS_TREE_MODEL (cell_view->priv->model));
913
914   if (cell_view->priv->displayed_row)
915     gtk_tree_row_reference_free (cell_view->priv->displayed_row);
916
917   if (path)
918     {
919       cell_view->priv->displayed_row =
920         gtk_tree_row_reference_new (cell_view->priv->model, path);
921     }
922   else
923     cell_view->priv->displayed_row = NULL;
924
925   /* force resize and redraw */
926   gtk_widget_queue_resize (GTK_WIDGET (cell_view));
927   gtk_widget_queue_draw (GTK_WIDGET (cell_view));
928 }
929
930 GtkTreePath *
931 gtk_cell_view_get_displayed_row (GtkCellView *cell_view)
932 {
933   g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), NULL);
934
935   if (!cell_view->priv->displayed_row)
936     return NULL;
937
938   return gtk_tree_row_reference_get_path (cell_view->priv->displayed_row);
939 }
940
941 gboolean
942 gtk_cell_view_get_size_of_row (GtkCellView    *cell_view,
943                                GtkTreePath    *path,
944                                GtkRequisition *requisition)
945 {
946   GtkTreeRowReference *tmp;
947
948   g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), FALSE);
949   g_return_val_if_fail (path != NULL, FALSE);
950   g_return_val_if_fail (requisition != NULL, FALSE);
951
952   tmp = cell_view->priv->displayed_row;
953   cell_view->priv->displayed_row =
954     gtk_tree_row_reference_new (cell_view->priv->model, path);
955
956   gtk_cell_view_size_request (GTK_WIDGET (cell_view), requisition);
957
958   gtk_tree_row_reference_free (cell_view->priv->displayed_row);
959   cell_view->priv->displayed_row = tmp;
960
961   return TRUE;
962 }
963
964 void
965 gtk_cell_view_set_background_color (GtkCellView    *view,
966                                     const GdkColor *color)
967 {
968   g_return_if_fail (GTK_IS_CELL_VIEW (view));
969
970   if (color)
971     {
972       if (!view->priv->background_set)
973         {
974           view->priv->background_set = TRUE;
975           g_object_notify (G_OBJECT (view), "background_set");
976         }
977
978       view->priv->background = *color;
979     }
980   else
981     {
982       if (view->priv->background_set)
983         {
984           view->priv->background_set = FALSE;
985           g_object_notify (G_OBJECT (view), "background_set");
986         }
987     }
988 }
989
990 GList *
991 gtk_cell_view_get_cell_renderers (GtkCellView *cell_view)
992 {
993   GList *retval = NULL, *list;
994
995   g_return_val_if_fail (cell_view != NULL, NULL);
996
997   for (list = cell_view->priv->cell_list; list; list = list->next)
998     {
999       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
1000
1001       retval = g_list_prepend (retval, info->cell);
1002     }
1003
1004   return g_list_reverse (retval);
1005 }