]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellarea.c
Made progress on focus handling.
[~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 "gtkmarshalers.h"
35 #include "gtkprivate.h"
36
37 #include <gobject/gvaluecollector.h>
38
39
40 /* GObjectClass */
41 static void      gtk_cell_area_dispose                             (GObject            *object);
42 static void      gtk_cell_area_finalize                            (GObject            *object);
43 static void      gtk_cell_area_set_property                        (GObject            *object,
44                                                                     guint               prop_id,
45                                                                     const GValue       *value,
46                                                                     GParamSpec         *pspec);
47 static void      gtk_cell_area_get_property                        (GObject            *object,
48                                                                     guint               prop_id,
49                                                                     GValue             *value,
50                                                                     GParamSpec         *pspec);
51
52 /* GtkCellAreaClass */
53 static gint      gtk_cell_area_real_event                          (GtkCellArea          *area,
54                                                                     GtkCellAreaIter      *iter,
55                                                                     GtkWidget            *widget,
56                                                                     GdkEvent             *event,
57                                                                     const GdkRectangle   *cell_area,
58                                                                     GtkCellRendererState  flags);
59 static void      gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea           *area,
60                                                                     GtkCellAreaIter       *iter,
61                                                                     GtkWidget             *widget,
62                                                                     gint                   width,
63                                                                     gint                  *minimum_height,
64                                                                     gint                  *natural_height);
65 static void      gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea           *area,
66                                                                     GtkCellAreaIter       *iter,
67                                                                     GtkWidget             *widget,
68                                                                     gint                   height,
69                                                                     gint                  *minimum_width,
70                                                                     gint                  *natural_width);
71 static void      gtk_cell_area_real_update_focus                   (GtkCellArea           *area);
72
73 /* GtkCellLayoutIface */
74 static void      gtk_cell_area_cell_layout_init              (GtkCellLayoutIface    *iface);
75 static void      gtk_cell_area_pack_default                  (GtkCellLayout         *cell_layout,
76                                                               GtkCellRenderer       *renderer,
77                                                               gboolean               expand);
78 static void      gtk_cell_area_clear                         (GtkCellLayout         *cell_layout);
79 static void      gtk_cell_area_add_attribute                 (GtkCellLayout         *cell_layout,
80                                                               GtkCellRenderer       *renderer,
81                                                               const gchar           *attribute,
82                                                               gint                   column);
83 static void      gtk_cell_area_set_cell_data_func            (GtkCellLayout         *cell_layout,
84                                                               GtkCellRenderer       *cell,
85                                                               GtkCellLayoutDataFunc  func,
86                                                               gpointer               func_data,
87                                                               GDestroyNotify         destroy);
88 static void      gtk_cell_area_clear_attributes              (GtkCellLayout         *cell_layout,
89                                                               GtkCellRenderer       *renderer);
90 static void      gtk_cell_area_reorder                       (GtkCellLayout         *cell_layout,
91                                                               GtkCellRenderer       *cell,
92                                                               gint                   position);
93 static GList    *gtk_cell_area_get_cells                     (GtkCellLayout         *cell_layout);
94
95 /* Attribute/Cell metadata */
96 typedef struct {
97   const gchar *attribute;
98   gint         column;
99 } CellAttribute;
100
101 typedef struct {
102   GSList                *attributes;
103
104   GtkCellLayoutDataFunc  func;
105   gpointer               data;
106   GDestroyNotify         destroy;
107 } CellInfo;
108
109 static CellInfo       *cell_info_new       (GtkCellLayoutDataFunc  func,
110                                             gpointer               data,
111                                             GDestroyNotify         destroy);
112 static void            cell_info_free      (CellInfo              *info);
113 static CellAttribute  *cell_attribute_new  (GtkCellRenderer       *renderer,
114                                             const gchar           *attribute,
115                                             gint                   column);
116 static void            cell_attribute_free (CellAttribute         *attribute);
117 static gint            cell_attribute_find (CellAttribute         *cell_attribute,
118                                             const gchar           *attribute);
119
120 /* Struct to pass data along while looping over 
121  * cell renderers to apply attributes
122  */
123 typedef struct {
124   GtkCellArea  *area;
125   GtkTreeModel *model;
126   GtkTreeIter  *iter;
127   gboolean      is_expander;
128   gboolean      is_expanded;
129 } AttributeData;
130
131 struct _GtkCellAreaPrivate
132 {
133   /* The GtkCellArea bookkeeps any connected 
134    * attributes in this hash table.
135    */
136   GHashTable      *cell_info;
137
138   /* The cell border decides how much space to reserve
139    * around each cell for the background_area
140    */
141   GtkBorder        cell_border;
142
143   /* Current path is saved as a side-effect
144    * of gtk_cell_area_apply_attributes() */
145   gchar           *current_path;
146
147   GtkCellRenderer *edited_cell;
148   GtkCellRenderer *focus_cell;
149   guint            can_focus : 1;
150
151 };
152
153 enum {
154   PROP_0,
155   PROP_CELL_MARGIN_LEFT,
156   PROP_CELL_MARGIN_RIGHT,
157   PROP_CELL_MARGIN_TOP,
158   PROP_CELL_MARGIN_BOTTOM,
159   PROP_FOCUS_CELL,
160   PROP_EDITED_CELL
161 };
162
163 enum {
164   SIGNAL_FOCUS_LEAVE,
165   SIGNAL_EDITING_STARTED,
166   LAST_SIGNAL
167 };
168
169 /* Keep the paramspec pool internal, no need to deliver notifications
170  * on cells. at least no percieved need for now */
171 static GParamSpecPool *cell_property_pool = NULL;
172 static guint           cell_area_signals[LAST_SIGNAL] = { 0 };
173
174 #define PARAM_SPEC_PARAM_ID(pspec)              ((pspec)->param_id)
175 #define PARAM_SPEC_SET_PARAM_ID(pspec, id)      ((pspec)->param_id = (id))
176
177
178 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkCellArea, gtk_cell_area, G_TYPE_INITIALLY_UNOWNED,
179                                   G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
180                                                          gtk_cell_area_cell_layout_init));
181
182 static void
183 gtk_cell_area_init (GtkCellArea *area)
184 {
185   GtkCellAreaPrivate *priv;
186
187   area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area,
188                                             GTK_TYPE_CELL_AREA,
189                                             GtkCellAreaPrivate);
190   priv = area->priv;
191
192   priv->cell_info = g_hash_table_new_full (g_direct_hash, 
193                                            g_direct_equal,
194                                            NULL, 
195                                            (GDestroyNotify)cell_info_free);
196
197   priv->cell_border.left   = 0;
198   priv->cell_border.right  = 0;
199   priv->cell_border.top    = 0;
200   priv->cell_border.bottom = 0;
201
202   priv->focus_cell         = NULL;
203 }
204
205 static void 
206 gtk_cell_area_class_init (GtkCellAreaClass *class)
207 {
208   GObjectClass *object_class = G_OBJECT_CLASS (class);
209   
210   /* GObjectClass */
211   object_class->dispose      = gtk_cell_area_dispose;
212   object_class->finalize     = gtk_cell_area_finalize;
213   object_class->get_property = gtk_cell_area_get_property;
214   object_class->set_property = gtk_cell_area_set_property;
215
216   /* general */
217   class->add     = NULL;
218   class->remove  = NULL;
219   class->forall  = NULL;
220   class->event   = gtk_cell_area_real_event;
221   class->render  = NULL;
222
223   /* geometry */
224   class->create_iter                    = NULL;
225   class->get_request_mode               = NULL;
226   class->get_preferred_width            = NULL;
227   class->get_preferred_height           = NULL;
228   class->get_preferred_height_for_width = gtk_cell_area_real_get_preferred_height_for_width;
229   class->get_preferred_width_for_height = gtk_cell_area_real_get_preferred_width_for_height;
230
231   /* focus */
232   class->grab_focus = NULL;
233   class->update_focus = gtk_cell_area_real_update_focus;
234
235   /* Signals */
236   cell_area_signals[SIGNAL_FOCUS_LEAVE] =
237     g_signal_new (I_("focus-leave"),
238                   G_TYPE_FROM_CLASS (object_class),
239                   G_SIGNAL_RUN_LAST,
240                   0, /* Class offset (just a notification, no class handler) */
241                   NULL, NULL,
242                   _gtk_marshal_VOID__ENUM_STRING,
243                   G_TYPE_NONE, 2,
244                   GTK_TYPE_DIRECTION_TYPE, G_TYPE_STRING);
245
246   cell_area_signals[SIGNAL_EDITING_STARTED] =
247     g_signal_new (I_("editing-started"),
248                   G_OBJECT_CLASS_TYPE (object_class),
249                   G_SIGNAL_RUN_FIRST,
250                   0, /* No class closure here */
251                   NULL, NULL,
252                   _gtk_marshal_VOID__OBJECT_OBJECT_STRING,
253                   G_TYPE_NONE, 3,
254                   GTK_TYPE_CELL_RENDERER,
255                   GTK_TYPE_CELL_EDITABLE,
256                   G_TYPE_STRING);
257
258   /* Properties */
259   g_object_class_install_property (object_class,
260                                    PROP_CELL_MARGIN_LEFT,
261                                    g_param_spec_int
262                                    ("cell-margin-left",
263                                     P_("Margin on Left"),
264                                     P_("Pixels of extra space on the left side of each cell"),
265                                     0,
266                                     G_MAXINT16,
267                                     0,
268                                     GTK_PARAM_READWRITE));
269
270   g_object_class_install_property (object_class,
271                                    PROP_CELL_MARGIN_RIGHT,
272                                    g_param_spec_int
273                                    ("cell-margin-right",
274                                     P_("Margin on Right"),
275                                     P_("Pixels of extra space on the right side of each cell"),
276                                     0,
277                                     G_MAXINT16,
278                                     0,
279                                     GTK_PARAM_READWRITE));
280   
281   g_object_class_install_property (object_class,
282                                    PROP_CELL_MARGIN_TOP,
283                                    g_param_spec_int 
284                                    ("cell-margin-top",
285                                     P_("Margin on Top"),
286                                     P_("Pixels of extra space on the top side of each cell"),
287                                     0,
288                                     G_MAXINT16,
289                                     0,
290                                     GTK_PARAM_READWRITE));
291
292   g_object_class_install_property (object_class,
293                                    PROP_CELL_MARGIN_BOTTOM,
294                                    g_param_spec_int
295                                    ("cell-margin-bottom",
296                                     P_("Margin on Bottom"),
297                                     P_("Pixels of extra space on the bottom side of each cell"),
298                                     0,
299                                     G_MAXINT16,
300                                     0,
301                                     GTK_PARAM_READWRITE));
302
303   g_object_class_install_property (object_class,
304                                    PROP_FOCUS_CELL,
305                                    g_param_spec_object
306                                    ("focus-cell",
307                                     P_("Focus Cell"),
308                                     P_("The cell which currently has focus"),
309                                     GTK_TYPE_CELL_RENDERER,
310                                     GTK_PARAM_READWRITE));
311
312   g_object_class_install_property (object_class,
313                                    PROP_EDITED_CELL,
314                                    g_param_spec_object
315                                    ("edited-cell",
316                                     P_("Edited Cell"),
317                                     P_("The cell which is currently being edited"),
318                                     GTK_TYPE_CELL_RENDERER,
319                                     GTK_PARAM_READWRITE));
320
321   /* Pool for Cell Properties */
322   if (!cell_property_pool)
323     cell_property_pool = g_param_spec_pool_new (FALSE);
324
325   g_type_class_add_private (object_class, sizeof (GtkCellAreaPrivate));
326 }
327
328 /*************************************************************
329  *                    CellInfo Basics                        *
330  *************************************************************/
331 static CellInfo *
332 cell_info_new (GtkCellLayoutDataFunc  func,
333                gpointer               data,
334                GDestroyNotify         destroy)
335 {
336   CellInfo *info = g_slice_new (CellInfo);
337   
338   info->attributes = NULL;
339   info->func       = func;
340   info->data       = data;
341   info->destroy    = destroy;
342
343   return info;
344 }
345
346 static void
347 cell_info_free (CellInfo *info)
348 {
349   if (info->destroy)
350     info->destroy (info->data);
351
352   g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
353   g_slist_free (info->attributes);
354
355   g_slice_free (CellInfo, info);
356 }
357
358 static CellAttribute  *
359 cell_attribute_new  (GtkCellRenderer       *renderer,
360                      const gchar           *attribute,
361                      gint                   column)
362 {
363   GParamSpec *pspec;
364
365   /* Check if the attribute really exists and point to
366    * the property string installed on the cell renderer
367    * class (dont dup the string) 
368    */
369   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (renderer), attribute);
370
371   if (pspec)
372     {
373       CellAttribute *cell_attribute = g_slice_new (CellAttribute);
374
375       cell_attribute->attribute = pspec->name;
376       cell_attribute->column    = column;
377
378       return cell_attribute;
379     }
380
381   return NULL;
382 }
383
384 static void
385 cell_attribute_free (CellAttribute *attribute)
386 {
387   g_slice_free (CellAttribute, attribute);
388 }
389
390 /* GCompareFunc for g_slist_find_custom() */
391 static gint
392 cell_attribute_find (CellAttribute *cell_attribute,
393                      const gchar   *attribute)
394 {
395   return g_strcmp0 (cell_attribute->attribute, attribute);
396 }
397
398 /*************************************************************
399  *                      GObjectClass                         *
400  *************************************************************/
401 static void
402 gtk_cell_area_finalize (GObject *object)
403 {
404   GtkCellArea        *area   = GTK_CELL_AREA (object);
405   GtkCellAreaPrivate *priv   = area->priv;
406
407   /* All cell renderers should already be removed at this point,
408    * just kill our hash table here. 
409    */
410   g_hash_table_destroy (priv->cell_info);
411
412   g_free (priv->current_path);
413
414   G_OBJECT_CLASS (gtk_cell_area_parent_class)->finalize (object);
415 }
416
417
418 static void
419 gtk_cell_area_dispose (GObject *object)
420 {
421   /* This removes every cell renderer that may be added to the GtkCellArea,
422    * subclasses should be breaking references to the GtkCellRenderers 
423    * at this point.
424    */
425   gtk_cell_layout_clear (GTK_CELL_LAYOUT (object));
426
427   /* Remove any ref to a focused/edited cell */
428   gtk_cell_area_set_focus_cell (GTK_CELL_AREA (object), NULL);
429   gtk_cell_area_set_edited_cell (GTK_CELL_AREA (object), NULL);
430
431   G_OBJECT_CLASS (gtk_cell_area_parent_class)->dispose (object);
432 }
433
434 static void
435 gtk_cell_area_set_property (GObject       *object,
436                             guint          prop_id,
437                             const GValue  *value,
438                             GParamSpec    *pspec)
439 {
440   GtkCellArea *area = GTK_CELL_AREA (object);
441
442   switch (prop_id)
443     {
444     case PROP_CELL_MARGIN_LEFT:
445       gtk_cell_area_set_cell_margin_left (area, g_value_get_int (value));
446       break;
447     case PROP_CELL_MARGIN_RIGHT:
448       gtk_cell_area_set_cell_margin_right (area, g_value_get_int (value));
449       break;
450     case PROP_CELL_MARGIN_TOP:
451       gtk_cell_area_set_cell_margin_top (area, g_value_get_int (value));
452       break;
453     case PROP_CELL_MARGIN_BOTTOM:
454       gtk_cell_area_set_cell_margin_bottom (area, g_value_get_int (value));
455       break;
456     case PROP_FOCUS_CELL:
457       gtk_cell_area_set_focus_cell (area, (GtkCellRenderer *)g_value_get_object (value));
458       break;
459     default:
460       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
461       break;
462     }
463 }
464
465 static void
466 gtk_cell_area_get_property (GObject     *object,
467                             guint        prop_id,
468                             GValue      *value,
469                             GParamSpec  *pspec)
470 {
471   GtkCellArea        *area = GTK_CELL_AREA (object);
472   GtkCellAreaPrivate *priv = area->priv;
473
474   switch (prop_id)
475     {
476     case PROP_CELL_MARGIN_LEFT:
477       g_value_set_int (value, priv->cell_border.left);
478       break;
479     case PROP_CELL_MARGIN_RIGHT:
480       g_value_set_int (value, priv->cell_border.right);
481       break;
482     case PROP_CELL_MARGIN_TOP:
483       g_value_set_int (value, priv->cell_border.top);
484       break;
485     case PROP_CELL_MARGIN_BOTTOM:
486       g_value_set_int (value, priv->cell_border.bottom);
487       break;
488     case PROP_FOCUS_CELL:
489       g_value_set_object (value, priv->focus_cell);
490       break;
491     default:
492       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
493       break;
494     }
495 }
496
497 /*************************************************************
498  *                    GtkCellAreaClass                       *
499  *************************************************************/
500 static gint
501 gtk_cell_area_real_event (GtkCellArea          *area,
502                           GtkCellAreaIter      *iter,
503                           GtkWidget            *widget,
504                           GdkEvent             *event,
505                           const GdkRectangle   *cell_area,
506                           GtkCellRendererState  flags)
507 {
508   if (event->type == GDK_KEY_PRESS && (flags & GTK_CELL_RENDERER_FOCUSED) != 0)
509     {
510       GdkEventKey        *key_event = (GdkEventKey *)event;
511       GtkCellAreaPrivate *priv = area->priv;
512
513       if (priv->focus_cell && 
514           (key_event->keyval == GDK_KEY_space ||
515            key_event->keyval == GDK_KEY_KP_Space ||
516            key_event->keyval == GDK_KEY_Return ||
517            key_event->keyval == GDK_KEY_ISO_Enter ||
518            key_event->keyval == GDK_KEY_KP_Enter))
519         {
520           /* Activate or Edit the currently focused cell */
521           GtkCellRendererMode mode;
522           GdkRectangle        background_area;
523           GdkRectangle        inner_area;
524
525           /* Get the allocation of the focused cell.
526            */
527           gtk_cell_area_get_cell_allocation (area, iter, widget, priv->focus_cell,
528                                              cell_area, &background_area);
529
530           /* Remove margins from the background area to produce the cell area.
531            */
532           gtk_cell_area_inner_cell_area (area, &background_area, &inner_area);
533
534           /* XXX Need to do some extra right-to-left casing either here 
535            * or inside the above called apis.
536            */
537
538           g_object_get (priv->focus_cell, "mode", &mode, NULL);
539
540           if (mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
541             {
542               if (gtk_cell_renderer_activate (priv->focus_cell,
543                                               event, widget,
544                                               priv->current_path,
545                                               &background_area,
546                                               &inner_area,
547                                               flags))
548                   return TRUE;
549             }
550           else if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
551             {
552               GtkCellEditable *editable_widget;
553
554               editable_widget =
555                 gtk_cell_renderer_start_editing (priv->focus_cell,
556                                                  event, widget,
557                                                  priv->current_path,
558                                                  &background_area,
559                                                  &inner_area,
560                                                  flags);
561
562               if (editable_widget != NULL)
563                 {
564                   g_return_val_if_fail (GTK_IS_CELL_EDITABLE (editable_widget), FALSE);
565
566                   gtk_cell_area_set_edited_cell (area, priv->focus_cell);
567
568                   /* Signal that editing started so that callers can get 
569                    * a handle on the editable_widget */
570                   gtk_cell_area_editing_started (area, priv->focus_cell, editable_widget);
571                   
572                   return TRUE;
573                 }
574             }
575         }
576     }
577
578   return FALSE;
579 }
580
581 static void
582 gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea        *area,
583                                                    GtkCellAreaIter    *iter,
584                                                    GtkWidget          *widget,
585                                                    gint                width,
586                                                    gint               *minimum_height,
587                                                    gint               *natural_height)
588 {
589   /* If the area doesnt do height-for-width, fallback on base preferred height */
590   GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, iter, widget, minimum_height, natural_height);
591 }
592
593 static void
594 gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea        *area,
595                                                    GtkCellAreaIter    *iter,
596                                                    GtkWidget          *widget,
597                                                    gint                height,
598                                                    gint               *minimum_width,
599                                                    gint               *natural_width)
600 {
601   /* If the area doesnt do width-for-height, fallback on base preferred width */
602   GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, iter, widget, minimum_width, natural_width);
603 }
604
605 static void
606 update_can_focus (GtkCellRenderer *renderer,
607                   gboolean        *can_focus)
608 {
609
610   if (gtk_cell_renderer_can_focus (renderer))
611     *can_focus = TRUE;
612 }
613
614 static void
615 gtk_cell_area_real_update_focus (GtkCellArea *area)
616 {
617   gboolean can_focus = FALSE;
618
619   /* Update the area's can focus flag, if any of the renderers can
620    * focus then the area can focus.
621    *
622    * Subclasses can override this in the case that they are also
623    * rendering widgets as well as renderers.
624    */
625   gtk_cell_area_forall (area, (GtkCellCallback)update_can_focus, &can_focus);
626   gtk_cell_area_set_can_focus (area, can_focus);
627
628   /* Unset the currently focused cell if the area can not receive
629    * focus for the given row data */
630   if (!can_focus)
631     gtk_cell_area_set_focus_cell (area, NULL);
632 }
633
634 /*************************************************************
635  *                   GtkCellLayoutIface                      *
636  *************************************************************/
637 static void
638 gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface)
639 {
640   iface->pack_start         = gtk_cell_area_pack_default;
641   iface->pack_end           = gtk_cell_area_pack_default;
642   iface->clear              = gtk_cell_area_clear;
643   iface->add_attribute      = gtk_cell_area_add_attribute;
644   iface->set_cell_data_func = gtk_cell_area_set_cell_data_func;
645   iface->clear_attributes   = gtk_cell_area_clear_attributes;
646   iface->reorder            = gtk_cell_area_reorder;
647   iface->get_cells          = gtk_cell_area_get_cells;
648 }
649
650 static void
651 gtk_cell_area_pack_default (GtkCellLayout         *cell_layout,
652                             GtkCellRenderer       *renderer,
653                             gboolean               expand)
654 {
655   gtk_cell_area_add (GTK_CELL_AREA (cell_layout), renderer);
656 }
657
658 static void
659 gtk_cell_area_clear (GtkCellLayout *cell_layout)
660 {
661   GtkCellArea *area = GTK_CELL_AREA (cell_layout);
662   GList *l, *cells  =
663     gtk_cell_layout_get_cells (cell_layout);
664
665   for (l = cells; l; l = l->next)
666     {
667       GtkCellRenderer *renderer = l->data;
668       gtk_cell_area_remove (area, renderer);
669     }
670
671   g_list_free (cells);
672 }
673
674 static void
675 gtk_cell_area_add_attribute (GtkCellLayout         *cell_layout,
676                              GtkCellRenderer       *renderer,
677                              const gchar           *attribute,
678                              gint                   column)
679 {
680   gtk_cell_area_attribute_connect (GTK_CELL_AREA (cell_layout),
681                                    renderer, attribute, column);
682 }
683
684 static void
685 gtk_cell_area_set_cell_data_func (GtkCellLayout         *cell_layout,
686                                   GtkCellRenderer       *renderer,
687                                   GtkCellLayoutDataFunc  func,
688                                   gpointer               func_data,
689                                   GDestroyNotify         destroy)
690 {
691   GtkCellArea        *area   = GTK_CELL_AREA (cell_layout);
692   GtkCellAreaPrivate *priv   = area->priv;
693   CellInfo           *info;
694
695   info = g_hash_table_lookup (priv->cell_info, renderer);
696
697   if (info)
698     {
699       if (info->destroy && info->data)
700         info->destroy (info->data);
701
702       if (func)
703         {
704           info->func    = func;
705           info->data    = func_data;
706           info->destroy = destroy;
707         }
708       else
709         {
710           info->func    = NULL;
711           info->data    = NULL;
712           info->destroy = NULL;
713         }
714     }
715   else
716     {
717       info = cell_info_new (func, func_data, destroy);
718
719       g_hash_table_insert (priv->cell_info, renderer, info);
720     }
721 }
722
723 static void
724 gtk_cell_area_clear_attributes (GtkCellLayout         *cell_layout,
725                                 GtkCellRenderer       *renderer)
726 {
727   GtkCellArea        *area = GTK_CELL_AREA (cell_layout);
728   GtkCellAreaPrivate *priv = area->priv;
729   CellInfo           *info;
730
731   info = g_hash_table_lookup (priv->cell_info, renderer);
732
733   if (info)
734     {
735       g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
736       g_slist_free (info->attributes);
737
738       info->attributes = NULL;
739     }
740 }
741
742 static void 
743 gtk_cell_area_reorder (GtkCellLayout   *cell_layout,
744                        GtkCellRenderer *cell,
745                        gint             position)
746 {
747   g_warning ("GtkCellLayout::reorder not implemented for `%s'", 
748              g_type_name (G_TYPE_FROM_INSTANCE (cell_layout)));
749 }
750
751 static void
752 accum_cells (GtkCellRenderer *renderer,
753              GList          **accum)
754 {
755   *accum = g_list_prepend (*accum, renderer);
756 }
757
758 static GList *
759 gtk_cell_area_get_cells (GtkCellLayout *cell_layout)
760 {
761   GList *cells = NULL;
762
763   gtk_cell_area_forall (GTK_CELL_AREA (cell_layout), 
764                         (GtkCellCallback)accum_cells,
765                         &cells);
766
767   return g_list_reverse (cells);
768 }
769
770
771 /*************************************************************
772  *                            API                            *
773  *************************************************************/
774
775 /**
776  * gtk_cell_area_add:
777  * @area: a #GtkCellArea
778  * @renderer: the #GtkCellRenderer to add to @area
779  *
780  * Adds @renderer to @area with the default child cell properties.
781  */
782 void
783 gtk_cell_area_add (GtkCellArea        *area,
784                    GtkCellRenderer    *renderer)
785 {
786   GtkCellAreaClass *class;
787
788   g_return_if_fail (GTK_IS_CELL_AREA (area));
789   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
790
791   class = GTK_CELL_AREA_GET_CLASS (area);
792
793   if (class->add)
794     class->add (area, renderer);
795   else
796     g_warning ("GtkCellAreaClass::add not implemented for `%s'", 
797                g_type_name (G_TYPE_FROM_INSTANCE (area)));
798 }
799
800 /**
801  * gtk_cell_area_remove:
802  * @area: a #GtkCellArea
803  * @renderer: the #GtkCellRenderer to add to @area
804  *
805  * Removes @renderer from @area.
806  */
807 void
808 gtk_cell_area_remove (GtkCellArea        *area,
809                       GtkCellRenderer    *renderer)
810 {
811   GtkCellAreaClass   *class;
812   GtkCellAreaPrivate *priv;
813
814   g_return_if_fail (GTK_IS_CELL_AREA (area));
815   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
816
817   class = GTK_CELL_AREA_GET_CLASS (area);
818   priv  = area->priv;
819
820   /* Remove any custom attributes and custom cell data func here first */
821   g_hash_table_remove (priv->cell_info, renderer);
822
823   if (class->remove)
824     class->remove (area, renderer);
825   else
826     g_warning ("GtkCellAreaClass::remove not implemented for `%s'", 
827                g_type_name (G_TYPE_FROM_INSTANCE (area)));
828 }
829
830 /**
831  * gtk_cell_area_forall
832  * @area: a #GtkCellArea
833  * @callback: the #GtkCellCallback to call
834  * @callback_data: user provided data pointer
835  *
836  * Calls @callback for every #GtkCellRenderer in @area.
837  */
838 void
839 gtk_cell_area_forall (GtkCellArea        *area,
840                       GtkCellCallback     callback,
841                       gpointer            callback_data)
842 {
843   GtkCellAreaClass *class;
844
845   g_return_if_fail (GTK_IS_CELL_AREA (area));
846   g_return_if_fail (callback != NULL);
847
848   class = GTK_CELL_AREA_GET_CLASS (area);
849
850   if (class->forall)
851     class->forall (area, callback, callback_data);
852   else
853     g_warning ("GtkCellAreaClass::forall not implemented for `%s'", 
854                g_type_name (G_TYPE_FROM_INSTANCE (area)));
855 }
856
857 /**
858  * gtk_cell_area_get_cell_allocation:
859  * @area: a #GtkCellArea
860  * @iter: the #GtkCellAreaIter used to hold sizes for @area.
861  * @widget: the #GtkWidget that @area is rendering on
862  * @renderer: the #GtkCellRenderer to get the allocation for
863  * @cell_area: the whole allocated area for @area in @widget
864  *             for this row
865  * @allocation: where to store the allocation for @renderer
866  *
867  * Derives the allocation of @renderer inside @area if @area
868  * were to be renderered in @cell_area.
869  */
870 void
871 gtk_cell_area_get_cell_allocation (GtkCellArea          *area,
872                                    GtkCellAreaIter      *iter,  
873                                    GtkWidget            *widget,
874                                    GtkCellRenderer      *renderer,
875                                    const GdkRectangle   *cell_area,
876                                    GdkRectangle         *allocation)
877 {
878   GtkCellAreaClass *class;
879
880   g_return_if_fail (GTK_IS_CELL_AREA (area));
881   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
882   g_return_if_fail (GTK_IS_WIDGET (widget));
883   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
884   g_return_if_fail (cell_area != NULL);
885   g_return_if_fail (allocation != NULL);
886
887   class = GTK_CELL_AREA_GET_CLASS (area);
888
889   if (class->get_cell_allocation)
890     class->get_cell_allocation (area, iter, widget, renderer, cell_area, allocation);
891   else
892     g_warning ("GtkCellAreaClass::get_cell_allocation not implemented for `%s'", 
893                g_type_name (G_TYPE_FROM_INSTANCE (area)));
894 }
895
896 gint
897 gtk_cell_area_event (GtkCellArea          *area,
898                      GtkCellAreaIter      *iter,
899                      GtkWidget            *widget,
900                      GdkEvent             *event,
901                      const GdkRectangle   *cell_area,
902                      GtkCellRendererState  flags)
903 {
904   GtkCellAreaClass *class;
905
906   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
907   g_return_val_if_fail (GTK_IS_CELL_AREA_ITER (iter), 0);
908   g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
909   g_return_val_if_fail (event != NULL, 0);
910   g_return_val_if_fail (cell_area != NULL, 0);
911
912   class = GTK_CELL_AREA_GET_CLASS (area);
913
914   if (class->event)
915     return class->event (area, iter, widget, event, cell_area, flags);
916
917   g_warning ("GtkCellAreaClass::event not implemented for `%s'", 
918              g_type_name (G_TYPE_FROM_INSTANCE (area)));
919   return 0;
920 }
921
922 void
923 gtk_cell_area_render (GtkCellArea          *area,
924                       GtkCellAreaIter      *iter,
925                       GtkWidget            *widget,
926                       cairo_t              *cr,
927                       const GdkRectangle   *cell_area,
928                       GtkCellRendererState  flags)
929 {
930   GtkCellAreaClass *class;
931
932   g_return_if_fail (GTK_IS_CELL_AREA (area));
933   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
934   g_return_if_fail (GTK_IS_WIDGET (widget));
935   g_return_if_fail (cr != NULL);
936   g_return_if_fail (cell_area != NULL);
937
938   class = GTK_CELL_AREA_GET_CLASS (area);
939
940   if (class->render)
941     class->render (area, iter, widget, cr, cell_area, flags);
942   else
943     g_warning ("GtkCellAreaClass::render not implemented for `%s'", 
944                g_type_name (G_TYPE_FROM_INSTANCE (area)));
945 }
946
947 /*************************************************************
948  *                      API: Geometry                        *
949  *************************************************************/
950 GtkCellAreaIter   *
951 gtk_cell_area_create_iter (GtkCellArea *area)
952 {
953   GtkCellAreaClass *class;
954
955   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
956
957   class = GTK_CELL_AREA_GET_CLASS (area);
958
959   if (class->create_iter)
960     return class->create_iter (area);
961
962   g_warning ("GtkCellAreaClass::create_iter not implemented for `%s'", 
963              g_type_name (G_TYPE_FROM_INSTANCE (area)));
964   
965   return NULL;
966 }
967
968
969 GtkSizeRequestMode 
970 gtk_cell_area_get_request_mode (GtkCellArea *area)
971 {
972   GtkCellAreaClass *class;
973
974   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 
975                         GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH);
976
977   class = GTK_CELL_AREA_GET_CLASS (area);
978
979   if (class->get_request_mode)
980     return class->get_request_mode (area);
981
982   g_warning ("GtkCellAreaClass::get_request_mode not implemented for `%s'", 
983              g_type_name (G_TYPE_FROM_INSTANCE (area)));
984   
985   return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
986 }
987
988 void
989 gtk_cell_area_get_preferred_width (GtkCellArea        *area,
990                                    GtkCellAreaIter    *iter,
991                                    GtkWidget          *widget,
992                                    gint               *minimum_size,
993                                    gint               *natural_size)
994 {
995   GtkCellAreaClass *class;
996
997   g_return_if_fail (GTK_IS_CELL_AREA (area));
998   g_return_if_fail (GTK_IS_WIDGET (widget));
999
1000   class = GTK_CELL_AREA_GET_CLASS (area);
1001
1002   if (class->get_preferred_width)
1003     class->get_preferred_width (area, iter, widget, minimum_size, natural_size);
1004   else
1005     g_warning ("GtkCellAreaClass::get_preferred_width not implemented for `%s'", 
1006                g_type_name (G_TYPE_FROM_INSTANCE (area)));
1007 }
1008
1009 void
1010 gtk_cell_area_get_preferred_height_for_width (GtkCellArea        *area,
1011                                               GtkCellAreaIter    *iter,
1012                                               GtkWidget          *widget,
1013                                               gint                width,
1014                                               gint               *minimum_height,
1015                                               gint               *natural_height)
1016 {
1017   GtkCellAreaClass *class;
1018
1019   g_return_if_fail (GTK_IS_CELL_AREA (area));
1020   g_return_if_fail (GTK_IS_WIDGET (widget));
1021
1022   class = GTK_CELL_AREA_GET_CLASS (area);
1023   class->get_preferred_height_for_width (area, iter, widget, width, minimum_height, natural_height);
1024 }
1025
1026 void
1027 gtk_cell_area_get_preferred_height (GtkCellArea        *area,
1028                                     GtkCellAreaIter    *iter,
1029                                     GtkWidget          *widget,
1030                                     gint               *minimum_size,
1031                                     gint               *natural_size)
1032 {
1033   GtkCellAreaClass *class;
1034
1035   g_return_if_fail (GTK_IS_CELL_AREA (area));
1036   g_return_if_fail (GTK_IS_WIDGET (widget));
1037
1038   class = GTK_CELL_AREA_GET_CLASS (area);
1039
1040   if (class->get_preferred_height)
1041     class->get_preferred_height (area, iter, widget, minimum_size, natural_size);
1042   else
1043     g_warning ("GtkCellAreaClass::get_preferred_height not implemented for `%s'", 
1044                g_type_name (G_TYPE_FROM_INSTANCE (area)));
1045 }
1046
1047 void
1048 gtk_cell_area_get_preferred_width_for_height (GtkCellArea        *area,
1049                                               GtkCellAreaIter    *iter,
1050                                               GtkWidget          *widget,
1051                                               gint                height,
1052                                               gint               *minimum_width,
1053                                               gint               *natural_width)
1054 {
1055   GtkCellAreaClass *class;
1056
1057   g_return_if_fail (GTK_IS_CELL_AREA (area));
1058   g_return_if_fail (GTK_IS_WIDGET (widget));
1059
1060   class = GTK_CELL_AREA_GET_CLASS (area);
1061   class->get_preferred_width_for_height (area, iter, widget, height, minimum_width, natural_width);
1062 }
1063
1064 /*************************************************************
1065  *                      API: Attributes                      *
1066  *************************************************************/
1067
1068 /**
1069  * gtk_cell_area_attribute_connect:
1070  * @area: a #GtkCellArea
1071  * @renderer: the #GtkCellRenderer to connect an attribute for
1072  * @attribute: the attribute name
1073  * @column: the #GtkTreeModel column to fetch attribute values from
1074  *
1075  * Connects an @attribute to apply values from @column for the
1076  * #GtkTreeModel in use.
1077  */
1078 void
1079 gtk_cell_area_attribute_connect (GtkCellArea        *area,
1080                                  GtkCellRenderer    *renderer,
1081                                  const gchar        *attribute,
1082                                  gint                column)
1083
1084   GtkCellAreaPrivate *priv;
1085   CellInfo           *info;
1086   CellAttribute      *cell_attribute;
1087
1088   g_return_if_fail (GTK_IS_CELL_AREA (area));
1089   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1090   g_return_if_fail (attribute != NULL);
1091
1092   priv = area->priv;
1093   info = g_hash_table_lookup (priv->cell_info, renderer);
1094
1095   if (!info)
1096     {
1097       info = cell_info_new (NULL, NULL, NULL);
1098
1099       g_hash_table_insert (priv->cell_info, renderer, info);
1100     }
1101   else
1102     {
1103       GSList *node;
1104
1105       /* Check we are not adding the same attribute twice */
1106       if ((node = g_slist_find_custom (info->attributes, attribute,
1107                                        (GCompareFunc)cell_attribute_find)) != NULL)
1108         {
1109           cell_attribute = node->data;
1110
1111           g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
1112                      "since `%s' is already attributed to column %d", 
1113                      attribute,
1114                      g_type_name (G_TYPE_FROM_INSTANCE (area)),
1115                      attribute, cell_attribute->column);
1116           return;
1117         }
1118     }
1119
1120   cell_attribute = cell_attribute_new (renderer, attribute, column);
1121
1122   if (!cell_attribute)
1123     {
1124       g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
1125                  "since attribute does not exist", 
1126                  attribute,
1127                  g_type_name (G_TYPE_FROM_INSTANCE (area)));
1128       return;
1129     }
1130
1131   info->attributes = g_slist_prepend (info->attributes, cell_attribute);
1132 }
1133
1134 /**
1135  * gtk_cell_area_attribute_disconnect:
1136  * @area: a #GtkCellArea
1137  * @renderer: the #GtkCellRenderer to disconnect an attribute for
1138  * @attribute: the attribute name
1139  *
1140  * Disconnects @attribute for the @renderer in @area so that
1141  * attribute will no longer be updated with values from the
1142  * model.
1143  */
1144 void 
1145 gtk_cell_area_attribute_disconnect (GtkCellArea        *area,
1146                                     GtkCellRenderer    *renderer,
1147                                     const gchar        *attribute)
1148 {
1149   GtkCellAreaPrivate *priv;
1150   CellInfo           *info;
1151   CellAttribute      *cell_attribute;
1152   GSList             *node;
1153
1154   g_return_if_fail (GTK_IS_CELL_AREA (area));
1155   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1156   g_return_if_fail (attribute != NULL);
1157
1158   priv = area->priv;
1159   info = g_hash_table_lookup (priv->cell_info, renderer);
1160
1161   if (info)
1162     {
1163       node = g_slist_find_custom (info->attributes, attribute,
1164                                   (GCompareFunc)cell_attribute_find);
1165       if (node)
1166         {
1167           cell_attribute = node->data;
1168
1169           cell_attribute_free (cell_attribute);
1170
1171           info->attributes = g_slist_delete_link (info->attributes, node);
1172         }
1173     }
1174 }
1175
1176 static void
1177 apply_cell_attributes (GtkCellRenderer *renderer,
1178                        CellInfo        *info,
1179                        AttributeData   *data)
1180 {
1181   CellAttribute *attribute;
1182   GSList        *list;
1183   GValue         value = { 0, };
1184   gboolean       is_expander;
1185   gboolean       is_expanded;
1186
1187   g_object_freeze_notify (G_OBJECT (renderer));
1188
1189   /* Whether a row expands or is presently expanded can only be 
1190    * provided by the view (as these states can vary across views
1191    * accessing the same model).
1192    */
1193   g_object_get (renderer, "is-expander", &is_expander, NULL);
1194   if (is_expander != data->is_expander)
1195     g_object_set (renderer, "is-expander", data->is_expander, NULL);
1196   
1197   g_object_get (renderer, "is-expanded", &is_expanded, NULL);
1198   if (is_expanded != data->is_expanded)
1199     g_object_set (renderer, "is-expanded", data->is_expanded, NULL);
1200
1201   /* Apply the attributes directly to the renderer */
1202   for (list = info->attributes; list; list = list->next)
1203     {
1204       attribute = list->data;
1205
1206       gtk_tree_model_get_value (data->model, data->iter, attribute->column, &value);
1207       g_object_set_property (G_OBJECT (renderer), attribute->attribute, &value);
1208       g_value_unset (&value);
1209     }
1210
1211   /* Call any GtkCellLayoutDataFunc that may have been set by the user
1212    */
1213   if (info->func)
1214     info->func (GTK_CELL_LAYOUT (data->area), renderer,
1215                 data->model, data->iter, info->data);
1216
1217   g_object_thaw_notify (G_OBJECT (renderer));
1218 }
1219
1220 /**
1221  * gtk_cell_area_apply_attributes
1222  * @area: a #GtkCellArea
1223  * @tree_model: a #GtkTreeModel to pull values from
1224  * @iter: the #GtkTreeIter in @tree_model to apply values for
1225  * @is_expander: whether @iter has children
1226  * @is_expanded: whether @iter is expanded in the view and
1227  *               children are visible
1228  *
1229  * Applies any connected attributes to the renderers in 
1230  * @area by pulling the values from @tree_model.
1231  */
1232 void
1233 gtk_cell_area_apply_attributes (GtkCellArea  *area,
1234                                 GtkTreeModel *tree_model,
1235                                 GtkTreeIter  *iter,
1236                                 gboolean      is_expander,
1237                                 gboolean      is_expanded)
1238 {
1239   GtkCellAreaPrivate *priv;
1240   AttributeData       data;
1241   GtkTreePath        *path;
1242
1243   g_return_if_fail (GTK_IS_CELL_AREA (area));
1244   g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
1245   g_return_if_fail (iter != NULL);
1246
1247   priv = area->priv;
1248
1249   /* Feed in data needed to apply to every renderer */
1250   data.area        = area;
1251   data.model       = tree_model;
1252   data.iter        = iter;
1253   data.is_expander = is_expander;
1254   data.is_expanded = is_expanded;
1255
1256   /* Go over any cells that have attributes or custom GtkCellLayoutDataFuncs and
1257    * apply the data from the treemodel */
1258   g_hash_table_foreach (priv->cell_info, (GHFunc)apply_cell_attributes, &data);
1259
1260   /* Update the currently applied path */
1261   g_free (priv->current_path);
1262   path               = gtk_tree_model_get_path (tree_model, iter);
1263   priv->current_path = gtk_tree_path_to_string (path);
1264   gtk_tree_path_free (path);
1265 }
1266
1267 /**
1268  * gtk_cell_area_get_current_path_string:
1269  * @area: a #GtkCellArea
1270  *
1271  * Gets the current #GtkTreePath string for the currently
1272  * applied #GtkTreeIter, this is implicitly updated when
1273  * gtk_cell_area_apply_attributes() is called and can be
1274  * used to interact with renderers from #GtkCellArea
1275  * subclasses.
1276  */
1277 const gchar *
1278 gtk_cell_area_get_current_path_string (GtkCellArea *area)
1279 {
1280   GtkCellAreaPrivate *priv;
1281
1282   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1283
1284   priv = area->priv;
1285
1286   return priv->current_path;
1287 }
1288
1289
1290 /*************************************************************
1291  *                    API: Cell Properties                   *
1292  *************************************************************/
1293 void
1294 gtk_cell_area_class_install_cell_property (GtkCellAreaClass   *aclass,
1295                                            guint               property_id,
1296                                            GParamSpec         *pspec)
1297 {
1298   g_return_if_fail (GTK_IS_CELL_AREA_CLASS (aclass));
1299   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1300   if (pspec->flags & G_PARAM_WRITABLE)
1301     g_return_if_fail (aclass->set_cell_property != NULL);
1302   if (pspec->flags & G_PARAM_READABLE)
1303     g_return_if_fail (aclass->get_cell_property != NULL);
1304   g_return_if_fail (property_id > 0);
1305   g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0);  /* paranoid */
1306   g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0);
1307
1308   if (g_param_spec_pool_lookup (cell_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (aclass), TRUE))
1309     {
1310       g_warning (G_STRLOC ": class `%s' already contains a cell property named `%s'",
1311                  G_OBJECT_CLASS_NAME (aclass), pspec->name);
1312       return;
1313     }
1314   g_param_spec_ref (pspec);
1315   g_param_spec_sink (pspec);
1316   PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
1317   g_param_spec_pool_insert (cell_property_pool, pspec, G_OBJECT_CLASS_TYPE (aclass));
1318 }
1319
1320 GParamSpec*
1321 gtk_cell_area_class_find_cell_property (GtkCellAreaClass   *aclass,
1322                                         const gchar        *property_name)
1323 {
1324   g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
1325   g_return_val_if_fail (property_name != NULL, NULL);
1326
1327   return g_param_spec_pool_lookup (cell_property_pool,
1328                                    property_name,
1329                                    G_OBJECT_CLASS_TYPE (aclass),
1330                                    TRUE);
1331 }
1332
1333 GParamSpec**
1334 gtk_cell_area_class_list_cell_properties (GtkCellAreaClass   *aclass,
1335                                           guint             *n_properties)
1336 {
1337   GParamSpec **pspecs;
1338   guint n;
1339
1340   g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
1341
1342   pspecs = g_param_spec_pool_list (cell_property_pool,
1343                                    G_OBJECT_CLASS_TYPE (aclass),
1344                                    &n);
1345   if (n_properties)
1346     *n_properties = n;
1347
1348   return pspecs;
1349 }
1350
1351 void
1352 gtk_cell_area_add_with_properties (GtkCellArea        *area,
1353                                    GtkCellRenderer    *renderer,
1354                                    const gchar        *first_prop_name,
1355                                    ...)
1356 {
1357   GtkCellAreaClass *class;
1358
1359   g_return_if_fail (GTK_IS_CELL_AREA (area));
1360   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1361
1362   class = GTK_CELL_AREA_GET_CLASS (area);
1363
1364   if (class->add)
1365     {
1366       va_list var_args;
1367
1368       class->add (area, renderer);
1369
1370       va_start (var_args, first_prop_name);
1371       gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1372       va_end (var_args);
1373     }
1374   else
1375     g_warning ("GtkCellAreaClass::add not implemented for `%s'", 
1376                g_type_name (G_TYPE_FROM_INSTANCE (area)));
1377 }
1378
1379 void
1380 gtk_cell_area_cell_set (GtkCellArea        *area,
1381                         GtkCellRenderer    *renderer,
1382                         const gchar        *first_prop_name,
1383                         ...)
1384 {
1385   va_list var_args;
1386
1387   g_return_if_fail (GTK_IS_CELL_AREA (area));
1388   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1389
1390   va_start (var_args, first_prop_name);
1391   gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1392   va_end (var_args);
1393 }
1394
1395 void
1396 gtk_cell_area_cell_get (GtkCellArea        *area,
1397                         GtkCellRenderer    *renderer,
1398                         const gchar        *first_prop_name,
1399                         ...)
1400 {
1401   va_list var_args;
1402
1403   g_return_if_fail (GTK_IS_CELL_AREA (area));
1404   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1405
1406   va_start (var_args, first_prop_name);
1407   gtk_cell_area_cell_get_valist (area, renderer, first_prop_name, var_args);
1408   va_end (var_args);
1409 }
1410
1411 static inline void
1412 area_get_cell_property (GtkCellArea     *area,
1413                         GtkCellRenderer *renderer,
1414                         GParamSpec      *pspec,
1415                         GValue          *value)
1416 {
1417   GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1418   
1419   class->get_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), value, pspec);
1420 }
1421
1422 static inline void
1423 area_set_cell_property (GtkCellArea     *area,
1424                         GtkCellRenderer *renderer,
1425                         GParamSpec      *pspec,
1426                         const GValue    *value)
1427 {
1428   GValue tmp_value = { 0, };
1429   GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1430
1431   /* provide a copy to work from, convert (if necessary) and validate */
1432   g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1433   if (!g_value_transform (value, &tmp_value))
1434     g_warning ("unable to set cell property `%s' of type `%s' from value of type `%s'",
1435                pspec->name,
1436                g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1437                G_VALUE_TYPE_NAME (value));
1438   else if (g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION))
1439     {
1440       gchar *contents = g_strdup_value_contents (value);
1441
1442       g_warning ("value \"%s\" of type `%s' is invalid for property `%s' of type `%s'",
1443                  contents,
1444                  G_VALUE_TYPE_NAME (value),
1445                  pspec->name,
1446                  g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
1447       g_free (contents);
1448     }
1449   else
1450     {
1451       class->set_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec);
1452     }
1453   g_value_unset (&tmp_value);
1454 }
1455
1456 void
1457 gtk_cell_area_cell_set_valist (GtkCellArea        *area,
1458                                GtkCellRenderer    *renderer,
1459                                const gchar        *first_property_name,
1460                                va_list             var_args)
1461 {
1462   const gchar *name;
1463
1464   g_return_if_fail (GTK_IS_CELL_AREA (area));
1465   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1466
1467   name = first_property_name;
1468   while (name)
1469     {
1470       GValue value = { 0, };
1471       gchar *error = NULL;
1472       GParamSpec *pspec = 
1473         g_param_spec_pool_lookup (cell_property_pool, name,
1474                                   G_OBJECT_TYPE (area), TRUE);
1475       if (!pspec)
1476         {
1477           g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1478                      G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1479           break;
1480         }
1481       if (!(pspec->flags & G_PARAM_WRITABLE))
1482         {
1483           g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1484                      G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1485           break;
1486         }
1487
1488       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1489       G_VALUE_COLLECT (&value, var_args, 0, &error);
1490       if (error)
1491         {
1492           g_warning ("%s: %s", G_STRLOC, error);
1493           g_free (error);
1494
1495           /* we purposely leak the value here, it might not be
1496            * in a sane state if an error condition occoured
1497            */
1498           break;
1499         }
1500       area_set_cell_property (area, renderer, pspec, &value);
1501       g_value_unset (&value);
1502       name = va_arg (var_args, gchar*);
1503     }
1504 }
1505
1506 void
1507 gtk_cell_area_cell_get_valist (GtkCellArea        *area,
1508                                GtkCellRenderer    *renderer,
1509                                const gchar        *first_property_name,
1510                                va_list             var_args)
1511 {
1512   const gchar *name;
1513
1514   g_return_if_fail (GTK_IS_CELL_AREA (area));
1515   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1516
1517   name = first_property_name;
1518   while (name)
1519     {
1520       GValue value = { 0, };
1521       GParamSpec *pspec;
1522       gchar *error;
1523
1524       pspec = g_param_spec_pool_lookup (cell_property_pool, name,
1525                                         G_OBJECT_TYPE (area), TRUE);
1526       if (!pspec)
1527         {
1528           g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1529                      G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1530           break;
1531         }
1532       if (!(pspec->flags & G_PARAM_READABLE))
1533         {
1534           g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1535                      G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1536           break;
1537         }
1538
1539       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1540       area_get_cell_property (area, renderer, pspec, &value);
1541       G_VALUE_LCOPY (&value, var_args, 0, &error);
1542       if (error)
1543         {
1544           g_warning ("%s: %s", G_STRLOC, error);
1545           g_free (error);
1546           g_value_unset (&value);
1547           break;
1548         }
1549       g_value_unset (&value);
1550       name = va_arg (var_args, gchar*);
1551     }
1552 }
1553
1554 void
1555 gtk_cell_area_cell_set_property (GtkCellArea        *area,
1556                                  GtkCellRenderer    *renderer,
1557                                  const gchar        *property_name,
1558                                  const GValue       *value)
1559 {
1560   GParamSpec *pspec;
1561
1562   g_return_if_fail (GTK_IS_CELL_AREA (area));
1563   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1564   g_return_if_fail (property_name != NULL);
1565   g_return_if_fail (G_IS_VALUE (value));
1566   
1567   pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1568                                     G_OBJECT_TYPE (area), TRUE);
1569   if (!pspec)
1570     g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1571                G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1572   else if (!(pspec->flags & G_PARAM_WRITABLE))
1573     g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1574                G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1575   else
1576     {
1577       area_set_cell_property (area, renderer, pspec, value);
1578     }
1579 }
1580
1581 void
1582 gtk_cell_area_cell_get_property (GtkCellArea        *area,
1583                                  GtkCellRenderer    *renderer,
1584                                  const gchar        *property_name,
1585                                  GValue             *value)
1586 {
1587   GParamSpec *pspec;
1588
1589   g_return_if_fail (GTK_IS_CELL_AREA (area));
1590   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1591   g_return_if_fail (property_name != NULL);
1592   g_return_if_fail (G_IS_VALUE (value));
1593   
1594   pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1595                                     G_OBJECT_TYPE (area), TRUE);
1596   if (!pspec)
1597     g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1598                G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1599   else if (!(pspec->flags & G_PARAM_READABLE))
1600     g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1601                G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1602   else
1603     {
1604       GValue *prop_value, tmp_value = { 0, };
1605
1606       /* auto-conversion of the callers value type
1607        */
1608       if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
1609         {
1610           g_value_reset (value);
1611           prop_value = value;
1612         }
1613       else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
1614         {
1615           g_warning ("can't retrieve cell property `%s' of type `%s' as value of type `%s'",
1616                      pspec->name,
1617                      g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1618                      G_VALUE_TYPE_NAME (value));
1619           return;
1620         }
1621       else
1622         {
1623           g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1624           prop_value = &tmp_value;
1625         }
1626
1627       area_get_cell_property (area, renderer, pspec, prop_value);
1628
1629       if (prop_value != value)
1630         {
1631           g_value_transform (prop_value, value);
1632           g_value_unset (&tmp_value);
1633         }
1634     }
1635 }
1636
1637 /*************************************************************
1638  *                         API: Focus                        *
1639  *************************************************************/
1640
1641 /**
1642  * gtk_cell_area_grab_focus:
1643  * @area: a #GtkCellArea
1644  * @direction: the #GtkDirectionType from which focus came
1645  *
1646  * This should be called by the @area's owning layout widget
1647  * when focus should be passed to @area for a given row data.
1648  *
1649  * Note that after applying new attributes for @area that
1650  * gtk_cell_area_update_focus() should be called and
1651  * gtk_cell_area_can_focus() should be checked before trying
1652  * to pass focus to @area.
1653  *
1654  * Implementing #GtkCellArea classes should implement this
1655  * method to receive focus in it's own way particular to
1656  * how it lays out cells.
1657  */
1658 void
1659 gtk_cell_area_grab_focus (GtkCellArea      *area,
1660                           GtkDirectionType  direction)
1661 {
1662   GtkCellAreaClass *class;
1663
1664   g_return_if_fail (GTK_IS_CELL_AREA (area));
1665
1666   class = GTK_CELL_AREA_GET_CLASS (area);
1667
1668   if (class->grab_focus)
1669     class->grab_focus (area, direction);
1670   else
1671     g_warning ("GtkCellAreaClass::grab_focus not implemented for `%s'", 
1672                g_type_name (G_TYPE_FROM_INSTANCE (area)));
1673 }
1674
1675 /**
1676  * gtk_cell_area_focus_leave:
1677  * @area: a #GtkCellArea
1678  * @direction: the #GtkDirectionType in which focus
1679  *             is to leave @area
1680  * @path: the current #GtkTreePath string for the 
1681  *        event which was handled by @area
1682  *
1683  * Notifies that focus is to leave @area in the
1684  * given @direction.
1685  *
1686  * This is called by #GtkCellArea implementations upon
1687  * handling a key event that caused focus to leave the
1688  * cell. The resulting signal can be handled by the
1689  * owning layouting widget to decide which new @area
1690  * to pass focus to and from what @direction. Or to
1691  * pass focus along to an entirely new data row.
1692  */
1693 void
1694 gtk_cell_area_focus_leave (GtkCellArea        *area,
1695                            GtkDirectionType    direction,
1696                            const gchar        *path)
1697 {
1698   g_return_if_fail (GTK_IS_CELL_AREA (area));
1699
1700   g_signal_emit (area, cell_area_signals[SIGNAL_FOCUS_LEAVE], 0, direction, path);
1701 }
1702
1703 /**
1704  * gtk_cell_area_update_focus:
1705  * @area: a #GtkCellArea
1706  *
1707  * Updates focus information on @area for a given 
1708  * row of data.
1709  *
1710  * After calling gtk_cell_area_apply_attributes() to
1711  * the @area this method should be called to update
1712  * information about whether the @area can focus and
1713  * which is the cell currently in focus.
1714  */
1715 void
1716 gtk_cell_area_update_focus (GtkCellArea *area)
1717 {
1718   g_return_if_fail (GTK_IS_CELL_AREA (area));
1719
1720   GTK_CELL_AREA_GET_CLASS (area)->update_focus (area);
1721 }
1722
1723 /**
1724  * gtk_cell_area_set_can_focus:
1725  * @area: a #GtkCellArea
1726  * @can_focus: whether @area can receive focus
1727  *
1728  * This is generally called from GtkCellArea::update_focus() 
1729  * implementations to update if the @area can focus after
1730  * applying new row data attributes.
1731  */
1732 void
1733 gtk_cell_area_set_can_focus (GtkCellArea *area,
1734                              gboolean     can_focus)
1735 {
1736   GtkCellAreaPrivate *priv;
1737
1738   g_return_if_fail (GTK_IS_CELL_AREA (area));
1739
1740   priv = area->priv;
1741
1742   if (priv->can_focus != can_focus)
1743     {
1744       priv->can_focus = can_focus;
1745     }
1746 }
1747
1748 /**
1749  * gtk_cell_area_get_can_focus:
1750  * @area: a #GtkCellArea
1751  *
1752  * Returns whether the area can receive keyboard focus,
1753  * after applying new attributes to @area, 
1754  * gtk_cell_area_update_focus() needs to be called before
1755  * calling this method.
1756  *
1757  * Returns: whether @area can receive focus.
1758  */
1759 gboolean
1760 gtk_cell_area_get_can_focus (GtkCellArea *area)
1761 {
1762   GtkCellAreaPrivate *priv;
1763
1764   g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
1765
1766   priv = area->priv;
1767
1768   return priv->can_focus;
1769 }
1770
1771
1772 /**
1773  * gtk_cell_area_set_focus_cell:
1774  * @area: a #GtkCellArea
1775  * @focus_cell: the #GtkCellRenderer to give focus to
1776  *
1777  * This is generally called from #GtkCellArea implementations
1778  * either gtk_cell_area_grab_focus() or gtk_cell_area_update_focus()
1779  * is called. It's also up to the #GtkCellArea implementation
1780  * to update the focused cell when receiving events from
1781  * gtk_cell_area_event() appropriately.
1782  */
1783 void
1784 gtk_cell_area_set_focus_cell (GtkCellArea     *area,
1785                               GtkCellRenderer *renderer)
1786 {
1787   GtkCellAreaPrivate *priv;
1788
1789   g_return_if_fail (GTK_IS_CELL_AREA (area));
1790   g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer));
1791
1792   priv = area->priv;
1793
1794   if (priv->focus_cell != renderer)
1795     {
1796       if (priv->focus_cell)
1797         g_object_unref (priv->focus_cell);
1798
1799       priv->focus_cell = renderer;
1800
1801       if (priv->focus_cell)
1802         g_object_ref (priv->focus_cell);
1803
1804       g_object_notify (G_OBJECT (area), "focus-cell");
1805     }
1806 }
1807
1808 /**
1809  * gtk_cell_area_get_focus_cell:
1810  * @area: a #GtkCellArea
1811  *
1812  * Retrieves the currently focused cell for @area
1813  *
1814  * Returns: the currently focused cell in @area.
1815  */
1816 GtkCellRenderer *
1817 gtk_cell_area_get_focus_cell (GtkCellArea *area)
1818 {
1819   GtkCellAreaPrivate *priv;
1820
1821   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1822
1823   priv = area->priv;
1824
1825   return priv->focus_cell;
1826 }
1827
1828 void
1829 gtk_cell_area_set_edited_cell (GtkCellArea     *area,
1830                                GtkCellRenderer *renderer)
1831 {
1832   GtkCellAreaPrivate *priv;
1833
1834   g_return_if_fail (GTK_IS_CELL_AREA (area));
1835   g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer));
1836
1837   priv = area->priv;
1838
1839   if (priv->edited_cell != renderer)
1840     {
1841       if (priv->edited_cell)
1842         g_object_unref (priv->edited_cell);
1843
1844       priv->edited_cell = renderer;
1845
1846       if (priv->edited_cell)
1847         g_object_ref (priv->edited_cell);
1848
1849       g_object_notify (G_OBJECT (area), "edited-cell");
1850     }
1851 }
1852
1853 GtkCellRenderer   *
1854 gtk_cell_area_get_edited_cell (GtkCellArea *area)
1855 {
1856   GtkCellAreaPrivate *priv;
1857
1858   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1859
1860   priv = area->priv;
1861
1862   return priv->edited_cell;
1863 }
1864
1865 /*************************************************************
1866  *                        API: Margins                       *
1867  *************************************************************/
1868 gint
1869 gtk_cell_area_get_cell_margin_left (GtkCellArea *area)
1870 {
1871   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1872
1873   return area->priv->cell_border.left;
1874 }
1875
1876 void
1877 gtk_cell_area_set_cell_margin_left (GtkCellArea *area,
1878                                     gint         margin)
1879 {
1880   GtkCellAreaPrivate *priv;
1881
1882   g_return_if_fail (GTK_IS_CELL_AREA (area));
1883
1884   priv = area->priv;
1885
1886   if (priv->cell_border.left != margin)
1887     {
1888       priv->cell_border.left = margin;
1889
1890       g_object_notify (G_OBJECT (area), "margin-left");
1891     }
1892 }
1893
1894 gint
1895 gtk_cell_area_get_cell_margin_right (GtkCellArea *area)
1896 {
1897   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1898
1899   return area->priv->cell_border.right;
1900 }
1901
1902 void
1903 gtk_cell_area_set_cell_margin_right (GtkCellArea *area,
1904                                      gint         margin)
1905 {
1906   GtkCellAreaPrivate *priv;
1907
1908   g_return_if_fail (GTK_IS_CELL_AREA (area));
1909
1910   priv = area->priv;
1911
1912   if (priv->cell_border.right != margin)
1913     {
1914       priv->cell_border.right = margin;
1915
1916       g_object_notify (G_OBJECT (area), "margin-right");
1917     }
1918 }
1919
1920 gint
1921 gtk_cell_area_get_cell_margin_top (GtkCellArea *area)
1922 {
1923   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1924
1925   return area->priv->cell_border.top;
1926 }
1927
1928 void
1929 gtk_cell_area_set_cell_margin_top (GtkCellArea *area,
1930                                    gint         margin)
1931 {
1932   GtkCellAreaPrivate *priv;
1933
1934   g_return_if_fail (GTK_IS_CELL_AREA (area));
1935
1936   priv = area->priv;
1937
1938   if (priv->cell_border.top != margin)
1939     {
1940       priv->cell_border.top = margin;
1941
1942       g_object_notify (G_OBJECT (area), "margin-top");
1943     }
1944 }
1945
1946 gint
1947 gtk_cell_area_get_cell_margin_bottom (GtkCellArea *area)
1948 {
1949   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1950
1951   return area->priv->cell_border.bottom;
1952 }
1953
1954 void
1955 gtk_cell_area_set_cell_margin_bottom (GtkCellArea *area,
1956                                       gint         margin)
1957 {
1958   GtkCellAreaPrivate *priv;
1959
1960   g_return_if_fail (GTK_IS_CELL_AREA (area));
1961
1962   priv = area->priv;
1963
1964   if (priv->cell_border.bottom != margin)
1965     {
1966       priv->cell_border.bottom = margin;
1967
1968       g_object_notify (G_OBJECT (area), "margin-bottom");
1969     }
1970 }
1971
1972 /* For convenience in area implementations */
1973 void
1974 gtk_cell_area_editing_started (GtkCellArea        *area,
1975                                GtkCellRenderer    *renderer,
1976                                GtkCellEditable    *editable)
1977 {
1978   GtkCellAreaPrivate *priv;
1979
1980   g_return_if_fail (GTK_IS_CELL_AREA (area));
1981
1982   priv = area->priv;
1983
1984   g_signal_emit (area, cell_area_signals[SIGNAL_EDITING_STARTED], 0, 
1985                  renderer, editable, priv->current_path);
1986 }
1987
1988 void
1989 gtk_cell_area_inner_cell_area (GtkCellArea        *area,
1990                                GdkRectangle       *background_area,
1991                                GdkRectangle       *cell_area)
1992 {
1993   GtkCellAreaPrivate *priv;
1994
1995   g_return_if_fail (GTK_IS_CELL_AREA (area));
1996   g_return_if_fail (background_area != NULL);
1997   g_return_if_fail (cell_area != NULL);
1998
1999   priv = area->priv;
2000
2001   *cell_area = *background_area;
2002
2003   cell_area->x      += priv->cell_border.left;
2004   cell_area->width  -= (priv->cell_border.left + priv->cell_border.right);
2005   cell_area->y      += priv->cell_border.top;
2006   cell_area->height -= (priv->cell_border.top + priv->cell_border.bottom);
2007 }
2008
2009 void
2010 gtk_cell_area_request_renderer (GtkCellArea        *area,
2011                                 GtkCellRenderer    *renderer,
2012                                 GtkOrientation      orientation,
2013                                 GtkWidget          *widget,
2014                                 gint                for_size,
2015                                 gint               *minimum_size,
2016                                 gint               *natural_size)
2017 {
2018   GtkCellAreaPrivate *priv;
2019
2020   g_return_if_fail (GTK_IS_CELL_AREA (area));
2021   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2022   g_return_if_fail (GTK_IS_WIDGET (widget));
2023   g_return_if_fail (minimum_size != NULL);
2024   g_return_if_fail (natural_size != NULL);
2025
2026   priv = area->priv;
2027
2028   if (orientation == GTK_ORIENTATION_HORIZONTAL)
2029     {
2030       if (for_size < 0)
2031           gtk_cell_renderer_get_preferred_width (renderer, widget, minimum_size, natural_size);
2032       else
2033         {
2034           for_size = MAX (0, for_size - (priv->cell_border.top + priv->cell_border.bottom));
2035
2036           gtk_cell_renderer_get_preferred_width_for_height (renderer, widget, for_size, 
2037                                                             minimum_size, natural_size);
2038         }
2039
2040       *minimum_size += (priv->cell_border.left + priv->cell_border.right);
2041       *natural_size += (priv->cell_border.left + priv->cell_border.right);
2042     }
2043   else /* GTK_ORIENTATION_VERTICAL */
2044     {
2045       if (for_size < 0)
2046         gtk_cell_renderer_get_preferred_height (renderer, widget, minimum_size, natural_size);
2047       else
2048         {
2049           for_size = MAX (0, for_size - (priv->cell_border.left + priv->cell_border.right));
2050
2051           gtk_cell_renderer_get_preferred_height_for_width (renderer, widget, for_size, 
2052                                                             minimum_size, natural_size);
2053         }
2054
2055       *minimum_size += (priv->cell_border.top + priv->cell_border.bottom);
2056       *natural_size += (priv->cell_border.top + priv->cell_border.bottom);
2057     }
2058 }