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