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