]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellarea.c
cd41fc6cfad061043ace4c2b2980b499af4da435
[~andy/gtk] / gtk / gtkcellarea.c
1 /* gtkcellarea.c
2  *
3  * Copyright (C) 2010 Openismus GmbH
4  *
5  * Authors:
6  *      Tristan Van Berkom <tristanvb@openismus.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #include "config.h"
25
26 #include <stdarg.h>
27 #include <string.h>
28 #include <stdlib.h>
29
30 #include "gtkintl.h"
31 #include "gtkcelllayout.h"
32 #include "gtkcellarea.h"
33 #include "gtkcellareaiter.h"
34 #include "gtkprivate.h"
35
36 #include <gobject/gvaluecollector.h>
37
38
39 /* GObjectClass */
40 static void      gtk_cell_area_dispose                             (GObject            *object);
41 static void      gtk_cell_area_finalize                            (GObject            *object);
42 static void      gtk_cell_area_set_property                        (GObject            *object,
43                                                                     guint               prop_id,
44                                                                     const GValue       *value,
45                                                                     GParamSpec         *pspec);
46 static void      gtk_cell_area_get_property                        (GObject            *object,
47                                                                     guint               prop_id,
48                                                                     GValue             *value,
49                                                                     GParamSpec         *pspec);
50
51 /* GtkCellAreaClass */
52 static void      gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea        *area,
53                                                                     GtkCellAreaIter    *iter,
54                                                                     GtkWidget          *widget,
55                                                                     gint                width,
56                                                                     gint               *minimum_height,
57                                                                     gint               *natural_height);
58 static void      gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea        *area,
59                                                                     GtkCellAreaIter    *iter,
60                                                                     GtkWidget          *widget,
61                                                                     gint                height,
62                                                                     gint               *minimum_width,
63                                                                     gint               *natural_width);
64
65 /* GtkCellLayoutIface */
66 static void      gtk_cell_area_cell_layout_init              (GtkCellLayoutIface    *iface);
67 static void      gtk_cell_area_pack_default                  (GtkCellLayout         *cell_layout,
68                                                               GtkCellRenderer       *renderer,
69                                                               gboolean               expand);
70 static void      gtk_cell_area_clear                         (GtkCellLayout         *cell_layout);
71 static void      gtk_cell_area_add_attribute                 (GtkCellLayout         *cell_layout,
72                                                               GtkCellRenderer       *renderer,
73                                                               const gchar           *attribute,
74                                                               gint                   column);
75 static void      gtk_cell_area_set_cell_data_func            (GtkCellLayout         *cell_layout,
76                                                               GtkCellRenderer       *cell,
77                                                               GtkCellLayoutDataFunc  func,
78                                                               gpointer               func_data,
79                                                               GDestroyNotify         destroy);
80 static void      gtk_cell_area_clear_attributes              (GtkCellLayout         *cell_layout,
81                                                               GtkCellRenderer       *renderer);
82 static void      gtk_cell_area_reorder                       (GtkCellLayout         *cell_layout,
83                                                               GtkCellRenderer       *cell,
84                                                               gint                   position);
85 static GList    *gtk_cell_area_get_cells                     (GtkCellLayout         *cell_layout);
86
87 /* Attribute/Cell metadata */
88 typedef struct {
89   const gchar *attribute;
90   gint         column;
91 } CellAttribute;
92
93 typedef struct {
94   GSList                *attributes;
95
96   GtkCellLayoutDataFunc  func;
97   gpointer               data;
98   GDestroyNotify         destroy;
99 } CellInfo;
100
101 static CellInfo       *cell_info_new       (GtkCellLayoutDataFunc  func,
102                                             gpointer               data,
103                                             GDestroyNotify         destroy);
104 static void            cell_info_free      (CellInfo              *info);
105 static CellAttribute  *cell_attribute_new  (GtkCellRenderer       *renderer,
106                                             const gchar           *attribute,
107                                             gint                   column);
108 static void            cell_attribute_free (CellAttribute         *attribute);
109 static gint            cell_attribute_find (CellAttribute         *cell_attribute,
110                                             const gchar           *attribute);
111
112 /* Struct to pass data along while looping over 
113  * cell renderers to apply attributes
114  */
115 typedef struct {
116   GtkCellArea  *area;
117   GtkTreeModel *model;
118   GtkTreeIter  *iter;
119 } AttributeData;
120
121 struct _GtkCellAreaPrivate
122 {
123   GHashTable *cell_info;
124
125   GtkBorder   cell_border;
126 };
127
128 /* Keep the paramspec pool internal, no need to deliver notifications
129  * on cells. at least no percieved need for now */
130 static GParamSpecPool *cell_property_pool = NULL;
131
132 #define PARAM_SPEC_PARAM_ID(pspec)              ((pspec)->param_id)
133 #define PARAM_SPEC_SET_PARAM_ID(pspec, id)      ((pspec)->param_id = (id))
134
135 enum {
136   PROP_0,
137   PROP_CELL_MARGIN_LEFT,
138   PROP_CELL_MARGIN_RIGHT,
139   PROP_CELL_MARGIN_TOP,
140   PROP_CELL_MARGIN_BOTTOM
141 };
142
143 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkCellArea, gtk_cell_area, G_TYPE_INITIALLY_UNOWNED,
144                                   G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
145                                                          gtk_cell_area_cell_layout_init));
146
147 static void
148 gtk_cell_area_init (GtkCellArea *area)
149 {
150   GtkCellAreaPrivate *priv;
151
152   area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area,
153                                             GTK_TYPE_CELL_AREA,
154                                             GtkCellAreaPrivate);
155   priv = area->priv;
156
157   priv->cell_info = g_hash_table_new_full (g_direct_hash, 
158                                            g_direct_equal,
159                                            NULL, 
160                                            (GDestroyNotify)cell_info_free);
161
162   priv->cell_border.left   = 0;
163   priv->cell_border.right  = 0;
164   priv->cell_border.top    = 0;
165   priv->cell_border.bottom = 0;
166 }
167
168 static void 
169 gtk_cell_area_class_init (GtkCellAreaClass *class)
170 {
171   GObjectClass *object_class = G_OBJECT_CLASS (class);
172   
173   /* GObjectClass */
174   object_class->dispose      = gtk_cell_area_dispose;
175   object_class->finalize     = gtk_cell_area_finalize;
176   object_class->get_property = gtk_cell_area_get_property;
177   object_class->set_property = gtk_cell_area_set_property;
178
179   /* general */
180   class->add     = NULL;
181   class->remove  = NULL;
182   class->forall  = NULL;
183   class->event   = NULL;
184   class->render  = NULL;
185
186   /* geometry */
187   class->create_iter                    = NULL;
188   class->get_request_mode               = NULL;
189   class->get_preferred_width            = NULL;
190   class->get_preferred_height           = NULL;
191   class->get_preferred_height_for_width = gtk_cell_area_real_get_preferred_height_for_width;
192   class->get_preferred_width_for_height = gtk_cell_area_real_get_preferred_width_for_height;
193
194   /* Properties */
195   g_object_class_install_property (object_class,
196                                    PROP_CELL_MARGIN_LEFT,
197                                    g_param_spec_int
198                                    ("cell-margin-left",
199                                     P_("Margin on Left"),
200                                     P_("Pixels of extra space on the left side of each cell"),
201                                     0,
202                                     G_MAXINT16,
203                                     0,
204                                     GTK_PARAM_READWRITE));
205
206   g_object_class_install_property (object_class,
207                                    PROP_CELL_MARGIN_RIGHT,
208                                    g_param_spec_int
209                                    ("cell-margin-right",
210                                     P_("Margin on Right"),
211                                     P_("Pixels of extra space on the right side of each cell"),
212                                     0,
213                                     G_MAXINT16,
214                                     0,
215                                     GTK_PARAM_READWRITE));
216   
217   g_object_class_install_property (object_class,
218                                    PROP_CELL_MARGIN_TOP,
219                                    g_param_spec_int 
220                                    ("cell-margin-top",
221                                     P_("Margin on Top"),
222                                     P_("Pixels of extra space on the top side of each cell"),
223                                     0,
224                                     G_MAXINT16,
225                                     0,
226                                     GTK_PARAM_READWRITE));
227
228   g_object_class_install_property (object_class,
229                                    PROP_CELL_MARGIN_BOTTOM,
230                                    g_param_spec_int
231                                    ("cell-margin-bottom",
232                                     P_("Margin on Bottom"),
233                                     P_("Pixels of extra space on the bottom side of each cell"),
234                                     0,
235                                     G_MAXINT16,
236                                     0,
237                                     GTK_PARAM_READWRITE));
238
239   /* Pool for Cell Properties */
240   if (!cell_property_pool)
241     cell_property_pool = g_param_spec_pool_new (FALSE);
242
243   g_type_class_add_private (object_class, sizeof (GtkCellAreaPrivate));
244 }
245
246 /*************************************************************
247  *                    CellInfo Basics                        *
248  *************************************************************/
249 static CellInfo *
250 cell_info_new (GtkCellLayoutDataFunc  func,
251                gpointer               data,
252                GDestroyNotify         destroy)
253 {
254   CellInfo *info = g_slice_new (CellInfo);
255   
256   info->attributes = NULL;
257   info->func       = func;
258   info->data       = data;
259   info->destroy    = destroy;
260
261   return info;
262 }
263
264 static void
265 cell_info_free (CellInfo *info)
266 {
267   if (info->destroy)
268     info->destroy (info->data);
269
270   g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
271   g_slist_free (info->attributes);
272
273   g_slice_free (CellInfo, info);
274 }
275
276 static CellAttribute  *
277 cell_attribute_new  (GtkCellRenderer       *renderer,
278                      const gchar           *attribute,
279                      gint                   column)
280 {
281   GParamSpec *pspec;
282
283   /* Check if the attribute really exists and point to
284    * the property string installed on the cell renderer
285    * class (dont dup the string) 
286    */
287   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (renderer), attribute);
288
289   if (pspec)
290     {
291       CellAttribute *cell_attribute = g_slice_new (CellAttribute);
292
293       cell_attribute->attribute = pspec->name;
294       cell_attribute->column    = column;
295
296       return cell_attribute;
297     }
298
299   return NULL;
300 }
301
302 static void
303 cell_attribute_free (CellAttribute *attribute)
304 {
305   g_slice_free (CellAttribute, attribute);
306 }
307
308 /* GCompareFunc for g_slist_find_custom() */
309 static gint
310 cell_attribute_find (CellAttribute *cell_attribute,
311                      const gchar   *attribute)
312 {
313   return g_strcmp0 (cell_attribute->attribute, attribute);
314 }
315
316 /*************************************************************
317  *                      GObjectClass                         *
318  *************************************************************/
319 static void
320 gtk_cell_area_finalize (GObject *object)
321 {
322   GtkCellArea        *area   = GTK_CELL_AREA (object);
323   GtkCellAreaPrivate *priv   = area->priv;
324
325   /* All cell renderers should already be removed at this point,
326    * just kill our hash table here. 
327    */
328   g_hash_table_destroy (priv->cell_info);
329
330   G_OBJECT_CLASS (gtk_cell_area_parent_class)->finalize (object);
331 }
332
333
334 static void
335 gtk_cell_area_dispose (GObject *object)
336 {
337   /* This removes every cell renderer that may be added to the GtkCellArea,
338    * subclasses should be breaking references to the GtkCellRenderers 
339    * at this point.
340    */
341   gtk_cell_layout_clear (GTK_CELL_LAYOUT (object));
342
343   G_OBJECT_CLASS (gtk_cell_area_parent_class)->dispose (object);
344 }
345
346 static void
347 gtk_cell_area_set_property (GObject       *object,
348                             guint          prop_id,
349                             const GValue  *value,
350                             GParamSpec    *pspec)
351 {
352   GtkCellArea *area = GTK_CELL_AREA (object);
353
354   switch (prop_id)
355     {
356     case PROP_CELL_MARGIN_LEFT:
357       gtk_cell_area_set_cell_margin_left (area, g_value_get_int (value));
358       break;
359     case PROP_CELL_MARGIN_RIGHT:
360       gtk_cell_area_set_cell_margin_right (area, g_value_get_int (value));
361       break;
362     case PROP_CELL_MARGIN_TOP:
363       gtk_cell_area_set_cell_margin_top (area, g_value_get_int (value));
364       break;
365     case PROP_CELL_MARGIN_BOTTOM:
366       gtk_cell_area_set_cell_margin_bottom (area, g_value_get_int (value));
367       break;
368     default:
369       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
370       break;
371     }
372 }
373
374 static void
375 gtk_cell_area_get_property (GObject     *object,
376                             guint        prop_id,
377                             GValue      *value,
378                             GParamSpec  *pspec)
379 {
380   GtkCellArea        *area = GTK_CELL_AREA (object);
381   GtkCellAreaPrivate *priv = area->priv;
382
383   switch (prop_id)
384     {
385     case PROP_CELL_MARGIN_LEFT:
386       g_value_set_int (value, priv->cell_border.left);
387       break;
388     case PROP_CELL_MARGIN_RIGHT:
389       g_value_set_int (value, priv->cell_border.right);
390       break;
391     case PROP_CELL_MARGIN_TOP:
392       g_value_set_int (value, priv->cell_border.top);
393       break;
394     case PROP_CELL_MARGIN_BOTTOM:
395       g_value_set_int (value, priv->cell_border.bottom);
396       break;
397     default:
398       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
399       break;
400     }
401 }
402
403 /*************************************************************
404  *                    GtkCellAreaClass                       *
405  *************************************************************/
406 static void
407 gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea        *area,
408                                                    GtkCellAreaIter    *iter,
409                                                    GtkWidget          *widget,
410                                                    gint                width,
411                                                    gint               *minimum_height,
412                                                    gint               *natural_height)
413 {
414   /* If the area doesnt do height-for-width, fallback on base preferred height */
415   GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, iter, widget, minimum_height, natural_height);
416 }
417
418 static void
419 gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea        *area,
420                                                    GtkCellAreaIter    *iter,
421                                                    GtkWidget          *widget,
422                                                    gint                height,
423                                                    gint               *minimum_width,
424                                                    gint               *natural_width)
425 {
426   /* If the area doesnt do width-for-height, fallback on base preferred width */
427   GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, iter, widget, minimum_width, natural_width);
428 }
429
430 /*************************************************************
431  *                   GtkCellLayoutIface                      *
432  *************************************************************/
433 static void
434 gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface)
435 {
436   iface->pack_start         = gtk_cell_area_pack_default;
437   iface->pack_end           = gtk_cell_area_pack_default;
438   iface->clear              = gtk_cell_area_clear;
439   iface->add_attribute      = gtk_cell_area_add_attribute;
440   iface->set_cell_data_func = gtk_cell_area_set_cell_data_func;
441   iface->clear_attributes   = gtk_cell_area_clear_attributes;
442   iface->reorder            = gtk_cell_area_reorder;
443   iface->get_cells          = gtk_cell_area_get_cells;
444 }
445
446 static void
447 gtk_cell_area_pack_default (GtkCellLayout         *cell_layout,
448                             GtkCellRenderer       *renderer,
449                             gboolean               expand)
450 {
451   gtk_cell_area_add (GTK_CELL_AREA (cell_layout), renderer);
452 }
453
454 static void
455 gtk_cell_area_clear (GtkCellLayout *cell_layout)
456 {
457   GtkCellArea *area = GTK_CELL_AREA (cell_layout);
458   GList *l, *cells  =
459     gtk_cell_layout_get_cells (cell_layout);
460
461   for (l = cells; l; l = l->next)
462     {
463       GtkCellRenderer *renderer = l->data;
464       gtk_cell_area_remove (area, renderer);
465     }
466
467   g_list_free (cells);
468 }
469
470 static void
471 gtk_cell_area_add_attribute (GtkCellLayout         *cell_layout,
472                              GtkCellRenderer       *renderer,
473                              const gchar           *attribute,
474                              gint                   column)
475 {
476   gtk_cell_area_attribute_connect (GTK_CELL_AREA (cell_layout),
477                                    renderer, attribute, column);
478 }
479
480 static void
481 gtk_cell_area_set_cell_data_func (GtkCellLayout         *cell_layout,
482                                   GtkCellRenderer       *renderer,
483                                   GtkCellLayoutDataFunc  func,
484                                   gpointer               func_data,
485                                   GDestroyNotify         destroy)
486 {
487   GtkCellArea        *area   = GTK_CELL_AREA (cell_layout);
488   GtkCellAreaPrivate *priv   = area->priv;
489   CellInfo           *info;
490
491   info = g_hash_table_lookup (priv->cell_info, renderer);
492
493   if (info)
494     {
495       if (info->destroy && info->data)
496         info->destroy (info->data);
497
498       if (func)
499         {
500           info->func    = func;
501           info->data    = func_data;
502           info->destroy = destroy;
503         }
504       else
505         {
506           info->func    = NULL;
507           info->data    = NULL;
508           info->destroy = NULL;
509         }
510     }
511   else
512     {
513       info = cell_info_new (func, func_data, destroy);
514
515       g_hash_table_insert (priv->cell_info, renderer, info);
516     }
517 }
518
519 static void
520 gtk_cell_area_clear_attributes (GtkCellLayout         *cell_layout,
521                                 GtkCellRenderer       *renderer)
522 {
523   GtkCellArea        *area = GTK_CELL_AREA (cell_layout);
524   GtkCellAreaPrivate *priv = area->priv;
525   CellInfo           *info;
526
527   info = g_hash_table_lookup (priv->cell_info, renderer);
528
529   if (info)
530     {
531       g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
532       g_slist_free (info->attributes);
533
534       info->attributes = NULL;
535     }
536 }
537
538 static void 
539 gtk_cell_area_reorder (GtkCellLayout   *cell_layout,
540                        GtkCellRenderer *cell,
541                        gint             position)
542 {
543   g_warning ("GtkCellLayout::reorder not implemented for `%s'", 
544              g_type_name (G_TYPE_FROM_INSTANCE (cell_layout)));
545 }
546
547 static void
548 accum_cells (GtkCellRenderer *renderer,
549              GList          **accum)
550 {
551   *accum = g_list_prepend (*accum, renderer);
552 }
553
554 static GList *
555 gtk_cell_area_get_cells (GtkCellLayout *cell_layout)
556 {
557   GList *cells = NULL;
558
559   gtk_cell_area_forall (GTK_CELL_AREA (cell_layout), 
560                         (GtkCellCallback)accum_cells,
561                         &cells);
562
563   return g_list_reverse (cells);
564 }
565
566
567 /*************************************************************
568  *                            API                            *
569  *************************************************************/
570 void
571 gtk_cell_area_add (GtkCellArea        *area,
572                    GtkCellRenderer    *renderer)
573 {
574   GtkCellAreaClass *class;
575
576   g_return_if_fail (GTK_IS_CELL_AREA (area));
577   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
578
579   class = GTK_CELL_AREA_GET_CLASS (area);
580
581   if (class->add)
582     class->add (area, renderer);
583   else
584     g_warning ("GtkCellAreaClass::add not implemented for `%s'", 
585                g_type_name (G_TYPE_FROM_INSTANCE (area)));
586 }
587
588 void
589 gtk_cell_area_remove (GtkCellArea        *area,
590                       GtkCellRenderer    *renderer)
591 {
592   GtkCellAreaClass   *class;
593   GtkCellAreaPrivate *priv;
594
595   g_return_if_fail (GTK_IS_CELL_AREA (area));
596   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
597
598   class = GTK_CELL_AREA_GET_CLASS (area);
599   priv  = area->priv;
600
601   /* Remove any custom attributes and custom cell data func here first */
602   g_hash_table_remove (priv->cell_info, renderer);
603
604   if (class->remove)
605     class->remove (area, renderer);
606   else
607     g_warning ("GtkCellAreaClass::remove not implemented for `%s'", 
608                g_type_name (G_TYPE_FROM_INSTANCE (area)));
609 }
610
611 void
612 gtk_cell_area_forall (GtkCellArea        *area,
613                       GtkCellCallback     callback,
614                       gpointer            callback_data)
615 {
616   GtkCellAreaClass *class;
617
618   g_return_if_fail (GTK_IS_CELL_AREA (area));
619   g_return_if_fail (callback != NULL);
620
621   class = GTK_CELL_AREA_GET_CLASS (area);
622
623   if (class->forall)
624     class->forall (area, callback, callback_data);
625   else
626     g_warning ("GtkCellAreaClass::forall not implemented for `%s'", 
627                g_type_name (G_TYPE_FROM_INSTANCE (area)));
628 }
629
630 gint
631 gtk_cell_area_event (GtkCellArea          *area,
632                      GtkCellAreaIter      *iter,
633                      GtkWidget            *widget,
634                      GdkEvent             *event,
635                      const GdkRectangle   *cell_area,
636                      GtkCellRendererState  flags)
637 {
638   GtkCellAreaClass *class;
639
640   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
641   g_return_val_if_fail (GTK_IS_CELL_AREA_ITER (iter), 0);
642   g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
643   g_return_val_if_fail (event != NULL, 0);
644   g_return_val_if_fail (cell_area != NULL, 0);
645
646   class = GTK_CELL_AREA_GET_CLASS (area);
647
648   if (class->event)
649     return class->event (area, iter, widget, event, cell_area, flags);
650
651   g_warning ("GtkCellAreaClass::event not implemented for `%s'", 
652              g_type_name (G_TYPE_FROM_INSTANCE (area)));
653   return 0;
654 }
655
656 void
657 gtk_cell_area_render (GtkCellArea          *area,
658                       GtkCellAreaIter      *iter,
659                       GtkWidget            *widget,
660                       cairo_t              *cr,
661                       const GdkRectangle   *cell_area,
662                       GtkCellRendererState  flags)
663 {
664   GtkCellAreaClass *class;
665
666   g_return_if_fail (GTK_IS_CELL_AREA (area));
667   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
668   g_return_if_fail (GTK_IS_WIDGET (widget));
669   g_return_if_fail (cr != NULL);
670   g_return_if_fail (cell_area != NULL);
671
672   class = GTK_CELL_AREA_GET_CLASS (area);
673
674   if (class->render)
675     class->render (area, iter, widget, cr, cell_area, flags);
676   else
677     g_warning ("GtkCellAreaClass::render not implemented for `%s'", 
678                g_type_name (G_TYPE_FROM_INSTANCE (area)));
679 }
680
681 /* Geometry */
682 GtkCellAreaIter   *
683 gtk_cell_area_create_iter (GtkCellArea *area)
684 {
685   GtkCellAreaClass *class;
686
687   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
688
689   class = GTK_CELL_AREA_GET_CLASS (area);
690
691   if (class->create_iter)
692     return class->create_iter (area);
693
694   g_warning ("GtkCellAreaClass::create_iter not implemented for `%s'", 
695              g_type_name (G_TYPE_FROM_INSTANCE (area)));
696   
697   return NULL;
698 }
699
700
701 GtkSizeRequestMode 
702 gtk_cell_area_get_request_mode (GtkCellArea *area)
703 {
704   GtkCellAreaClass *class;
705
706   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 
707                         GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH);
708
709   class = GTK_CELL_AREA_GET_CLASS (area);
710
711   if (class->get_request_mode)
712     return class->get_request_mode (area);
713
714   g_warning ("GtkCellAreaClass::get_request_mode not implemented for `%s'", 
715              g_type_name (G_TYPE_FROM_INSTANCE (area)));
716   
717   return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
718 }
719
720 void
721 gtk_cell_area_get_preferred_width (GtkCellArea        *area,
722                                    GtkCellAreaIter    *iter,
723                                    GtkWidget          *widget,
724                                    gint               *minimum_size,
725                                    gint               *natural_size)
726 {
727   GtkCellAreaClass *class;
728
729   g_return_if_fail (GTK_IS_CELL_AREA (area));
730   g_return_if_fail (GTK_IS_WIDGET (widget));
731
732   class = GTK_CELL_AREA_GET_CLASS (area);
733
734   if (class->get_preferred_width)
735     class->get_preferred_width (area, iter, widget, minimum_size, natural_size);
736   else
737     g_warning ("GtkCellAreaClass::get_preferred_width not implemented for `%s'", 
738                g_type_name (G_TYPE_FROM_INSTANCE (area)));
739 }
740
741 void
742 gtk_cell_area_get_preferred_height_for_width (GtkCellArea        *area,
743                                               GtkCellAreaIter    *iter,
744                                               GtkWidget          *widget,
745                                               gint                width,
746                                               gint               *minimum_height,
747                                               gint               *natural_height)
748 {
749   GtkCellAreaClass *class;
750
751   g_return_if_fail (GTK_IS_CELL_AREA (area));
752   g_return_if_fail (GTK_IS_WIDGET (widget));
753
754   class = GTK_CELL_AREA_GET_CLASS (area);
755   class->get_preferred_height_for_width (area, iter, widget, width, minimum_height, natural_height);
756 }
757
758 void
759 gtk_cell_area_get_preferred_height (GtkCellArea        *area,
760                                     GtkCellAreaIter    *iter,
761                                     GtkWidget          *widget,
762                                     gint               *minimum_size,
763                                     gint               *natural_size)
764 {
765   GtkCellAreaClass *class;
766
767   g_return_if_fail (GTK_IS_CELL_AREA (area));
768   g_return_if_fail (GTK_IS_WIDGET (widget));
769
770   class = GTK_CELL_AREA_GET_CLASS (area);
771
772   if (class->get_preferred_height)
773     class->get_preferred_height (area, iter, widget, minimum_size, natural_size);
774   else
775     g_warning ("GtkCellAreaClass::get_preferred_height not implemented for `%s'", 
776                g_type_name (G_TYPE_FROM_INSTANCE (area)));
777 }
778
779 void
780 gtk_cell_area_get_preferred_width_for_height (GtkCellArea        *area,
781                                               GtkCellAreaIter    *iter,
782                                               GtkWidget          *widget,
783                                               gint                height,
784                                               gint               *minimum_width,
785                                               gint               *natural_width)
786 {
787   GtkCellAreaClass *class;
788
789   g_return_if_fail (GTK_IS_CELL_AREA (area));
790   g_return_if_fail (GTK_IS_WIDGET (widget));
791
792   class = GTK_CELL_AREA_GET_CLASS (area);
793   class->get_preferred_width_for_height (area, iter, widget, height, minimum_width, natural_width);
794 }
795
796 /* Attributes */
797 void
798 gtk_cell_area_attribute_connect (GtkCellArea        *area,
799                                  GtkCellRenderer    *renderer,
800                                  const gchar        *attribute,
801                                  gint                column)
802
803   GtkCellAreaPrivate *priv;
804   CellInfo           *info;
805   CellAttribute      *cell_attribute;
806
807   g_return_if_fail (GTK_IS_CELL_AREA (area));
808   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
809   g_return_if_fail (attribute != NULL);
810
811   priv = area->priv;
812   info = g_hash_table_lookup (priv->cell_info, renderer);
813
814   if (!info)
815     {
816       info = cell_info_new (NULL, NULL, NULL);
817
818       g_hash_table_insert (priv->cell_info, renderer, info);
819     }
820   else
821     {
822       GSList *node;
823
824       /* Check we are not adding the same attribute twice */
825       if ((node = g_slist_find_custom (info->attributes, attribute,
826                                        (GCompareFunc)cell_attribute_find)) != NULL)
827         {
828           cell_attribute = node->data;
829
830           g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
831                      "since `%s' is already attributed to column %d", 
832                      attribute,
833                      g_type_name (G_TYPE_FROM_INSTANCE (area)),
834                      attribute, cell_attribute->column);
835           return;
836         }
837     }
838
839   cell_attribute = cell_attribute_new (renderer, attribute, column);
840
841   if (!cell_attribute)
842     {
843       g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
844                  "since attribute does not exist", 
845                  attribute,
846                  g_type_name (G_TYPE_FROM_INSTANCE (area)));
847       return;
848     }
849
850   info->attributes = g_slist_prepend (info->attributes, cell_attribute);
851 }
852
853 void 
854 gtk_cell_area_attribute_disconnect (GtkCellArea        *area,
855                                     GtkCellRenderer    *renderer,
856                                     const gchar        *attribute)
857 {
858   GtkCellAreaPrivate *priv;
859   CellInfo           *info;
860   CellAttribute      *cell_attribute;
861   GSList             *node;
862
863   g_return_if_fail (GTK_IS_CELL_AREA (area));
864   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
865   g_return_if_fail (attribute != NULL);
866
867   priv = area->priv;
868   info = g_hash_table_lookup (priv->cell_info, renderer);
869
870   if (info)
871     {
872       node = g_slist_find_custom (info->attributes, attribute,
873                                   (GCompareFunc)cell_attribute_find);
874       if (node)
875         {
876           cell_attribute = node->data;
877
878           cell_attribute_free (cell_attribute);
879
880           info->attributes = g_slist_delete_link (info->attributes, node);
881         }
882     }
883 }
884
885 static void
886 apply_cell_attributes (GtkCellRenderer *renderer,
887                        CellInfo        *info,
888                        AttributeData   *data)
889 {
890   CellAttribute *attribute;
891   GSList        *list;
892   GValue         value = { 0, };
893
894   /* Apply the attributes directly to the renderer */
895   for (list = info->attributes; list; list = list->next)
896     {
897       attribute = list->data;
898
899       gtk_tree_model_get_value (data->model, data->iter, attribute->column, &value);
900       g_object_set_property (G_OBJECT (renderer), attribute->attribute, &value);
901       g_value_unset (&value);
902     }
903
904   /* Call any GtkCellLayoutDataFunc that may have been set by the user
905    */
906   if (info->func)
907     info->func (GTK_CELL_LAYOUT (data->area), renderer,
908                 data->model, data->iter, info->data);
909 }
910
911 void
912 gtk_cell_area_apply_attributes (GtkCellArea  *area,
913                                 GtkTreeModel *tree_model,
914                                 GtkTreeIter  *iter)
915 {
916   GtkCellAreaPrivate *priv;
917   AttributeData       data;
918
919   g_return_if_fail (GTK_IS_CELL_AREA (area));
920   g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
921   g_return_if_fail (iter != NULL);
922
923   priv = area->priv;
924
925   /* Go over any cells that have attributes or custom GtkCellLayoutDataFuncs and
926    * apply the data from the treemodel */
927   g_hash_table_foreach (priv->cell_info, (GHFunc)apply_cell_attributes, &data);
928 }
929
930 /* Cell Properties */
931 void
932 gtk_cell_area_class_install_cell_property (GtkCellAreaClass   *aclass,
933                                            guint               property_id,
934                                            GParamSpec         *pspec)
935 {
936   g_return_if_fail (GTK_IS_CELL_AREA_CLASS (aclass));
937   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
938   if (pspec->flags & G_PARAM_WRITABLE)
939     g_return_if_fail (aclass->set_cell_property != NULL);
940   if (pspec->flags & G_PARAM_READABLE)
941     g_return_if_fail (aclass->get_cell_property != NULL);
942   g_return_if_fail (property_id > 0);
943   g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0);  /* paranoid */
944   g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0);
945
946   if (g_param_spec_pool_lookup (cell_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (aclass), TRUE))
947     {
948       g_warning (G_STRLOC ": class `%s' already contains a cell property named `%s'",
949                  G_OBJECT_CLASS_NAME (aclass), pspec->name);
950       return;
951     }
952   g_param_spec_ref (pspec);
953   g_param_spec_sink (pspec);
954   PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
955   g_param_spec_pool_insert (cell_property_pool, pspec, G_OBJECT_CLASS_TYPE (aclass));
956 }
957
958 GParamSpec*
959 gtk_cell_area_class_find_cell_property (GtkCellAreaClass   *aclass,
960                                         const gchar        *property_name)
961 {
962   g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
963   g_return_val_if_fail (property_name != NULL, NULL);
964
965   return g_param_spec_pool_lookup (cell_property_pool,
966                                    property_name,
967                                    G_OBJECT_CLASS_TYPE (aclass),
968                                    TRUE);
969 }
970
971 GParamSpec**
972 gtk_cell_area_class_list_cell_properties (GtkCellAreaClass   *aclass,
973                                           guint             *n_properties)
974 {
975   GParamSpec **pspecs;
976   guint n;
977
978   g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
979
980   pspecs = g_param_spec_pool_list (cell_property_pool,
981                                    G_OBJECT_CLASS_TYPE (aclass),
982                                    &n);
983   if (n_properties)
984     *n_properties = n;
985
986   return pspecs;
987 }
988
989 void
990 gtk_cell_area_add_with_properties (GtkCellArea        *area,
991                                    GtkCellRenderer    *renderer,
992                                    const gchar        *first_prop_name,
993                                    ...)
994 {
995   GtkCellAreaClass *class;
996
997   g_return_if_fail (GTK_IS_CELL_AREA (area));
998   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
999
1000   class = GTK_CELL_AREA_GET_CLASS (area);
1001
1002   if (class->add)
1003     {
1004       va_list var_args;
1005
1006       class->add (area, renderer);
1007
1008       va_start (var_args, first_prop_name);
1009       gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1010       va_end (var_args);
1011     }
1012   else
1013     g_warning ("GtkCellAreaClass::add not implemented for `%s'", 
1014                g_type_name (G_TYPE_FROM_INSTANCE (area)));
1015 }
1016
1017 void
1018 gtk_cell_area_cell_set (GtkCellArea        *area,
1019                         GtkCellRenderer    *renderer,
1020                         const gchar        *first_prop_name,
1021                         ...)
1022 {
1023   va_list var_args;
1024
1025   g_return_if_fail (GTK_IS_CELL_AREA (area));
1026   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1027
1028   va_start (var_args, first_prop_name);
1029   gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1030   va_end (var_args);
1031 }
1032
1033 void
1034 gtk_cell_area_cell_get (GtkCellArea        *area,
1035                         GtkCellRenderer    *renderer,
1036                         const gchar        *first_prop_name,
1037                         ...)
1038 {
1039   va_list var_args;
1040
1041   g_return_if_fail (GTK_IS_CELL_AREA (area));
1042   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1043
1044   va_start (var_args, first_prop_name);
1045   gtk_cell_area_cell_get_valist (area, renderer, first_prop_name, var_args);
1046   va_end (var_args);
1047 }
1048
1049 static inline void
1050 area_get_cell_property (GtkCellArea     *area,
1051                         GtkCellRenderer *renderer,
1052                         GParamSpec      *pspec,
1053                         GValue          *value)
1054 {
1055   GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1056   
1057   class->get_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), value, pspec);
1058 }
1059
1060 static inline void
1061 area_set_cell_property (GtkCellArea     *area,
1062                         GtkCellRenderer *renderer,
1063                         GParamSpec      *pspec,
1064                         const GValue    *value)
1065 {
1066   GValue tmp_value = { 0, };
1067   GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1068
1069   /* provide a copy to work from, convert (if necessary) and validate */
1070   g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1071   if (!g_value_transform (value, &tmp_value))
1072     g_warning ("unable to set cell property `%s' of type `%s' from value of type `%s'",
1073                pspec->name,
1074                g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1075                G_VALUE_TYPE_NAME (value));
1076   else if (g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION))
1077     {
1078       gchar *contents = g_strdup_value_contents (value);
1079
1080       g_warning ("value \"%s\" of type `%s' is invalid for property `%s' of type `%s'",
1081                  contents,
1082                  G_VALUE_TYPE_NAME (value),
1083                  pspec->name,
1084                  g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
1085       g_free (contents);
1086     }
1087   else
1088     {
1089       class->set_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec);
1090     }
1091   g_value_unset (&tmp_value);
1092 }
1093
1094 void
1095 gtk_cell_area_cell_set_valist (GtkCellArea        *area,
1096                                GtkCellRenderer    *renderer,
1097                                const gchar        *first_property_name,
1098                                va_list             var_args)
1099 {
1100   const gchar *name;
1101
1102   g_return_if_fail (GTK_IS_CELL_AREA (area));
1103   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1104
1105   name = first_property_name;
1106   while (name)
1107     {
1108       GValue value = { 0, };
1109       gchar *error = NULL;
1110       GParamSpec *pspec = 
1111         g_param_spec_pool_lookup (cell_property_pool, name,
1112                                   G_OBJECT_TYPE (area), TRUE);
1113       if (!pspec)
1114         {
1115           g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1116                      G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1117           break;
1118         }
1119       if (!(pspec->flags & G_PARAM_WRITABLE))
1120         {
1121           g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1122                      G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1123           break;
1124         }
1125
1126       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1127       G_VALUE_COLLECT (&value, var_args, 0, &error);
1128       if (error)
1129         {
1130           g_warning ("%s: %s", G_STRLOC, error);
1131           g_free (error);
1132
1133           /* we purposely leak the value here, it might not be
1134            * in a sane state if an error condition occoured
1135            */
1136           break;
1137         }
1138       area_set_cell_property (area, renderer, pspec, &value);
1139       g_value_unset (&value);
1140       name = va_arg (var_args, gchar*);
1141     }
1142 }
1143
1144 void
1145 gtk_cell_area_cell_get_valist (GtkCellArea        *area,
1146                                GtkCellRenderer    *renderer,
1147                                const gchar        *first_property_name,
1148                                va_list             var_args)
1149 {
1150   const gchar *name;
1151
1152   g_return_if_fail (GTK_IS_CELL_AREA (area));
1153   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1154
1155   name = first_property_name;
1156   while (name)
1157     {
1158       GValue value = { 0, };
1159       GParamSpec *pspec;
1160       gchar *error;
1161
1162       pspec = g_param_spec_pool_lookup (cell_property_pool, name,
1163                                         G_OBJECT_TYPE (area), TRUE);
1164       if (!pspec)
1165         {
1166           g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1167                      G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1168           break;
1169         }
1170       if (!(pspec->flags & G_PARAM_READABLE))
1171         {
1172           g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1173                      G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1174           break;
1175         }
1176
1177       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1178       area_get_cell_property (area, renderer, pspec, &value);
1179       G_VALUE_LCOPY (&value, var_args, 0, &error);
1180       if (error)
1181         {
1182           g_warning ("%s: %s", G_STRLOC, error);
1183           g_free (error);
1184           g_value_unset (&value);
1185           break;
1186         }
1187       g_value_unset (&value);
1188       name = va_arg (var_args, gchar*);
1189     }
1190 }
1191
1192 void
1193 gtk_cell_area_cell_set_property (GtkCellArea        *area,
1194                                  GtkCellRenderer    *renderer,
1195                                  const gchar        *property_name,
1196                                  const GValue       *value)
1197 {
1198   GParamSpec *pspec;
1199
1200   g_return_if_fail (GTK_IS_CELL_AREA (area));
1201   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1202   g_return_if_fail (property_name != NULL);
1203   g_return_if_fail (G_IS_VALUE (value));
1204   
1205   pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1206                                     G_OBJECT_TYPE (area), TRUE);
1207   if (!pspec)
1208     g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1209                G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1210   else if (!(pspec->flags & G_PARAM_WRITABLE))
1211     g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1212                G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1213   else
1214     {
1215       area_set_cell_property (area, renderer, pspec, value);
1216     }
1217 }
1218
1219 void
1220 gtk_cell_area_cell_get_property (GtkCellArea        *area,
1221                                  GtkCellRenderer    *renderer,
1222                                  const gchar        *property_name,
1223                                  GValue             *value)
1224 {
1225   GParamSpec *pspec;
1226
1227   g_return_if_fail (GTK_IS_CELL_AREA (area));
1228   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1229   g_return_if_fail (property_name != NULL);
1230   g_return_if_fail (G_IS_VALUE (value));
1231   
1232   pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1233                                     G_OBJECT_TYPE (area), TRUE);
1234   if (!pspec)
1235     g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1236                G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1237   else if (!(pspec->flags & G_PARAM_READABLE))
1238     g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1239                G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1240   else
1241     {
1242       GValue *prop_value, tmp_value = { 0, };
1243
1244       /* auto-conversion of the callers value type
1245        */
1246       if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
1247         {
1248           g_value_reset (value);
1249           prop_value = value;
1250         }
1251       else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
1252         {
1253           g_warning ("can't retrieve cell property `%s' of type `%s' as value of type `%s'",
1254                      pspec->name,
1255                      g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1256                      G_VALUE_TYPE_NAME (value));
1257           return;
1258         }
1259       else
1260         {
1261           g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1262           prop_value = &tmp_value;
1263         }
1264
1265       area_get_cell_property (area, renderer, pspec, prop_value);
1266
1267       if (prop_value != value)
1268         {
1269           g_value_transform (prop_value, value);
1270           g_value_unset (&tmp_value);
1271         }
1272     }
1273 }
1274
1275 /* Margins */
1276 gint
1277 gtk_cell_area_get_cell_margin_left (GtkCellArea *area)
1278 {
1279   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1280
1281   return area->priv->cell_border.left;
1282 }
1283
1284 void
1285 gtk_cell_area_set_cell_margin_left (GtkCellArea *area,
1286                                     gint         margin)
1287 {
1288   GtkCellAreaPrivate *priv;
1289
1290   g_return_if_fail (GTK_IS_CELL_AREA (area));
1291
1292   priv = area->priv;
1293
1294   if (priv->cell_border.left != margin)
1295     {
1296       priv->cell_border.left = margin;
1297
1298       g_object_notify (G_OBJECT (area), "margin-left");
1299     }
1300 }
1301
1302 gint
1303 gtk_cell_area_get_cell_margin_right (GtkCellArea *area)
1304 {
1305   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1306
1307   return area->priv->cell_border.right;
1308 }
1309
1310 void
1311 gtk_cell_area_set_cell_margin_right (GtkCellArea *area,
1312                                      gint         margin)
1313 {
1314   GtkCellAreaPrivate *priv;
1315
1316   g_return_if_fail (GTK_IS_CELL_AREA (area));
1317
1318   priv = area->priv;
1319
1320   if (priv->cell_border.right != margin)
1321     {
1322       priv->cell_border.right = margin;
1323
1324       g_object_notify (G_OBJECT (area), "margin-right");
1325     }
1326 }
1327
1328 gint
1329 gtk_cell_area_get_cell_margin_top (GtkCellArea *area)
1330 {
1331   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1332
1333   return area->priv->cell_border.top;
1334 }
1335
1336 void
1337 gtk_cell_area_set_cell_margin_top (GtkCellArea *area,
1338                                    gint         margin)
1339 {
1340   GtkCellAreaPrivate *priv;
1341
1342   g_return_if_fail (GTK_IS_CELL_AREA (area));
1343
1344   priv = area->priv;
1345
1346   if (priv->cell_border.top != margin)
1347     {
1348       priv->cell_border.top = margin;
1349
1350       g_object_notify (G_OBJECT (area), "margin-top");
1351     }
1352 }
1353
1354 gint
1355 gtk_cell_area_get_cell_margin_bottom (GtkCellArea *area)
1356 {
1357   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1358
1359   return area->priv->cell_border.bottom;
1360 }
1361
1362 void
1363 gtk_cell_area_set_cell_margin_bottom (GtkCellArea *area,
1364                                       gint         margin)
1365 {
1366   GtkCellAreaPrivate *priv;
1367
1368   g_return_if_fail (GTK_IS_CELL_AREA (area));
1369
1370   priv = area->priv;
1371
1372   if (priv->cell_border.bottom != margin)
1373     {
1374       priv->cell_border.bottom = margin;
1375
1376       g_object_notify (G_OBJECT (area), "margin-bottom");
1377     }
1378 }
1379
1380 /* For convenience in area implementations */
1381 void
1382 gtk_cell_area_inner_cell_area (GtkCellArea        *area,
1383                                GdkRectangle       *background_area,
1384                                GdkRectangle       *cell_area)
1385 {
1386   GtkCellAreaPrivate *priv;
1387
1388   g_return_if_fail (GTK_IS_CELL_AREA (area));
1389   g_return_if_fail (background_area != NULL);
1390   g_return_if_fail (cell_area != NULL);
1391
1392   priv = area->priv;
1393
1394   *cell_area = *background_area;
1395
1396   cell_area->x      += priv->cell_border.left;
1397   cell_area->width  -= (priv->cell_border.left + priv->cell_border.right);
1398   cell_area->y      += priv->cell_border.top;
1399   cell_area->height -= (priv->cell_border.top + priv->cell_border.bottom);
1400 }
1401
1402 void
1403 gtk_cell_area_request_renderer (GtkCellArea        *area,
1404                                 GtkCellRenderer    *renderer,
1405                                 GtkOrientation      orientation,
1406                                 GtkWidget          *widget,
1407                                 gint                for_size,
1408                                 gint               *minimum_size,
1409                                 gint               *natural_size)
1410 {
1411   GtkCellAreaPrivate *priv;
1412
1413   g_return_if_fail (GTK_IS_CELL_AREA (area));
1414   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1415   g_return_if_fail (GTK_IS_WIDGET (widget));
1416   g_return_if_fail (minimum_size != NULL);
1417   g_return_if_fail (natural_size != NULL);
1418
1419   priv = area->priv;
1420
1421   if (orientation == GTK_ORIENTATION_HORIZONTAL)
1422     {
1423       if (for_size < 0)
1424           gtk_cell_renderer_get_preferred_width (renderer, widget, minimum_size, natural_size);
1425       else
1426         {
1427           for_size = MAX (0, for_size - (priv->cell_border.top + priv->cell_border.bottom));
1428
1429           gtk_cell_renderer_get_preferred_width_for_height (renderer, widget, for_size, 
1430                                                             minimum_size, natural_size);
1431         }
1432
1433       *minimum_size += (priv->cell_border.left + priv->cell_border.right);
1434       *natural_size += (priv->cell_border.left + priv->cell_border.right);
1435     }
1436   else /* GTK_ORIENTATION_VERTICAL */
1437     {
1438       if (for_size < 0)
1439         gtk_cell_renderer_get_preferred_height (renderer, widget, minimum_size, natural_size);
1440       else
1441         {
1442           for_size = MAX (0, for_size - (priv->cell_border.left + priv->cell_border.right));
1443
1444           gtk_cell_renderer_get_preferred_height_for_width (renderer, widget, for_size, 
1445                                                             minimum_size, natural_size);
1446         }
1447
1448       *minimum_size += (priv->cell_border.top + priv->cell_border.bottom);
1449       *natural_size += (priv->cell_border.top + priv->cell_border.bottom);
1450     }
1451 }