]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellarea.c
Added margins to the cell area
[~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   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_MARGIN_LEFT,
138   PROP_MARGIN_RIGHT,
139   PROP_MARGIN_TOP,
140   PROP_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->border.left   = 0;
163   priv->border.right  = 0;
164   priv->border.top    = 0;
165   priv->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_MARGIN_LEFT,
197                                    g_param_spec_int ("margin-left",
198                                                      P_("Margin on Left"),
199                                                      P_("Pixels of extra space on the left side"),
200                                                      0,
201                                                      G_MAXINT16,
202                                                      0,
203                                                      GTK_PARAM_READWRITE));
204
205   g_object_class_install_property (object_class,
206                                    PROP_MARGIN_RIGHT,
207                                    g_param_spec_int ("margin-right",
208                                                      P_("Margin on Right"),
209                                                      P_("Pixels of extra space on the right side"),
210                                                      0,
211                                                      G_MAXINT16,
212                                                      0,
213                                                      GTK_PARAM_READWRITE));
214
215   g_object_class_install_property (object_class,
216                                    PROP_MARGIN_TOP,
217                                    g_param_spec_int ("margin-top",
218                                                      P_("Margin on Top"),
219                                                      P_("Pixels of extra space on the top side"),
220                                                      0,
221                                                      G_MAXINT16,
222                                                      0,
223                                                      GTK_PARAM_READWRITE));
224
225   g_object_class_install_property (object_class,
226                                    PROP_MARGIN_BOTTOM,
227                                    g_param_spec_int ("margin-bottom",
228                                                      P_("Margin on Bottom"),
229                                                      P_("Pixels of extra space on the bottom side"),
230                                                      0,
231                                                      G_MAXINT16,
232                                                      0,
233                                                      GTK_PARAM_READWRITE));
234
235   /* Pool for Cell Properties */
236   if (!cell_property_pool)
237     cell_property_pool = g_param_spec_pool_new (FALSE);
238
239   g_type_class_add_private (object_class, sizeof (GtkCellAreaPrivate));
240 }
241
242 /*************************************************************
243  *                    CellInfo Basics                        *
244  *************************************************************/
245 static CellInfo *
246 cell_info_new (GtkCellLayoutDataFunc  func,
247                gpointer               data,
248                GDestroyNotify         destroy)
249 {
250   CellInfo *info = g_slice_new (CellInfo);
251   
252   info->attributes = NULL;
253   info->func       = func;
254   info->data       = data;
255   info->destroy    = destroy;
256
257   return info;
258 }
259
260 static void
261 cell_info_free (CellInfo *info)
262 {
263   if (info->destroy)
264     info->destroy (info->data);
265
266   g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
267   g_slist_free (info->attributes);
268
269   g_slice_free (CellInfo, info);
270 }
271
272 static CellAttribute  *
273 cell_attribute_new  (GtkCellRenderer       *renderer,
274                      const gchar           *attribute,
275                      gint                   column)
276 {
277   GParamSpec *pspec;
278
279   /* Check if the attribute really exists and point to
280    * the property string installed on the cell renderer
281    * class (dont dup the string) 
282    */
283   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (renderer), attribute);
284
285   if (pspec)
286     {
287       CellAttribute *cell_attribute = g_slice_new (CellAttribute);
288
289       cell_attribute->attribute = pspec->name;
290       cell_attribute->column    = column;
291
292       return cell_attribute;
293     }
294
295   return NULL;
296 }
297
298 static void
299 cell_attribute_free (CellAttribute *attribute)
300 {
301   g_slice_free (CellAttribute, attribute);
302 }
303
304 /* GCompareFunc for g_slist_find_custom() */
305 static gint
306 cell_attribute_find (CellAttribute *cell_attribute,
307                      const gchar   *attribute)
308 {
309   return g_strcmp0 (cell_attribute->attribute, attribute);
310 }
311
312 /*************************************************************
313  *                      GObjectClass                         *
314  *************************************************************/
315 static void
316 gtk_cell_area_finalize (GObject *object)
317 {
318   GtkCellArea        *area   = GTK_CELL_AREA (object);
319   GtkCellAreaPrivate *priv   = area->priv;
320
321   /* All cell renderers should already be removed at this point,
322    * just kill our hash table here. 
323    */
324   g_hash_table_destroy (priv->cell_info);
325
326   G_OBJECT_CLASS (gtk_cell_area_parent_class)->finalize (object);
327 }
328
329
330 static void
331 gtk_cell_area_dispose (GObject *object)
332 {
333   /* This removes every cell renderer that may be added to the GtkCellArea,
334    * subclasses should be breaking references to the GtkCellRenderers 
335    * at this point.
336    */
337   gtk_cell_layout_clear (GTK_CELL_LAYOUT (object));
338
339   G_OBJECT_CLASS (gtk_cell_area_parent_class)->dispose (object);
340 }
341
342 static void
343 gtk_cell_area_set_property (GObject       *object,
344                             guint          prop_id,
345                             const GValue  *value,
346                             GParamSpec    *pspec)
347 {
348   GtkCellArea *area = GTK_CELL_AREA (object);
349
350   switch (prop_id)
351     {
352     case PROP_MARGIN_LEFT:
353       gtk_cell_area_set_margin_left (area, g_value_get_int (value));
354       break;
355     case PROP_MARGIN_RIGHT:
356       gtk_cell_area_set_margin_right (area, g_value_get_int (value));
357       break;
358     case PROP_MARGIN_TOP:
359       gtk_cell_area_set_margin_top (area, g_value_get_int (value));
360       break;
361     case PROP_MARGIN_BOTTOM:
362       gtk_cell_area_set_margin_bottom (area, g_value_get_int (value));
363       break;
364     default:
365       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
366       break;
367     }
368 }
369
370 static void
371 gtk_cell_area_get_property (GObject     *object,
372                             guint        prop_id,
373                             GValue      *value,
374                             GParamSpec  *pspec)
375 {
376   GtkCellArea        *area = GTK_CELL_AREA (object);
377   GtkCellAreaPrivate *priv = area->priv;
378
379   switch (prop_id)
380     {
381     case PROP_MARGIN_LEFT:
382       g_value_set_int (value, priv->border.left);
383       break;
384     case PROP_MARGIN_RIGHT:
385       g_value_set_int (value, priv->border.right);
386       break;
387     case PROP_MARGIN_TOP:
388       g_value_set_int (value, priv->border.top);
389       break;
390     case PROP_MARGIN_BOTTOM:
391       g_value_set_int (value, priv->border.bottom);
392       break;
393     default:
394       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
395       break;
396     }
397 }
398
399 /*************************************************************
400  *                    GtkCellAreaClass                       *
401  *************************************************************/
402 static void
403 gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea        *area,
404                                                    GtkCellAreaIter    *iter,
405                                                    GtkWidget          *widget,
406                                                    gint                width,
407                                                    gint               *minimum_height,
408                                                    gint               *natural_height)
409 {
410   /* If the area doesnt do height-for-width, fallback on base preferred height */
411   GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, iter, widget, minimum_height, natural_height);
412 }
413
414 static void
415 gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea        *area,
416                                                    GtkCellAreaIter    *iter,
417                                                    GtkWidget          *widget,
418                                                    gint                height,
419                                                    gint               *minimum_width,
420                                                    gint               *natural_width)
421 {
422   /* If the area doesnt do width-for-height, fallback on base preferred width */
423   GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, iter, widget, minimum_width, natural_width);
424 }
425
426 /*************************************************************
427  *                   GtkCellLayoutIface                      *
428  *************************************************************/
429 static void
430 gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface)
431 {
432   iface->pack_start         = gtk_cell_area_pack_default;
433   iface->pack_end           = gtk_cell_area_pack_default;
434   iface->clear              = gtk_cell_area_clear;
435   iface->add_attribute      = gtk_cell_area_add_attribute;
436   iface->set_cell_data_func = gtk_cell_area_set_cell_data_func;
437   iface->clear_attributes   = gtk_cell_area_clear_attributes;
438   iface->reorder            = gtk_cell_area_reorder;
439   iface->get_cells          = gtk_cell_area_get_cells;
440 }
441
442 static void
443 gtk_cell_area_pack_default (GtkCellLayout         *cell_layout,
444                             GtkCellRenderer       *renderer,
445                             gboolean               expand)
446 {
447   gtk_cell_area_add (GTK_CELL_AREA (cell_layout), renderer);
448 }
449
450 static void
451 gtk_cell_area_clear (GtkCellLayout *cell_layout)
452 {
453   GtkCellArea *area = GTK_CELL_AREA (cell_layout);
454   GList *l, *cells  =
455     gtk_cell_layout_get_cells (cell_layout);
456
457   for (l = cells; l; l = l->next)
458     {
459       GtkCellRenderer *renderer = l->data;
460       gtk_cell_area_remove (area, renderer);
461     }
462
463   g_list_free (cells);
464 }
465
466 static void
467 gtk_cell_area_add_attribute (GtkCellLayout         *cell_layout,
468                              GtkCellRenderer       *renderer,
469                              const gchar           *attribute,
470                              gint                   column)
471 {
472   gtk_cell_area_attribute_connect (GTK_CELL_AREA (cell_layout),
473                                    renderer, attribute, column);
474 }
475
476 static void
477 gtk_cell_area_set_cell_data_func (GtkCellLayout         *cell_layout,
478                                   GtkCellRenderer       *renderer,
479                                   GtkCellLayoutDataFunc  func,
480                                   gpointer               func_data,
481                                   GDestroyNotify         destroy)
482 {
483   GtkCellArea        *area   = GTK_CELL_AREA (cell_layout);
484   GtkCellAreaPrivate *priv   = area->priv;
485   CellInfo           *info;
486
487   info = g_hash_table_lookup (priv->cell_info, renderer);
488
489   if (info)
490     {
491       if (info->destroy && info->data)
492         info->destroy (info->data);
493
494       if (func)
495         {
496           info->func    = func;
497           info->data    = func_data;
498           info->destroy = destroy;
499         }
500       else
501         {
502           info->func    = NULL;
503           info->data    = NULL;
504           info->destroy = NULL;
505         }
506     }
507   else
508     {
509       info = cell_info_new (func, func_data, destroy);
510
511       g_hash_table_insert (priv->cell_info, renderer, info);
512     }
513 }
514
515 static void
516 gtk_cell_area_clear_attributes (GtkCellLayout         *cell_layout,
517                                 GtkCellRenderer       *renderer)
518 {
519   GtkCellArea        *area = GTK_CELL_AREA (cell_layout);
520   GtkCellAreaPrivate *priv = area->priv;
521   CellInfo           *info;
522
523   info = g_hash_table_lookup (priv->cell_info, renderer);
524
525   if (info)
526     {
527       g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
528       g_slist_free (info->attributes);
529
530       info->attributes = NULL;
531     }
532 }
533
534 static void 
535 gtk_cell_area_reorder (GtkCellLayout   *cell_layout,
536                        GtkCellRenderer *cell,
537                        gint             position)
538 {
539   g_warning ("GtkCellLayout::reorder not implemented for `%s'", 
540              g_type_name (G_TYPE_FROM_INSTANCE (cell_layout)));
541 }
542
543 static void
544 accum_cells (GtkCellRenderer *renderer,
545              GList          **accum)
546 {
547   *accum = g_list_prepend (*accum, renderer);
548 }
549
550 static GList *
551 gtk_cell_area_get_cells (GtkCellLayout *cell_layout)
552 {
553   GList *cells = NULL;
554
555   gtk_cell_area_forall (GTK_CELL_AREA (cell_layout), 
556                         (GtkCellCallback)accum_cells,
557                         &cells);
558
559   return g_list_reverse (cells);
560 }
561
562
563 /*************************************************************
564  *                            API                            *
565  *************************************************************/
566 void
567 gtk_cell_area_add (GtkCellArea        *area,
568                    GtkCellRenderer    *renderer)
569 {
570   GtkCellAreaClass *class;
571
572   g_return_if_fail (GTK_IS_CELL_AREA (area));
573   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
574
575   class = GTK_CELL_AREA_GET_CLASS (area);
576
577   if (class->add)
578     class->add (area, renderer);
579   else
580     g_warning ("GtkCellAreaClass::add not implemented for `%s'", 
581                g_type_name (G_TYPE_FROM_INSTANCE (area)));
582 }
583
584 void
585 gtk_cell_area_remove (GtkCellArea        *area,
586                       GtkCellRenderer    *renderer)
587 {
588   GtkCellAreaClass   *class;
589   GtkCellAreaPrivate *priv;
590
591   g_return_if_fail (GTK_IS_CELL_AREA (area));
592   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
593
594   class = GTK_CELL_AREA_GET_CLASS (area);
595   priv  = area->priv;
596
597   /* Remove any custom attributes and custom cell data func here first */
598   g_hash_table_remove (priv->cell_info, renderer);
599
600   if (class->remove)
601     class->remove (area, renderer);
602   else
603     g_warning ("GtkCellAreaClass::remove not implemented for `%s'", 
604                g_type_name (G_TYPE_FROM_INSTANCE (area)));
605 }
606
607 void
608 gtk_cell_area_forall (GtkCellArea        *area,
609                       GtkCellCallback     callback,
610                       gpointer            callback_data)
611 {
612   GtkCellAreaClass *class;
613
614   g_return_if_fail (GTK_IS_CELL_AREA (area));
615   g_return_if_fail (callback != NULL);
616
617   class = GTK_CELL_AREA_GET_CLASS (area);
618
619   if (class->forall)
620     class->forall (area, callback, callback_data);
621   else
622     g_warning ("GtkCellAreaClass::forall not implemented for `%s'", 
623                g_type_name (G_TYPE_FROM_INSTANCE (area)));
624 }
625
626 gint
627 gtk_cell_area_event (GtkCellArea        *area,
628                      GtkCellAreaIter    *iter,
629                      GtkWidget          *widget,
630                      GdkEvent           *event,
631                      const GdkRectangle *cell_area)
632 {
633   GtkCellAreaClass *class;
634
635   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
636   g_return_val_if_fail (GTK_IS_CELL_AREA_ITER (iter), 0);
637   g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
638   g_return_val_if_fail (event != NULL, 0);
639   g_return_val_if_fail (cell_area != NULL, 0);
640
641   class = GTK_CELL_AREA_GET_CLASS (area);
642
643   if (class->event)
644     return class->event (area, iter, widget, event, cell_area);
645
646   g_warning ("GtkCellAreaClass::event not implemented for `%s'", 
647              g_type_name (G_TYPE_FROM_INSTANCE (area)));
648   return 0;
649 }
650
651 void
652 gtk_cell_area_render (GtkCellArea        *area,
653                       GtkCellAreaIter    *iter,
654                       GtkWidget          *widget,
655                       cairo_t            *cr,
656                       const GdkRectangle *cell_area)
657 {
658   GtkCellAreaClass *class;
659
660   g_return_if_fail (GTK_IS_CELL_AREA (area));
661   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
662   g_return_if_fail (GTK_IS_WIDGET (widget));
663   g_return_if_fail (cr != NULL);
664   g_return_if_fail (cell_area != NULL);
665
666   class = GTK_CELL_AREA_GET_CLASS (area);
667
668   if (class->render)
669     class->render (area, iter, widget, cr, cell_area);
670   else
671     g_warning ("GtkCellAreaClass::render not implemented for `%s'", 
672                g_type_name (G_TYPE_FROM_INSTANCE (area)));
673 }
674
675 /* Geometry */
676 GtkCellAreaIter   *
677 gtk_cell_area_create_iter (GtkCellArea *area)
678 {
679   GtkCellAreaClass *class;
680
681   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
682
683   class = GTK_CELL_AREA_GET_CLASS (area);
684
685   if (class->create_iter)
686     return class->create_iter (area);
687
688   g_warning ("GtkCellAreaClass::create_iter not implemented for `%s'", 
689              g_type_name (G_TYPE_FROM_INSTANCE (area)));
690   
691   return NULL;
692 }
693
694
695 GtkSizeRequestMode 
696 gtk_cell_area_get_request_mode (GtkCellArea *area)
697 {
698   GtkCellAreaClass *class;
699
700   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 
701                         GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH);
702
703   class = GTK_CELL_AREA_GET_CLASS (area);
704
705   if (class->get_request_mode)
706     return class->get_request_mode (area);
707
708   g_warning ("GtkCellAreaClass::get_request_mode not implemented for `%s'", 
709              g_type_name (G_TYPE_FROM_INSTANCE (area)));
710   
711   return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
712 }
713
714 void
715 gtk_cell_area_get_preferred_width (GtkCellArea        *area,
716                                    GtkCellAreaIter    *iter,
717                                    GtkWidget          *widget,
718                                    gint               *minimum_size,
719                                    gint               *natural_size)
720 {
721   GtkCellAreaClass *class;
722
723   g_return_if_fail (GTK_IS_CELL_AREA (area));
724   g_return_if_fail (GTK_IS_WIDGET (widget));
725
726   class = GTK_CELL_AREA_GET_CLASS (area);
727
728   if (class->get_preferred_width)
729     class->get_preferred_width (area, iter, widget, minimum_size, natural_size);
730   else
731     g_warning ("GtkCellAreaClass::get_preferred_width not implemented for `%s'", 
732                g_type_name (G_TYPE_FROM_INSTANCE (area)));
733 }
734
735 void
736 gtk_cell_area_get_preferred_height_for_width (GtkCellArea        *area,
737                                               GtkCellAreaIter    *iter,
738                                               GtkWidget          *widget,
739                                               gint                width,
740                                               gint               *minimum_height,
741                                               gint               *natural_height)
742 {
743   GtkCellAreaClass *class;
744
745   g_return_if_fail (GTK_IS_CELL_AREA (area));
746   g_return_if_fail (GTK_IS_WIDGET (widget));
747
748   class = GTK_CELL_AREA_GET_CLASS (area);
749   class->get_preferred_height_for_width (area, iter, widget, width, minimum_height, natural_height);
750 }
751
752 void
753 gtk_cell_area_get_preferred_height (GtkCellArea        *area,
754                                     GtkCellAreaIter    *iter,
755                                     GtkWidget          *widget,
756                                     gint               *minimum_size,
757                                     gint               *natural_size)
758 {
759   GtkCellAreaClass *class;
760
761   g_return_if_fail (GTK_IS_CELL_AREA (area));
762   g_return_if_fail (GTK_IS_WIDGET (widget));
763
764   class = GTK_CELL_AREA_GET_CLASS (area);
765
766   if (class->get_preferred_height)
767     class->get_preferred_height (area, iter, widget, minimum_size, natural_size);
768   else
769     g_warning ("GtkCellAreaClass::get_preferred_height not implemented for `%s'", 
770                g_type_name (G_TYPE_FROM_INSTANCE (area)));
771 }
772
773 void
774 gtk_cell_area_get_preferred_width_for_height (GtkCellArea        *area,
775                                               GtkCellAreaIter    *iter,
776                                               GtkWidget          *widget,
777                                               gint                height,
778                                               gint               *minimum_width,
779                                               gint               *natural_width)
780 {
781   GtkCellAreaClass *class;
782
783   g_return_if_fail (GTK_IS_CELL_AREA (area));
784   g_return_if_fail (GTK_IS_WIDGET (widget));
785
786   class = GTK_CELL_AREA_GET_CLASS (area);
787   class->get_preferred_width_for_height (area, iter, widget, height, minimum_width, natural_width);
788 }
789
790 /* Attributes */
791 void
792 gtk_cell_area_attribute_connect (GtkCellArea        *area,
793                                  GtkCellRenderer    *renderer,
794                                  const gchar        *attribute,
795                                  gint                column)
796
797   GtkCellAreaPrivate *priv;
798   CellInfo           *info;
799   CellAttribute      *cell_attribute;
800
801   g_return_if_fail (GTK_IS_CELL_AREA (area));
802   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
803   g_return_if_fail (attribute != NULL);
804
805   priv = area->priv;
806   info = g_hash_table_lookup (priv->cell_info, renderer);
807
808   if (!info)
809     {
810       info = cell_info_new (NULL, NULL, NULL);
811
812       g_hash_table_insert (priv->cell_info, renderer, info);
813     }
814   else
815     {
816       GSList *node;
817
818       /* Check we are not adding the same attribute twice */
819       if ((node = g_slist_find_custom (info->attributes, attribute,
820                                        (GCompareFunc)cell_attribute_find)) != NULL)
821         {
822           cell_attribute = node->data;
823
824           g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
825                      "since `%s' is already attributed to column %d", 
826                      attribute,
827                      g_type_name (G_TYPE_FROM_INSTANCE (area)),
828                      attribute, cell_attribute->column);
829           return;
830         }
831     }
832
833   cell_attribute = cell_attribute_new (renderer, attribute, column);
834
835   if (!cell_attribute)
836     {
837       g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
838                  "since attribute does not exist", 
839                  attribute,
840                  g_type_name (G_TYPE_FROM_INSTANCE (area)));
841       return;
842     }
843
844   info->attributes = g_slist_prepend (info->attributes, cell_attribute);
845 }
846
847 void 
848 gtk_cell_area_attribute_disconnect (GtkCellArea        *area,
849                                     GtkCellRenderer    *renderer,
850                                     const gchar        *attribute)
851 {
852   GtkCellAreaPrivate *priv;
853   CellInfo           *info;
854   CellAttribute      *cell_attribute;
855   GSList             *node;
856
857   g_return_if_fail (GTK_IS_CELL_AREA (area));
858   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
859   g_return_if_fail (attribute != NULL);
860
861   priv = area->priv;
862   info = g_hash_table_lookup (priv->cell_info, renderer);
863
864   if (info)
865     {
866       node = g_slist_find_custom (info->attributes, attribute,
867                                   (GCompareFunc)cell_attribute_find);
868       if (node)
869         {
870           cell_attribute = node->data;
871
872           cell_attribute_free (cell_attribute);
873
874           info->attributes = g_slist_delete_link (info->attributes, node);
875         }
876     }
877 }
878
879 static void
880 apply_cell_attributes (GtkCellRenderer *renderer,
881                        CellInfo        *info,
882                        AttributeData   *data)
883 {
884   CellAttribute *attribute;
885   GSList        *list;
886   GValue         value = { 0, };
887
888   /* Apply the attributes directly to the renderer */
889   for (list = info->attributes; list; list = list->next)
890     {
891       attribute = list->data;
892
893       gtk_tree_model_get_value (data->model, data->iter, attribute->column, &value);
894       g_object_set_property (G_OBJECT (renderer), attribute->attribute, &value);
895       g_value_unset (&value);
896     }
897
898   /* Call any GtkCellLayoutDataFunc that may have been set by the user
899    */
900   if (info->func)
901     info->func (GTK_CELL_LAYOUT (data->area), renderer,
902                 data->model, data->iter, info->data);
903 }
904
905 void
906 gtk_cell_area_apply_attributes (GtkCellArea  *area,
907                                 GtkTreeModel *tree_model,
908                                 GtkTreeIter  *iter)
909 {
910   GtkCellAreaPrivate *priv;
911   AttributeData       data;
912
913   g_return_if_fail (GTK_IS_CELL_AREA (area));
914   g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
915   g_return_if_fail (iter != NULL);
916
917   priv = area->priv;
918
919   /* Go over any cells that have attributes or custom GtkCellLayoutDataFuncs and
920    * apply the data from the treemodel */
921   g_hash_table_foreach (priv->cell_info, (GHFunc)apply_cell_attributes, &data);
922 }
923
924 /* Cell Properties */
925 void
926 gtk_cell_area_class_install_cell_property (GtkCellAreaClass   *aclass,
927                                            guint               property_id,
928                                            GParamSpec         *pspec)
929 {
930   g_return_if_fail (GTK_IS_CELL_AREA_CLASS (aclass));
931   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
932   if (pspec->flags & G_PARAM_WRITABLE)
933     g_return_if_fail (aclass->set_cell_property != NULL);
934   if (pspec->flags & G_PARAM_READABLE)
935     g_return_if_fail (aclass->get_cell_property != NULL);
936   g_return_if_fail (property_id > 0);
937   g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0);  /* paranoid */
938   g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0);
939
940   if (g_param_spec_pool_lookup (cell_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (aclass), TRUE))
941     {
942       g_warning (G_STRLOC ": class `%s' already contains a cell property named `%s'",
943                  G_OBJECT_CLASS_NAME (aclass), pspec->name);
944       return;
945     }
946   g_param_spec_ref (pspec);
947   g_param_spec_sink (pspec);
948   PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
949   g_param_spec_pool_insert (cell_property_pool, pspec, G_OBJECT_CLASS_TYPE (aclass));
950 }
951
952 GParamSpec*
953 gtk_cell_area_class_find_cell_property (GtkCellAreaClass   *aclass,
954                                         const gchar        *property_name)
955 {
956   g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
957   g_return_val_if_fail (property_name != NULL, NULL);
958
959   return g_param_spec_pool_lookup (cell_property_pool,
960                                    property_name,
961                                    G_OBJECT_CLASS_TYPE (aclass),
962                                    TRUE);
963 }
964
965 GParamSpec**
966 gtk_cell_area_class_list_cell_properties (GtkCellAreaClass   *aclass,
967                                           guint             *n_properties)
968 {
969   GParamSpec **pspecs;
970   guint n;
971
972   g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
973
974   pspecs = g_param_spec_pool_list (cell_property_pool,
975                                    G_OBJECT_CLASS_TYPE (aclass),
976                                    &n);
977   if (n_properties)
978     *n_properties = n;
979
980   return pspecs;
981 }
982
983 void
984 gtk_cell_area_add_with_properties (GtkCellArea        *area,
985                                    GtkCellRenderer    *renderer,
986                                    const gchar        *first_prop_name,
987                                    ...)
988 {
989   GtkCellAreaClass *class;
990
991   g_return_if_fail (GTK_IS_CELL_AREA (area));
992   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
993
994   class = GTK_CELL_AREA_GET_CLASS (area);
995
996   if (class->add)
997     {
998       va_list var_args;
999
1000       class->add (area, renderer);
1001
1002       va_start (var_args, first_prop_name);
1003       gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1004       va_end (var_args);
1005     }
1006   else
1007     g_warning ("GtkCellAreaClass::add not implemented for `%s'", 
1008                g_type_name (G_TYPE_FROM_INSTANCE (area)));
1009 }
1010
1011 void
1012 gtk_cell_area_cell_set (GtkCellArea        *area,
1013                         GtkCellRenderer    *renderer,
1014                         const gchar        *first_prop_name,
1015                         ...)
1016 {
1017   va_list var_args;
1018
1019   g_return_if_fail (GTK_IS_CELL_AREA (area));
1020   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1021
1022   va_start (var_args, first_prop_name);
1023   gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1024   va_end (var_args);
1025 }
1026
1027 void
1028 gtk_cell_area_cell_get (GtkCellArea        *area,
1029                         GtkCellRenderer    *renderer,
1030                         const gchar        *first_prop_name,
1031                         ...)
1032 {
1033   va_list var_args;
1034
1035   g_return_if_fail (GTK_IS_CELL_AREA (area));
1036   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1037
1038   va_start (var_args, first_prop_name);
1039   gtk_cell_area_cell_get_valist (area, renderer, first_prop_name, var_args);
1040   va_end (var_args);
1041 }
1042
1043 static inline void
1044 area_get_cell_property (GtkCellArea     *area,
1045                         GtkCellRenderer *renderer,
1046                         GParamSpec      *pspec,
1047                         GValue          *value)
1048 {
1049   GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1050   
1051   class->get_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), value, pspec);
1052 }
1053
1054 static inline void
1055 area_set_cell_property (GtkCellArea     *area,
1056                         GtkCellRenderer *renderer,
1057                         GParamSpec      *pspec,
1058                         const GValue    *value)
1059 {
1060   GValue tmp_value = { 0, };
1061   GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1062
1063   /* provide a copy to work from, convert (if necessary) and validate */
1064   g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1065   if (!g_value_transform (value, &tmp_value))
1066     g_warning ("unable to set cell property `%s' of type `%s' from value of type `%s'",
1067                pspec->name,
1068                g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1069                G_VALUE_TYPE_NAME (value));
1070   else if (g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION))
1071     {
1072       gchar *contents = g_strdup_value_contents (value);
1073
1074       g_warning ("value \"%s\" of type `%s' is invalid for property `%s' of type `%s'",
1075                  contents,
1076                  G_VALUE_TYPE_NAME (value),
1077                  pspec->name,
1078                  g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
1079       g_free (contents);
1080     }
1081   else
1082     {
1083       class->set_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec);
1084     }
1085   g_value_unset (&tmp_value);
1086 }
1087
1088 void
1089 gtk_cell_area_cell_set_valist (GtkCellArea        *area,
1090                                GtkCellRenderer    *renderer,
1091                                const gchar        *first_property_name,
1092                                va_list             var_args)
1093 {
1094   const gchar *name;
1095
1096   g_return_if_fail (GTK_IS_CELL_AREA (area));
1097   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1098
1099   name = first_property_name;
1100   while (name)
1101     {
1102       GValue value = { 0, };
1103       gchar *error = NULL;
1104       GParamSpec *pspec = 
1105         g_param_spec_pool_lookup (cell_property_pool, name,
1106                                   G_OBJECT_TYPE (area), TRUE);
1107       if (!pspec)
1108         {
1109           g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1110                      G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1111           break;
1112         }
1113       if (!(pspec->flags & G_PARAM_WRITABLE))
1114         {
1115           g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1116                      G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1117           break;
1118         }
1119
1120       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1121       G_VALUE_COLLECT (&value, var_args, 0, &error);
1122       if (error)
1123         {
1124           g_warning ("%s: %s", G_STRLOC, error);
1125           g_free (error);
1126
1127           /* we purposely leak the value here, it might not be
1128            * in a sane state if an error condition occoured
1129            */
1130           break;
1131         }
1132       area_set_cell_property (area, renderer, pspec, &value);
1133       g_value_unset (&value);
1134       name = va_arg (var_args, gchar*);
1135     }
1136 }
1137
1138 void
1139 gtk_cell_area_cell_get_valist (GtkCellArea        *area,
1140                                GtkCellRenderer    *renderer,
1141                                const gchar        *first_property_name,
1142                                va_list             var_args)
1143 {
1144   const gchar *name;
1145
1146   g_return_if_fail (GTK_IS_CELL_AREA (area));
1147   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1148
1149   name = first_property_name;
1150   while (name)
1151     {
1152       GValue value = { 0, };
1153       GParamSpec *pspec;
1154       gchar *error;
1155
1156       pspec = g_param_spec_pool_lookup (cell_property_pool, name,
1157                                         G_OBJECT_TYPE (area), TRUE);
1158       if (!pspec)
1159         {
1160           g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1161                      G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1162           break;
1163         }
1164       if (!(pspec->flags & G_PARAM_READABLE))
1165         {
1166           g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1167                      G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1168           break;
1169         }
1170
1171       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1172       area_get_cell_property (area, renderer, pspec, &value);
1173       G_VALUE_LCOPY (&value, var_args, 0, &error);
1174       if (error)
1175         {
1176           g_warning ("%s: %s", G_STRLOC, error);
1177           g_free (error);
1178           g_value_unset (&value);
1179           break;
1180         }
1181       g_value_unset (&value);
1182       name = va_arg (var_args, gchar*);
1183     }
1184 }
1185
1186 void
1187 gtk_cell_area_cell_set_property (GtkCellArea        *area,
1188                                  GtkCellRenderer    *renderer,
1189                                  const gchar        *property_name,
1190                                  const GValue       *value)
1191 {
1192   GParamSpec *pspec;
1193
1194   g_return_if_fail (GTK_IS_CELL_AREA (area));
1195   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1196   g_return_if_fail (property_name != NULL);
1197   g_return_if_fail (G_IS_VALUE (value));
1198   
1199   pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1200                                     G_OBJECT_TYPE (area), TRUE);
1201   if (!pspec)
1202     g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1203                G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1204   else if (!(pspec->flags & G_PARAM_WRITABLE))
1205     g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1206                G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1207   else
1208     {
1209       area_set_cell_property (area, renderer, pspec, value);
1210     }
1211 }
1212
1213 void
1214 gtk_cell_area_cell_get_property (GtkCellArea        *area,
1215                                  GtkCellRenderer    *renderer,
1216                                  const gchar        *property_name,
1217                                  GValue             *value)
1218 {
1219   GParamSpec *pspec;
1220
1221   g_return_if_fail (GTK_IS_CELL_AREA (area));
1222   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1223   g_return_if_fail (property_name != NULL);
1224   g_return_if_fail (G_IS_VALUE (value));
1225   
1226   pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1227                                     G_OBJECT_TYPE (area), TRUE);
1228   if (!pspec)
1229     g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1230                G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1231   else if (!(pspec->flags & G_PARAM_READABLE))
1232     g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1233                G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1234   else
1235     {
1236       GValue *prop_value, tmp_value = { 0, };
1237
1238       /* auto-conversion of the callers value type
1239        */
1240       if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
1241         {
1242           g_value_reset (value);
1243           prop_value = value;
1244         }
1245       else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
1246         {
1247           g_warning ("can't retrieve cell property `%s' of type `%s' as value of type `%s'",
1248                      pspec->name,
1249                      g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1250                      G_VALUE_TYPE_NAME (value));
1251           return;
1252         }
1253       else
1254         {
1255           g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1256           prop_value = &tmp_value;
1257         }
1258
1259       area_get_cell_property (area, renderer, pspec, prop_value);
1260
1261       if (prop_value != value)
1262         {
1263           g_value_transform (prop_value, value);
1264           g_value_unset (&tmp_value);
1265         }
1266     }
1267 }
1268
1269 /* Margins */
1270 gint
1271 gtk_cell_area_get_margin_left (GtkCellArea *area)
1272 {
1273   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1274
1275   return area->priv->border.left;
1276 }
1277
1278 void
1279 gtk_cell_area_set_margin_left (GtkCellArea *area,
1280                                gint         margin)
1281 {
1282   GtkCellAreaPrivate *priv;
1283
1284   g_return_if_fail (GTK_IS_CELL_AREA (area));
1285
1286   priv = area->priv;
1287
1288   if (priv->border.left != margin)
1289     {
1290       priv->border.left = margin;
1291
1292       g_object_notify (G_OBJECT (area), "margin-left");
1293     }
1294 }
1295
1296 gint
1297 gtk_cell_area_get_margin_right (GtkCellArea *area)
1298 {
1299   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1300
1301   return area->priv->border.right;
1302 }
1303
1304 void
1305 gtk_cell_area_set_margin_right (GtkCellArea *area,
1306                                 gint         margin)
1307 {
1308   GtkCellAreaPrivate *priv;
1309
1310   g_return_if_fail (GTK_IS_CELL_AREA (area));
1311
1312   priv = area->priv;
1313
1314   if (priv->border.right != margin)
1315     {
1316       priv->border.right = margin;
1317
1318       g_object_notify (G_OBJECT (area), "margin-right");
1319     }
1320 }
1321
1322 gint
1323 gtk_cell_area_get_margin_top (GtkCellArea *area)
1324 {
1325   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1326
1327   return area->priv->border.top;
1328 }
1329
1330 void
1331 gtk_cell_area_set_margin_top (GtkCellArea *area,
1332                               gint         margin)
1333 {
1334   GtkCellAreaPrivate *priv;
1335
1336   g_return_if_fail (GTK_IS_CELL_AREA (area));
1337
1338   priv = area->priv;
1339
1340   if (priv->border.top != margin)
1341     {
1342       priv->border.top = margin;
1343
1344       g_object_notify (G_OBJECT (area), "margin-top");
1345     }
1346 }
1347
1348 gint
1349 gtk_cell_area_get_margin_bottom (GtkCellArea *area)
1350 {
1351   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1352
1353   return area->priv->border.bottom;
1354 }
1355
1356 void
1357 gtk_cell_area_set_margin_bottom (GtkCellArea *area,
1358                                  gint         margin)
1359 {
1360   GtkCellAreaPrivate *priv;
1361
1362   g_return_if_fail (GTK_IS_CELL_AREA (area));
1363
1364   priv = area->priv;
1365
1366   if (priv->border.bottom != margin)
1367     {
1368       priv->border.bottom = margin;
1369
1370       g_object_notify (G_OBJECT (area), "margin-bottom");
1371     }
1372 }
1373
1374 /* For convenience in area implementations */
1375 void
1376 gtk_cell_area_inner_area (GtkCellArea        *area,
1377                           GdkRectangle       *background_area,
1378                           GdkRectangle       *cell_area)
1379 {
1380   GtkCellAreaPrivate *priv;
1381
1382   g_return_if_fail (GTK_IS_CELL_AREA (area));
1383   g_return_if_fail (background_area != NULL);
1384   g_return_if_fail (cell_area != NULL);
1385
1386   priv = area->priv;
1387
1388   *cell_area = *background_area;
1389
1390   cell_area->x      += priv->border.left;
1391   cell_area->width  -= (priv->border.left + priv->border.right);
1392   cell_area->y      += priv->border.top;
1393   cell_area->height -= (priv->border.top + priv->border.bottom);
1394 }