]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellarea.c
7463e0bace9230a469132db434e558efb0182b67
[~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 "gtkcellareacontext.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                                                                     GtkCellAreaContext   *context,
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                                                                     GtkCellAreaContext    *context,
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                                                                     GtkCellAreaContext    *context,
67                                                                     GtkWidget             *widget,
68                                                                     gint                   height,
69                                                                     gint                  *minimum_width,
70                                                                     gint                  *natural_width);
71 static gboolean  gtk_cell_area_real_can_focus                      (GtkCellArea           *area);
72 static gboolean  gtk_cell_area_real_activate                       (GtkCellArea           *area,
73                                                                     GtkCellAreaContext    *context,
74                                                                     GtkWidget             *widget,
75                                                                     const GdkRectangle    *cell_area,
76                                                                     GtkCellRendererState   flags);
77
78 /* GtkCellLayoutIface */
79 static void      gtk_cell_area_cell_layout_init              (GtkCellLayoutIface    *iface);
80 static void      gtk_cell_area_pack_default                  (GtkCellLayout         *cell_layout,
81                                                               GtkCellRenderer       *renderer,
82                                                               gboolean               expand);
83 static void      gtk_cell_area_clear                         (GtkCellLayout         *cell_layout);
84 static void      gtk_cell_area_add_attribute                 (GtkCellLayout         *cell_layout,
85                                                               GtkCellRenderer       *renderer,
86                                                               const gchar           *attribute,
87                                                               gint                   column);
88 static void      gtk_cell_area_set_cell_data_func            (GtkCellLayout         *cell_layout,
89                                                               GtkCellRenderer       *cell,
90                                                               GtkCellLayoutDataFunc  func,
91                                                               gpointer               func_data,
92                                                               GDestroyNotify         destroy);
93 static void      gtk_cell_area_clear_attributes              (GtkCellLayout         *cell_layout,
94                                                               GtkCellRenderer       *renderer);
95 static void      gtk_cell_area_reorder                       (GtkCellLayout         *cell_layout,
96                                                               GtkCellRenderer       *cell,
97                                                               gint                   position);
98 static GList    *gtk_cell_area_get_cells                     (GtkCellLayout         *cell_layout);
99
100
101 /* Used in forall loop to check if a child renderer is present */
102 typedef struct {
103   GtkCellRenderer *renderer;
104   gboolean         has_renderer;
105 } HasRendererCheck;
106
107 /* Attribute/Cell metadata */
108 typedef struct {
109   const gchar *attribute;
110   gint         column;
111 } CellAttribute;
112
113 typedef struct {
114   GSList                *attributes;
115
116   GtkCellLayoutDataFunc  func;
117   gpointer               data;
118   GDestroyNotify         destroy;
119 } CellInfo;
120
121 static CellInfo       *cell_info_new       (GtkCellLayoutDataFunc  func,
122                                             gpointer               data,
123                                             GDestroyNotify         destroy);
124 static void            cell_info_free      (CellInfo              *info);
125 static CellAttribute  *cell_attribute_new  (GtkCellRenderer       *renderer,
126                                             const gchar           *attribute,
127                                             gint                   column);
128 static void            cell_attribute_free (CellAttribute         *attribute);
129 static gint            cell_attribute_find (CellAttribute         *cell_attribute,
130                                             const gchar           *attribute);
131
132 /* Internal functions/signal emissions */
133 static void            gtk_cell_area_add_editable     (GtkCellArea        *area,
134                                                        GtkCellRenderer    *renderer,
135                                                        GtkCellEditable    *editable,
136                                                        GdkRectangle       *cell_area);
137 static void            gtk_cell_area_remove_editable  (GtkCellArea        *area,
138                                                        GtkCellRenderer    *renderer,
139                                                        GtkCellEditable    *editable);
140 static void            gtk_cell_area_set_edit_widget  (GtkCellArea        *area,
141                                                        GtkCellEditable    *editable);
142 static void            gtk_cell_area_set_edited_cell  (GtkCellArea        *area,
143                                                        GtkCellRenderer    *renderer);
144
145
146 /* Struct to pass data along while looping over 
147  * cell renderers to apply attributes
148  */
149 typedef struct {
150   GtkCellArea  *area;
151   GtkTreeModel *model;
152   GtkTreeIter  *iter;
153   gboolean      is_expander;
154   gboolean      is_expanded;
155 } AttributeData;
156
157 struct _GtkCellAreaPrivate
158 {
159   /* The GtkCellArea bookkeeps any connected 
160    * attributes in this hash table.
161    */
162   GHashTable      *cell_info;
163
164   /* The cell border decides how much space to reserve
165    * around each cell for the background_area
166    */
167   GtkBorder        cell_border;
168
169   /* Current path is saved as a side-effect
170    * of gtk_cell_area_apply_attributes() */
171   gchar           *current_path;
172
173   /* Current cell being edited and editable widget used */
174   GtkCellEditable *edit_widget;
175   GtkCellRenderer *edited_cell;
176
177   /* Signal connections to the editable widget */
178   gulong           remove_widget_id;
179
180   /* Currently focused cell */
181   GtkCellRenderer *focus_cell;
182
183   /* Tracking which cells are focus siblings of focusable cells */
184   GHashTable      *focus_siblings;
185
186   /* Detail string to pass to gtk_paint_*() functions */
187   gchar           *style_detail;
188 };
189
190 enum {
191   PROP_0,
192   PROP_CELL_MARGIN_LEFT,
193   PROP_CELL_MARGIN_RIGHT,
194   PROP_CELL_MARGIN_TOP,
195   PROP_CELL_MARGIN_BOTTOM,
196   PROP_FOCUS_CELL,
197   PROP_EDITED_CELL,
198   PROP_EDIT_WIDGET
199 };
200
201 enum {
202   SIGNAL_ADD_EDITABLE,
203   SIGNAL_REMOVE_EDITABLE,
204   SIGNAL_FOCUS_CHANGED,
205   LAST_SIGNAL
206 };
207
208 /* Keep the paramspec pool internal, no need to deliver notifications
209  * on cells. at least no percieved need for now */
210 static GParamSpecPool *cell_property_pool = NULL;
211 static guint           cell_area_signals[LAST_SIGNAL] = { 0 };
212
213 #define PARAM_SPEC_PARAM_ID(pspec)              ((pspec)->param_id)
214 #define PARAM_SPEC_SET_PARAM_ID(pspec, id)      ((pspec)->param_id = (id))
215
216
217 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkCellArea, gtk_cell_area, G_TYPE_INITIALLY_UNOWNED,
218                                   G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
219                                                          gtk_cell_area_cell_layout_init));
220
221 static void
222 gtk_cell_area_init (GtkCellArea *area)
223 {
224   GtkCellAreaPrivate *priv;
225
226   area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area,
227                                             GTK_TYPE_CELL_AREA,
228                                             GtkCellAreaPrivate);
229   priv = area->priv;
230
231   priv->cell_info = g_hash_table_new_full (g_direct_hash, 
232                                            g_direct_equal,
233                                            NULL, 
234                                            (GDestroyNotify)cell_info_free);
235
236   priv->focus_siblings = g_hash_table_new_full (g_direct_hash, 
237                                                 g_direct_equal,
238                                                 NULL, 
239                                                 (GDestroyNotify)g_list_free);
240
241   priv->cell_border.left   = 0;
242   priv->cell_border.right  = 0;
243   priv->cell_border.top    = 0;
244   priv->cell_border.bottom = 0;
245
246   priv->focus_cell         = NULL;
247   priv->edited_cell        = NULL;
248   priv->edit_widget        = NULL;
249
250   priv->remove_widget_id   = 0;
251 }
252
253 static void 
254 gtk_cell_area_class_init (GtkCellAreaClass *class)
255 {
256   GObjectClass *object_class = G_OBJECT_CLASS (class);
257   
258   /* GObjectClass */
259   object_class->dispose      = gtk_cell_area_dispose;
260   object_class->finalize     = gtk_cell_area_finalize;
261   object_class->get_property = gtk_cell_area_get_property;
262   object_class->set_property = gtk_cell_area_set_property;
263
264   /* general */
265   class->add     = NULL;
266   class->remove  = NULL;
267   class->forall  = NULL;
268   class->event   = gtk_cell_area_real_event;
269   class->render  = NULL;
270
271   /* geometry */
272   class->create_context                 = NULL;
273   class->get_request_mode               = NULL;
274   class->get_preferred_width            = NULL;
275   class->get_preferred_height           = NULL;
276   class->get_preferred_height_for_width = gtk_cell_area_real_get_preferred_height_for_width;
277   class->get_preferred_width_for_height = gtk_cell_area_real_get_preferred_width_for_height;
278
279   /* focus */
280   class->can_focus  = gtk_cell_area_real_can_focus;
281   class->focus      = NULL;
282   class->activate   = gtk_cell_area_real_activate;
283
284   /* Signals */
285
286   /**
287    * GtkCellArea::add-editable:
288    * @area: the #GtkCellArea where editing started
289    * @renderer: the #GtkCellRenderer that started the edited
290    * @editable: the #GtkCellEditable widget to add
291    * @cell_area: the #GtkWidget relative #GdkRectangle coordinates
292    *             where @editable should be added
293    * @path:      the #GtkTreePath string this edit was initiated for
294    *
295    * Indicates that editing has started on @renderer and that @editable
296    * should be added to the owning cell layouting widget at @cell_area.
297    */
298   cell_area_signals[SIGNAL_ADD_EDITABLE] =
299     g_signal_new (I_("add-editable"),
300                   G_OBJECT_CLASS_TYPE (object_class),
301                   G_SIGNAL_RUN_FIRST,
302                   0, /* No class closure here */
303                   NULL, NULL,
304                   _gtk_marshal_VOID__OBJECT_OBJECT_BOXED_STRING,
305                   G_TYPE_NONE, 4,
306                   GTK_TYPE_CELL_RENDERER,
307                   GTK_TYPE_CELL_EDITABLE,
308                   GDK_TYPE_RECTANGLE,
309                   G_TYPE_STRING);
310
311
312   /**
313    * GtkCellArea::remove-editable:
314    * @area: the #GtkCellArea where editing finished
315    * @renderer: the #GtkCellRenderer that finished editeding
316    * @editable: the #GtkCellEditable widget to remove
317    *
318    * Indicates that editing finished on @renderer and that @editable
319    * should be removed from the owning cell layouting widget.
320    */
321   cell_area_signals[SIGNAL_REMOVE_EDITABLE] =
322     g_signal_new (I_("remove-editable"),
323                   G_OBJECT_CLASS_TYPE (object_class),
324                   G_SIGNAL_RUN_FIRST,
325                   0, /* No class closure here */
326                   NULL, NULL,
327                   _gtk_marshal_VOID__OBJECT_OBJECT,
328                   G_TYPE_NONE, 2,
329                   GTK_TYPE_CELL_RENDERER,
330                   GTK_TYPE_CELL_EDITABLE);
331
332   /**
333    * GtkCellArea::focus-changed:
334    * @area: the #GtkCellArea where focus changed
335    * @renderer: the #GtkCellRenderer that has focus
336    * @path: the current #GtkTreePath string set for @area
337    *
338    * Indicates that focus changed on this @area. This signal
339    * is emitted either as a result of focus handling or event
340    * handling.
341    *
342    * It's possible that the signal is emitted even if the
343    * currently focused renderer did not change, this is
344    * because focus may change to the same renderer in the
345    * same cell area for a different row of data.
346    */
347   cell_area_signals[SIGNAL_FOCUS_CHANGED] =
348     g_signal_new (I_("focus-changed"),
349                   G_OBJECT_CLASS_TYPE (object_class),
350                   G_SIGNAL_RUN_FIRST,
351                   0, /* No class closure here */
352                   NULL, NULL,
353                   _gtk_marshal_VOID__OBJECT_STRING,
354                   G_TYPE_NONE, 2,
355                   GTK_TYPE_CELL_RENDERER,
356                   G_TYPE_STRING);
357
358   /* Properties */
359   g_object_class_install_property (object_class,
360                                    PROP_CELL_MARGIN_LEFT,
361                                    g_param_spec_int
362                                    ("cell-margin-left",
363                                     P_("Margin on Left"),
364                                     P_("Pixels of extra space on the left side of each cell"),
365                                     0,
366                                     G_MAXINT16,
367                                     0,
368                                     GTK_PARAM_READWRITE));
369
370   g_object_class_install_property (object_class,
371                                    PROP_CELL_MARGIN_RIGHT,
372                                    g_param_spec_int
373                                    ("cell-margin-right",
374                                     P_("Margin on Right"),
375                                     P_("Pixels of extra space on the right side of each cell"),
376                                     0,
377                                     G_MAXINT16,
378                                     0,
379                                     GTK_PARAM_READWRITE));
380   
381   g_object_class_install_property (object_class,
382                                    PROP_CELL_MARGIN_TOP,
383                                    g_param_spec_int 
384                                    ("cell-margin-top",
385                                     P_("Margin on Top"),
386                                     P_("Pixels of extra space on the top side of each cell"),
387                                     0,
388                                     G_MAXINT16,
389                                     0,
390                                     GTK_PARAM_READWRITE));
391
392   g_object_class_install_property (object_class,
393                                    PROP_CELL_MARGIN_BOTTOM,
394                                    g_param_spec_int
395                                    ("cell-margin-bottom",
396                                     P_("Margin on Bottom"),
397                                     P_("Pixels of extra space on the bottom side of each cell"),
398                                     0,
399                                     G_MAXINT16,
400                                     0,
401                                     GTK_PARAM_READWRITE));
402
403   g_object_class_install_property (object_class,
404                                    PROP_FOCUS_CELL,
405                                    g_param_spec_object
406                                    ("focus-cell",
407                                     P_("Focus Cell"),
408                                     P_("The cell which currently has focus"),
409                                     GTK_TYPE_CELL_RENDERER,
410                                     GTK_PARAM_READWRITE));
411
412   g_object_class_install_property (object_class,
413                                    PROP_EDITED_CELL,
414                                    g_param_spec_object
415                                    ("edited-cell",
416                                     P_("Edited Cell"),
417                                     P_("The cell which is currently being edited"),
418                                     GTK_TYPE_CELL_RENDERER,
419                                     G_PARAM_READABLE));
420
421   g_object_class_install_property (object_class,
422                                    PROP_EDIT_WIDGET,
423                                    g_param_spec_object
424                                    ("edit-widget",
425                                     P_("Edit Widget"),
426                                     P_("The widget currently editing the edited cell"),
427                                     GTK_TYPE_CELL_RENDERER,
428                                     G_PARAM_READABLE));
429
430   /* Pool for Cell Properties */
431   if (!cell_property_pool)
432     cell_property_pool = g_param_spec_pool_new (FALSE);
433
434   g_type_class_add_private (object_class, sizeof (GtkCellAreaPrivate));
435 }
436
437 /*************************************************************
438  *                    CellInfo Basics                        *
439  *************************************************************/
440 static CellInfo *
441 cell_info_new (GtkCellLayoutDataFunc  func,
442                gpointer               data,
443                GDestroyNotify         destroy)
444 {
445   CellInfo *info = g_slice_new (CellInfo);
446   
447   info->attributes = NULL;
448   info->func       = func;
449   info->data       = data;
450   info->destroy    = destroy;
451
452   return info;
453 }
454
455 static void
456 cell_info_free (CellInfo *info)
457 {
458   if (info->destroy)
459     info->destroy (info->data);
460
461   g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
462   g_slist_free (info->attributes);
463
464   g_slice_free (CellInfo, info);
465 }
466
467 static CellAttribute  *
468 cell_attribute_new  (GtkCellRenderer       *renderer,
469                      const gchar           *attribute,
470                      gint                   column)
471 {
472   GParamSpec *pspec;
473
474   /* Check if the attribute really exists and point to
475    * the property string installed on the cell renderer
476    * class (dont dup the string) 
477    */
478   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (renderer), attribute);
479
480   if (pspec)
481     {
482       CellAttribute *cell_attribute = g_slice_new (CellAttribute);
483
484       cell_attribute->attribute = pspec->name;
485       cell_attribute->column    = column;
486
487       return cell_attribute;
488     }
489
490   return NULL;
491 }
492
493 static void
494 cell_attribute_free (CellAttribute *attribute)
495 {
496   g_slice_free (CellAttribute, attribute);
497 }
498
499 /* GCompareFunc for g_slist_find_custom() */
500 static gint
501 cell_attribute_find (CellAttribute *cell_attribute,
502                      const gchar   *attribute)
503 {
504   return g_strcmp0 (cell_attribute->attribute, attribute);
505 }
506
507 /*************************************************************
508  *                      GObjectClass                         *
509  *************************************************************/
510 static void
511 gtk_cell_area_finalize (GObject *object)
512 {
513   GtkCellArea        *area   = GTK_CELL_AREA (object);
514   GtkCellAreaPrivate *priv   = area->priv;
515
516   /* All cell renderers should already be removed at this point,
517    * just kill our (empty) hash tables here. 
518    */
519   g_hash_table_destroy (priv->cell_info);
520   g_hash_table_destroy (priv->focus_siblings);
521
522   g_free (priv->current_path);
523
524   G_OBJECT_CLASS (gtk_cell_area_parent_class)->finalize (object);
525 }
526
527
528 static void
529 gtk_cell_area_dispose (GObject *object)
530 {
531   /* This removes every cell renderer that may be added to the GtkCellArea,
532    * subclasses should be breaking references to the GtkCellRenderers 
533    * at this point.
534    */
535   gtk_cell_layout_clear (GTK_CELL_LAYOUT (object));
536
537   /* Remove any ref to a focused/edited cell */
538   gtk_cell_area_set_focus_cell (GTK_CELL_AREA (object), NULL);
539   gtk_cell_area_set_edited_cell (GTK_CELL_AREA (object), NULL);
540   gtk_cell_area_set_edit_widget (GTK_CELL_AREA (object), NULL);
541
542   G_OBJECT_CLASS (gtk_cell_area_parent_class)->dispose (object);
543 }
544
545 static void
546 gtk_cell_area_set_property (GObject       *object,
547                             guint          prop_id,
548                             const GValue  *value,
549                             GParamSpec    *pspec)
550 {
551   GtkCellArea *area = GTK_CELL_AREA (object);
552
553   switch (prop_id)
554     {
555     case PROP_CELL_MARGIN_LEFT:
556       gtk_cell_area_set_cell_margin_left (area, g_value_get_int (value));
557       break;
558     case PROP_CELL_MARGIN_RIGHT:
559       gtk_cell_area_set_cell_margin_right (area, g_value_get_int (value));
560       break;
561     case PROP_CELL_MARGIN_TOP:
562       gtk_cell_area_set_cell_margin_top (area, g_value_get_int (value));
563       break;
564     case PROP_CELL_MARGIN_BOTTOM:
565       gtk_cell_area_set_cell_margin_bottom (area, g_value_get_int (value));
566       break;
567     case PROP_FOCUS_CELL:
568       gtk_cell_area_set_focus_cell (area, (GtkCellRenderer *)g_value_get_object (value));
569       break;
570     default:
571       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
572       break;
573     }
574 }
575
576 static void
577 gtk_cell_area_get_property (GObject     *object,
578                             guint        prop_id,
579                             GValue      *value,
580                             GParamSpec  *pspec)
581 {
582   GtkCellArea        *area = GTK_CELL_AREA (object);
583   GtkCellAreaPrivate *priv = area->priv;
584
585   switch (prop_id)
586     {
587     case PROP_CELL_MARGIN_LEFT:
588       g_value_set_int (value, priv->cell_border.left);
589       break;
590     case PROP_CELL_MARGIN_RIGHT:
591       g_value_set_int (value, priv->cell_border.right);
592       break;
593     case PROP_CELL_MARGIN_TOP:
594       g_value_set_int (value, priv->cell_border.top);
595       break;
596     case PROP_CELL_MARGIN_BOTTOM:
597       g_value_set_int (value, priv->cell_border.bottom);
598       break;
599     case PROP_FOCUS_CELL:
600       g_value_set_object (value, priv->focus_cell);
601       break;
602     case PROP_EDITED_CELL:
603       g_value_set_object (value, priv->edited_cell);
604       break;
605     case PROP_EDIT_WIDGET:
606       g_value_set_object (value, priv->edit_widget);
607       break;
608     default:
609       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
610       break;
611     }
612 }
613
614 /*************************************************************
615  *                    GtkCellAreaClass                       *
616  *************************************************************/
617 static gint
618 gtk_cell_area_real_event (GtkCellArea          *area,
619                           GtkCellAreaContext   *context,
620                           GtkWidget            *widget,
621                           GdkEvent             *event,
622                           const GdkRectangle   *cell_area,
623                           GtkCellRendererState  flags)
624 {
625   GtkCellAreaPrivate *priv = area->priv;
626
627   if (event->type == GDK_KEY_PRESS && (flags & GTK_CELL_RENDERER_FOCUSED) != 0)
628     {
629       GdkEventKey *key_event = (GdkEventKey *)event;
630
631       /* Cancel any edits in progress */
632       if (priv->edited_cell && (key_event->keyval == GDK_KEY_Escape))
633         {
634           gtk_cell_area_stop_editing (area, TRUE);
635           return TRUE;
636         }
637     }
638
639   return FALSE;
640 }
641
642 static void
643 gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea        *area,
644                                                    GtkCellAreaContext *context,
645                                                    GtkWidget          *widget,
646                                                    gint                width,
647                                                    gint               *minimum_height,
648                                                    gint               *natural_height)
649 {
650   /* If the area doesnt do height-for-width, fallback on base preferred height */
651   GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, context, widget, minimum_height, natural_height);
652 }
653
654 static void
655 gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea        *area,
656                                                    GtkCellAreaContext *context,
657                                                    GtkWidget          *widget,
658                                                    gint                height,
659                                                    gint               *minimum_width,
660                                                    gint               *natural_width)
661 {
662   /* If the area doesnt do width-for-height, fallback on base preferred width */
663   GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, context, widget, minimum_width, natural_width);
664 }
665
666 static void
667 get_can_focus (GtkCellRenderer *renderer,
668                gboolean        *can_focus)
669 {
670
671   if (gtk_cell_renderer_can_focus (renderer))
672     *can_focus = TRUE;
673 }
674
675 static gboolean
676 gtk_cell_area_real_can_focus (GtkCellArea *area)
677 {
678   gboolean can_focus = FALSE;
679
680   /* Checks if any renderer can focus for the currently applied
681    * attributes.
682    *
683    * Subclasses can override this in the case that they are also
684    * rendering widgets as well as renderers.
685    */
686   gtk_cell_area_forall (area, (GtkCellCallback)get_can_focus, &can_focus);
687
688   return can_focus;
689 }
690
691 static gboolean
692 gtk_cell_area_real_activate (GtkCellArea         *area,
693                              GtkCellAreaContext  *context,
694                              GtkWidget           *widget,
695                              const GdkRectangle  *cell_area,
696                              GtkCellRendererState flags)
697 {
698   GtkCellAreaPrivate *priv = area->priv;
699   GdkRectangle        background_area;
700
701   if (priv->focus_cell)
702     {
703       /* Get the allocation of the focused cell.
704        */
705       gtk_cell_area_get_cell_allocation (area, context, widget, priv->focus_cell,
706                                          cell_area, &background_area);
707       
708       /* Activate or Edit the currently focused cell 
709        *
710        * Currently just not sending an event, renderers afaics dont use
711        * the event argument anyway, worst case is we can synthesize one.
712        */
713       if (gtk_cell_area_activate_cell (area, widget, priv->focus_cell, NULL,
714                                        &background_area, flags))
715         return TRUE;
716     }
717
718   return FALSE;
719 }
720
721 /*************************************************************
722  *                   GtkCellLayoutIface                      *
723  *************************************************************/
724 static void
725 gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface)
726 {
727   iface->pack_start         = gtk_cell_area_pack_default;
728   iface->pack_end           = gtk_cell_area_pack_default;
729   iface->clear              = gtk_cell_area_clear;
730   iface->add_attribute      = gtk_cell_area_add_attribute;
731   iface->set_cell_data_func = gtk_cell_area_set_cell_data_func;
732   iface->clear_attributes   = gtk_cell_area_clear_attributes;
733   iface->reorder            = gtk_cell_area_reorder;
734   iface->get_cells          = gtk_cell_area_get_cells;
735 }
736
737 static void
738 gtk_cell_area_pack_default (GtkCellLayout         *cell_layout,
739                             GtkCellRenderer       *renderer,
740                             gboolean               expand)
741 {
742   gtk_cell_area_add (GTK_CELL_AREA (cell_layout), renderer);
743 }
744
745 static void
746 gtk_cell_area_clear (GtkCellLayout *cell_layout)
747 {
748   GtkCellArea *area = GTK_CELL_AREA (cell_layout);
749   GList *l, *cells  =
750     gtk_cell_layout_get_cells (cell_layout);
751
752   for (l = cells; l; l = l->next)
753     {
754       GtkCellRenderer *renderer = l->data;
755       gtk_cell_area_remove (area, renderer);
756     }
757
758   g_list_free (cells);
759 }
760
761 static void
762 gtk_cell_area_add_attribute (GtkCellLayout         *cell_layout,
763                              GtkCellRenderer       *renderer,
764                              const gchar           *attribute,
765                              gint                   column)
766 {
767   gtk_cell_area_attribute_connect (GTK_CELL_AREA (cell_layout),
768                                    renderer, attribute, column);
769 }
770
771 static void
772 gtk_cell_area_set_cell_data_func (GtkCellLayout         *cell_layout,
773                                   GtkCellRenderer       *renderer,
774                                   GtkCellLayoutDataFunc  func,
775                                   gpointer               func_data,
776                                   GDestroyNotify         destroy)
777 {
778   GtkCellArea        *area   = GTK_CELL_AREA (cell_layout);
779   GtkCellAreaPrivate *priv   = area->priv;
780   CellInfo           *info;
781
782   info = g_hash_table_lookup (priv->cell_info, renderer);
783
784   if (info)
785     {
786       if (info->destroy && info->data)
787         info->destroy (info->data);
788
789       if (func)
790         {
791           info->func    = func;
792           info->data    = func_data;
793           info->destroy = destroy;
794         }
795       else
796         {
797           info->func    = NULL;
798           info->data    = NULL;
799           info->destroy = NULL;
800         }
801     }
802   else
803     {
804       info = cell_info_new (func, func_data, destroy);
805
806       g_hash_table_insert (priv->cell_info, renderer, info);
807     }
808 }
809
810 static void
811 gtk_cell_area_clear_attributes (GtkCellLayout         *cell_layout,
812                                 GtkCellRenderer       *renderer)
813 {
814   GtkCellArea        *area = GTK_CELL_AREA (cell_layout);
815   GtkCellAreaPrivate *priv = area->priv;
816   CellInfo           *info;
817
818   info = g_hash_table_lookup (priv->cell_info, renderer);
819
820   if (info)
821     {
822       g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
823       g_slist_free (info->attributes);
824
825       info->attributes = NULL;
826     }
827 }
828
829 static void 
830 gtk_cell_area_reorder (GtkCellLayout   *cell_layout,
831                        GtkCellRenderer *cell,
832                        gint             position)
833 {
834   g_warning ("GtkCellLayout::reorder not implemented for `%s'", 
835              g_type_name (G_TYPE_FROM_INSTANCE (cell_layout)));
836 }
837
838 static void
839 accum_cells (GtkCellRenderer *renderer,
840              GList          **accum)
841 {
842   *accum = g_list_prepend (*accum, renderer);
843 }
844
845 static GList *
846 gtk_cell_area_get_cells (GtkCellLayout *cell_layout)
847 {
848   GList *cells = NULL;
849
850   gtk_cell_area_forall (GTK_CELL_AREA (cell_layout), 
851                         (GtkCellCallback)accum_cells,
852                         &cells);
853
854   return g_list_reverse (cells);
855 }
856
857
858 /*************************************************************
859  *                            API                            *
860  *************************************************************/
861
862 /**
863  * gtk_cell_area_add:
864  * @area: a #GtkCellArea
865  * @renderer: the #GtkCellRenderer to add to @area
866  *
867  * Adds @renderer to @area with the default child cell properties.
868  */
869 void
870 gtk_cell_area_add (GtkCellArea        *area,
871                    GtkCellRenderer    *renderer)
872 {
873   GtkCellAreaClass *class;
874
875   g_return_if_fail (GTK_IS_CELL_AREA (area));
876   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
877
878   class = GTK_CELL_AREA_GET_CLASS (area);
879
880   if (class->add)
881     class->add (area, renderer);
882   else
883     g_warning ("GtkCellAreaClass::add not implemented for `%s'", 
884                g_type_name (G_TYPE_FROM_INSTANCE (area)));
885 }
886
887 /**
888  * gtk_cell_area_remove:
889  * @area: a #GtkCellArea
890  * @renderer: the #GtkCellRenderer to add to @area
891  *
892  * Removes @renderer from @area.
893  */
894 void
895 gtk_cell_area_remove (GtkCellArea        *area,
896                       GtkCellRenderer    *renderer)
897 {
898   GtkCellAreaClass   *class;
899   GtkCellAreaPrivate *priv;
900   GList              *renderers, *l;
901
902   g_return_if_fail (GTK_IS_CELL_AREA (area));
903   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
904
905   class = GTK_CELL_AREA_GET_CLASS (area);
906   priv  = area->priv;
907
908   /* Remove any custom attributes and custom cell data func here first */
909   g_hash_table_remove (priv->cell_info, renderer);
910
911   /* Remove focus siblings of this renderer */
912   g_hash_table_remove (priv->focus_siblings, renderer);
913
914   /* Remove this renderer from any focus renderer's sibling list */ 
915   renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (area));
916
917   for (l = renderers; l; l = l->next)
918     {
919       GtkCellRenderer *focus_renderer = l->data;
920
921       if (gtk_cell_area_is_focus_sibling (area, focus_renderer, renderer))
922         {
923           gtk_cell_area_remove_focus_sibling (area, focus_renderer, renderer);
924           break;
925         }
926     }
927
928   g_list_free (renderers);
929
930   if (class->remove)
931     class->remove (area, renderer);
932   else
933     g_warning ("GtkCellAreaClass::remove not implemented for `%s'", 
934                g_type_name (G_TYPE_FROM_INSTANCE (area)));
935 }
936
937 static void
938 get_has_renderer (GtkCellRenderer  *renderer,
939                   HasRendererCheck *check)
940 {
941   if (renderer == check->renderer)
942     check->has_renderer = TRUE;
943 }
944
945 /**
946  * gtk_cell_area_has_renderer:
947  * @area: a #GtkCellArea
948  * @renderer: the #GtkCellRenderer to check
949  *
950  * Checks if @area contains @renderer.
951  *
952  * Returns: %TRUE if @renderer is in the @area.
953  */
954 gboolean
955 gtk_cell_area_has_renderer (GtkCellArea     *area,
956                             GtkCellRenderer *renderer)
957 {
958   HasRendererCheck check = { renderer, FALSE };
959
960   g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
961   g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
962
963   gtk_cell_area_forall (area, (GtkCellCallback)get_has_renderer, &check);
964
965   return check.has_renderer;
966 }
967
968 /**
969  * gtk_cell_area_forall
970  * @area: a #GtkCellArea
971  * @callback: the #GtkCellCallback to call
972  * @callback_data: user provided data pointer
973  *
974  * Calls @callback for every #GtkCellRenderer in @area.
975  */
976 void
977 gtk_cell_area_forall (GtkCellArea        *area,
978                       GtkCellCallback     callback,
979                       gpointer            callback_data)
980 {
981   GtkCellAreaClass *class;
982
983   g_return_if_fail (GTK_IS_CELL_AREA (area));
984   g_return_if_fail (callback != NULL);
985
986   class = GTK_CELL_AREA_GET_CLASS (area);
987
988   if (class->forall)
989     class->forall (area, callback, callback_data);
990   else
991     g_warning ("GtkCellAreaClass::forall not implemented for `%s'", 
992                g_type_name (G_TYPE_FROM_INSTANCE (area)));
993 }
994
995 /**
996  * gtk_cell_area_get_cell_allocation:
997  * @area: a #GtkCellArea
998  * @context: the #GtkCellAreaContext used to hold sizes for @area.
999  * @widget: the #GtkWidget that @area is rendering on
1000  * @renderer: the #GtkCellRenderer to get the allocation for
1001  * @cell_area: the whole allocated area for @area in @widget
1002  *             for this row
1003  * @allocation: where to store the allocation for @renderer
1004  *
1005  * Derives the allocation of @renderer inside @area if @area
1006  * were to be renderered in @cell_area.
1007  */
1008 void
1009 gtk_cell_area_get_cell_allocation (GtkCellArea          *area,
1010                                    GtkCellAreaContext   *context,       
1011                                    GtkWidget            *widget,
1012                                    GtkCellRenderer      *renderer,
1013                                    const GdkRectangle   *cell_area,
1014                                    GdkRectangle         *allocation)
1015 {
1016   GtkCellAreaClass *class;
1017
1018   g_return_if_fail (GTK_IS_CELL_AREA (area));
1019   g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
1020   g_return_if_fail (GTK_IS_WIDGET (widget));
1021   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1022   g_return_if_fail (cell_area != NULL);
1023   g_return_if_fail (allocation != NULL);
1024
1025   class = GTK_CELL_AREA_GET_CLASS (area);
1026
1027   if (class->get_cell_allocation)
1028     class->get_cell_allocation (area, context, widget, renderer, cell_area, allocation);
1029   else
1030     g_warning ("GtkCellAreaClass::get_cell_allocation not implemented for `%s'", 
1031                g_type_name (G_TYPE_FROM_INSTANCE (area)));
1032 }
1033
1034 /**
1035  * gtk_cell_area_event:
1036  * @area: a #GtkCellArea
1037  * @context: the #GtkCellAreaContext for this row of data.
1038  * @widget: the #GtkWidget that @area is rendering to
1039  * @event: the #GdkEvent to handle
1040  * @cell_area: the @widget relative coordinates for @area
1041  * @flags: the #GtkCellRendererState for @area in this row.
1042  *
1043  * Delegates event handling to a #GtkCellArea.
1044  *
1045  * Returns: %TRUE if the event was handled by @area.
1046  */
1047 gint
1048 gtk_cell_area_event (GtkCellArea          *area,
1049                      GtkCellAreaContext   *context,
1050                      GtkWidget            *widget,
1051                      GdkEvent             *event,
1052                      const GdkRectangle   *cell_area,
1053                      GtkCellRendererState  flags)
1054 {
1055   GtkCellAreaClass *class;
1056
1057   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1058   g_return_val_if_fail (GTK_IS_CELL_AREA_CONTEXT (context), 0);
1059   g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
1060   g_return_val_if_fail (event != NULL, 0);
1061   g_return_val_if_fail (cell_area != NULL, 0);
1062
1063   class = GTK_CELL_AREA_GET_CLASS (area);
1064
1065   if (class->event)
1066     return class->event (area, context, widget, event, cell_area, flags);
1067
1068   g_warning ("GtkCellAreaClass::event not implemented for `%s'", 
1069              g_type_name (G_TYPE_FROM_INSTANCE (area)));
1070   return 0;
1071 }
1072
1073 /**
1074  * gtk_cell_area_render:
1075  * @area: a #GtkCellArea
1076  * @context: the #GtkCellAreaContext for this row of data.
1077  * @widget: the #GtkWidget that @area is rendering to
1078  * @cr: the #cairo_t to render with
1079  * @background_area: the @widget relative coordinates for @area's background
1080  * @cell_area: the @widget relative coordinates for @area
1081  * @flags: the #GtkCellRendererState for @area in this row.
1082  * @paint_focus: whether @area should paint focus on focused cells for focused rows or not.
1083  *
1084  * Renders @area's cells according to @area's layout onto @widget at
1085  * the given coordinates.
1086  */
1087 void
1088 gtk_cell_area_render (GtkCellArea          *area,
1089                       GtkCellAreaContext   *context,
1090                       GtkWidget            *widget,
1091                       cairo_t              *cr,
1092                       const GdkRectangle   *background_area,
1093                       const GdkRectangle   *cell_area,
1094                       GtkCellRendererState  flags,
1095                       gboolean              paint_focus)
1096 {
1097   GtkCellAreaClass *class;
1098
1099   g_return_if_fail (GTK_IS_CELL_AREA (area));
1100   g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
1101   g_return_if_fail (GTK_IS_WIDGET (widget));
1102   g_return_if_fail (cr != NULL);
1103   g_return_if_fail (background_area != NULL);
1104   g_return_if_fail (cell_area != NULL);
1105
1106   class = GTK_CELL_AREA_GET_CLASS (area);
1107
1108   if (class->render)
1109     class->render (area, context, widget, cr, background_area, cell_area, flags, paint_focus);
1110   else
1111     g_warning ("GtkCellAreaClass::render not implemented for `%s'", 
1112                g_type_name (G_TYPE_FROM_INSTANCE (area)));
1113 }
1114
1115 /**
1116  * gtk_cell_area_set_style_detail:
1117  * @area: a #GtkCellArea
1118  * @detail: the #GtkStyle detail string to set
1119  *
1120  * Sets the detail string used in any gtk_paint_*() functions
1121  * used by @area.
1122  */
1123 void
1124 gtk_cell_area_set_style_detail (GtkCellArea *area,
1125                                 const gchar *detail)
1126 {
1127   GtkCellAreaPrivate *priv;
1128
1129   g_return_if_fail (GTK_IS_CELL_AREA (area));
1130
1131   priv = area->priv;
1132
1133   if (g_strcmp0 (priv->style_detail, detail) != 0)
1134     {
1135       g_free (priv->style_detail);
1136       priv->style_detail = g_strdup (detail);
1137     }
1138 }
1139
1140 /**
1141  * gtk_cell_area_get_style_detail:
1142  * @area: a #GtkCellArea
1143  *
1144  * Gets the detail string used in any gtk_paint_*() functions
1145  * used by @area.
1146  *
1147  * Returns: the detail string.
1148  */
1149 G_CONST_RETURN gchar *
1150 gtk_cell_area_get_style_detail (GtkCellArea *area)
1151 {
1152   GtkCellAreaPrivate *priv;
1153
1154   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1155
1156   priv = area->priv;
1157
1158   return priv->style_detail;
1159 }
1160
1161 /*************************************************************
1162  *                      API: Geometry                        *
1163  *************************************************************/
1164 /**
1165  * gtk_cell_area_create_context:
1166  * @area: a #GtkCellArea
1167  *
1168  * Creates a #GtkCellAreaContext to be used with @area for
1169  * all purposes. #GtkCellAreaContext stores geometry information
1170  * for rows for which it was operated on, it is important to use
1171  * the same context for the same row of data at all times (i.e.
1172  * one should render and handle events with the same #GtkCellAreaContext
1173  * which was used to request the size of those rows of data).
1174  *
1175  * Returns: a newly created #GtkCellAreaContext which can be used with @area.
1176  */
1177 GtkCellAreaContext *
1178 gtk_cell_area_create_context (GtkCellArea *area)
1179 {
1180   GtkCellAreaClass *class;
1181
1182   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1183
1184   class = GTK_CELL_AREA_GET_CLASS (area);
1185
1186   if (class->create_context)
1187     return class->create_context (area);
1188
1189   g_warning ("GtkCellAreaClass::create_context not implemented for `%s'", 
1190              g_type_name (G_TYPE_FROM_INSTANCE (area)));
1191   
1192   return NULL;
1193 }
1194
1195
1196 /**
1197  * gtk_cell_area_get_request_mode:
1198  * @area: a #GtkCellArea
1199  *
1200  * Gets whether the area prefers a height-for-width layout
1201  * or a width-for-height layout.
1202  *
1203  * Returns: The #GtkSizeRequestMode preferred by @area.
1204  *
1205  * Since: 3.0
1206  */
1207 GtkSizeRequestMode 
1208 gtk_cell_area_get_request_mode (GtkCellArea *area)
1209 {
1210   GtkCellAreaClass *class;
1211
1212   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 
1213                         GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH);
1214
1215   class = GTK_CELL_AREA_GET_CLASS (area);
1216
1217   if (class->get_request_mode)
1218     return class->get_request_mode (area);
1219
1220   g_warning ("GtkCellAreaClass::get_request_mode not implemented for `%s'", 
1221              g_type_name (G_TYPE_FROM_INSTANCE (area)));
1222   
1223   return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
1224 }
1225
1226 /**
1227  * gtk_cell_area_get_preferred_width:
1228  * @area: a #GtkCellArea
1229  * @context: the #GtkCellAreaContext to perform this request with
1230  * @widget: the #GtkWidget where @area will be rendering
1231  * @minimum_width: (out) (allow-none): location to store the minimum width, or %NULL
1232  * @natural_width: (out) (allow-none): location to store the natural width, or %NULL
1233  *
1234  * Retrieves a cell area's initial minimum and natural width.
1235  *
1236  * @area will store some geometrical information in @context along the way,
1237  * when requesting sizes over an arbitrary number of rows, its not important
1238  * to check the @minimum_width and @natural_width of this call but rather to
1239  * call gtk_cell_area_context_sum_preferred_width() and then consult 
1240  * gtk_cell_area_context_get_preferred_width().
1241  *
1242  *
1243  * Since: 3.0
1244  */
1245 void
1246 gtk_cell_area_get_preferred_width (GtkCellArea        *area,
1247                                    GtkCellAreaContext *context,
1248                                    GtkWidget          *widget,
1249                                    gint               *minimum_width,
1250                                    gint               *natural_width)
1251 {
1252   GtkCellAreaClass *class;
1253
1254   g_return_if_fail (GTK_IS_CELL_AREA (area));
1255   g_return_if_fail (GTK_IS_WIDGET (widget));
1256
1257   class = GTK_CELL_AREA_GET_CLASS (area);
1258
1259   if (class->get_preferred_width)
1260     class->get_preferred_width (area, context, widget, minimum_width, natural_width);
1261   else
1262     g_warning ("GtkCellAreaClass::get_preferred_width not implemented for `%s'", 
1263                g_type_name (G_TYPE_FROM_INSTANCE (area)));
1264 }
1265
1266 /**
1267  * gtk_cell_area_get_preferred_height_for_width:
1268  * @area: a #GtkCellArea
1269  * @context: the #GtkCellAreaContext which has already been requested for widths.
1270  * @widget: the #GtkWidget where @area will be rendering
1271  * @width: the width for which to check the height of this area
1272  * @minimum_height: (out) (allow-none): location to store the minimum height, or %NULL
1273  * @natural_height: (out) (allow-none): location to store the natural height, or %NULL
1274  *
1275  * Retrieves a cell area's minimum and natural height if it would be given
1276  * the specified @width.
1277  *
1278  * @area stores some geometrical information in @context along the way
1279  * while calling gtk_cell_area_get_preferred_width(), it's important to
1280  * perform a series of gtk_cell_area_get_preferred_width() requests with
1281  * @context first and then call gtk_cell_area_get_preferred_height_for_width()
1282  * on each cell area individually to get the height for width of each
1283  * fully requested row.
1284  *
1285  * If at some point, the width of a single row changes, it should be
1286  * requested with gtk_cell_area_get_preferred_width() again and then
1287  * the full with of the requested rows checked again after calling
1288  * gtk_cell_area_context_sum_preferred_width(), and then the height
1289  * for width of each row needs to be requested again.
1290  *
1291  * Since: 3.0
1292  */
1293 void
1294 gtk_cell_area_get_preferred_height_for_width (GtkCellArea        *area,
1295                                               GtkCellAreaContext *context,
1296                                               GtkWidget          *widget,
1297                                               gint                width,
1298                                               gint               *minimum_height,
1299                                               gint               *natural_height)
1300 {
1301   GtkCellAreaClass *class;
1302
1303   g_return_if_fail (GTK_IS_CELL_AREA (area));
1304   g_return_if_fail (GTK_IS_WIDGET (widget));
1305
1306   class = GTK_CELL_AREA_GET_CLASS (area);
1307   class->get_preferred_height_for_width (area, context, widget, width, minimum_height, natural_height);
1308 }
1309
1310
1311 /**
1312  * gtk_cell_area_get_preferred_height:
1313  * @area: a #GtkCellArea
1314  * @context: the #GtkCellAreaContext to perform this request with
1315  * @widget: the #GtkWidget where @area will be rendering
1316  * @minimum_height: (out) (allow-none): location to store the minimum height, or %NULL
1317  * @natural_height: (out) (allow-none): location to store the natural height, or %NULL
1318  *
1319  * Retrieves a cell area's initial minimum and natural height.
1320  *
1321  * @area will store some geometrical information in @context along the way,
1322  * when requesting sizes over an arbitrary number of rows, its not important
1323  * to check the @minimum_height and @natural_height of this call but rather to
1324  * call gtk_cell_area_context_sum_preferred_height() and then consult 
1325  * gtk_cell_area_context_get_preferred_height().
1326  *
1327  * Since: 3.0
1328  */
1329 void
1330 gtk_cell_area_get_preferred_height (GtkCellArea        *area,
1331                                     GtkCellAreaContext *context,
1332                                     GtkWidget          *widget,
1333                                     gint               *minimum_height,
1334                                     gint               *natural_height)
1335 {
1336   GtkCellAreaClass *class;
1337
1338   g_return_if_fail (GTK_IS_CELL_AREA (area));
1339   g_return_if_fail (GTK_IS_WIDGET (widget));
1340
1341   class = GTK_CELL_AREA_GET_CLASS (area);
1342
1343   if (class->get_preferred_height)
1344     class->get_preferred_height (area, context, widget, minimum_height, natural_height);
1345   else
1346     g_warning ("GtkCellAreaClass::get_preferred_height not implemented for `%s'", 
1347                g_type_name (G_TYPE_FROM_INSTANCE (area)));
1348 }
1349
1350 /**
1351  * gtk_cell_area_get_preferred_width_for_height:
1352  * @area: a #GtkCellArea
1353  * @context: the #GtkCellAreaContext which has already been requested for widths.
1354  * @widget: the #GtkWidget where @area will be rendering
1355  * @height: the height for which to check the width of this area
1356  * @minimum_width: (out) (allow-none): location to store the minimum width, or %NULL
1357  * @natural_width: (out) (allow-none): location to store the natural width, or %NULL
1358  *
1359  * Retrieves a cell area's minimum and natural width if it would be given
1360  * the specified @height.
1361  *
1362  * @area stores some geometrical information in @context along the way
1363  * while calling gtk_cell_area_get_preferred_height(), it's important to
1364  * perform a series of gtk_cell_area_get_preferred_height() requests with
1365  * @context first and then call gtk_cell_area_get_preferred_width_for_height()
1366  * on each cell area individually to get the height for width of each
1367  * fully requested row.
1368  *
1369  * If at some point, the width of a single row changes, it should be
1370  * requested with gtk_cell_area_get_preferred_width() again and then
1371  * the full with of the requested rows checked again after calling
1372  * gtk_cell_area_context_sum_preferred_width(), and then the height
1373  * for width of each row needs to be requested again.
1374  *
1375  * Since: 3.0
1376  */
1377 void
1378 gtk_cell_area_get_preferred_width_for_height (GtkCellArea        *area,
1379                                               GtkCellAreaContext *context,
1380                                               GtkWidget          *widget,
1381                                               gint                height,
1382                                               gint               *minimum_width,
1383                                               gint               *natural_width)
1384 {
1385   GtkCellAreaClass *class;
1386
1387   g_return_if_fail (GTK_IS_CELL_AREA (area));
1388   g_return_if_fail (GTK_IS_WIDGET (widget));
1389
1390   class = GTK_CELL_AREA_GET_CLASS (area);
1391   class->get_preferred_width_for_height (area, context, widget, height, minimum_width, natural_width);
1392 }
1393
1394 /*************************************************************
1395  *                      API: Attributes                      *
1396  *************************************************************/
1397
1398 /**
1399  * gtk_cell_area_attribute_connect:
1400  * @area: a #GtkCellArea
1401  * @renderer: the #GtkCellRenderer to connect an attribute for
1402  * @attribute: the attribute name
1403  * @column: the #GtkTreeModel column to fetch attribute values from
1404  *
1405  * Connects an @attribute to apply values from @column for the
1406  * #GtkTreeModel in use.
1407  */
1408 void
1409 gtk_cell_area_attribute_connect (GtkCellArea        *area,
1410                                  GtkCellRenderer    *renderer,
1411                                  const gchar        *attribute,
1412                                  gint                column)
1413
1414   GtkCellAreaPrivate *priv;
1415   CellInfo           *info;
1416   CellAttribute      *cell_attribute;
1417
1418   g_return_if_fail (GTK_IS_CELL_AREA (area));
1419   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1420   g_return_if_fail (attribute != NULL);
1421   g_return_if_fail (gtk_cell_area_has_renderer (area, renderer));
1422
1423   priv = area->priv;
1424   info = g_hash_table_lookup (priv->cell_info, renderer);
1425
1426   if (!info)
1427     {
1428       info = cell_info_new (NULL, NULL, NULL);
1429
1430       g_hash_table_insert (priv->cell_info, renderer, info);
1431     }
1432   else
1433     {
1434       GSList *node;
1435
1436       /* Check we are not adding the same attribute twice */
1437       if ((node = g_slist_find_custom (info->attributes, attribute,
1438                                        (GCompareFunc)cell_attribute_find)) != NULL)
1439         {
1440           cell_attribute = node->data;
1441
1442           g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
1443                      "since `%s' is already attributed to column %d", 
1444                      attribute,
1445                      g_type_name (G_TYPE_FROM_INSTANCE (area)),
1446                      attribute, cell_attribute->column);
1447           return;
1448         }
1449     }
1450
1451   cell_attribute = cell_attribute_new (renderer, attribute, column);
1452
1453   if (!cell_attribute)
1454     {
1455       g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
1456                  "since attribute does not exist", 
1457                  attribute,
1458                  g_type_name (G_TYPE_FROM_INSTANCE (area)));
1459       return;
1460     }
1461
1462   info->attributes = g_slist_prepend (info->attributes, cell_attribute);
1463 }
1464
1465 /**
1466  * gtk_cell_area_attribute_disconnect:
1467  * @area: a #GtkCellArea
1468  * @renderer: the #GtkCellRenderer to disconnect an attribute for
1469  * @attribute: the attribute name
1470  *
1471  * Disconnects @attribute for the @renderer in @area so that
1472  * attribute will no longer be updated with values from the
1473  * model.
1474  */
1475 void 
1476 gtk_cell_area_attribute_disconnect (GtkCellArea        *area,
1477                                     GtkCellRenderer    *renderer,
1478                                     const gchar        *attribute)
1479 {
1480   GtkCellAreaPrivate *priv;
1481   CellInfo           *info;
1482   CellAttribute      *cell_attribute;
1483   GSList             *node;
1484
1485   g_return_if_fail (GTK_IS_CELL_AREA (area));
1486   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1487   g_return_if_fail (attribute != NULL);
1488   g_return_if_fail (gtk_cell_area_has_renderer (area, renderer));
1489
1490   priv = area->priv;
1491   info = g_hash_table_lookup (priv->cell_info, renderer);
1492
1493   if (info)
1494     {
1495       node = g_slist_find_custom (info->attributes, attribute,
1496                                   (GCompareFunc)cell_attribute_find);
1497       if (node)
1498         {
1499           cell_attribute = node->data;
1500
1501           cell_attribute_free (cell_attribute);
1502
1503           info->attributes = g_slist_delete_link (info->attributes, node);
1504         }
1505     }
1506 }
1507
1508 static void
1509 apply_cell_attributes (GtkCellRenderer *renderer,
1510                        CellInfo        *info,
1511                        AttributeData   *data)
1512 {
1513   CellAttribute *attribute;
1514   GSList        *list;
1515   GValue         value = { 0, };
1516   gboolean       is_expander;
1517   gboolean       is_expanded;
1518
1519   g_object_freeze_notify (G_OBJECT (renderer));
1520
1521   /* Whether a row expands or is presently expanded can only be 
1522    * provided by the view (as these states can vary across views
1523    * accessing the same model).
1524    */
1525   g_object_get (renderer, "is-expander", &is_expander, NULL);
1526   if (is_expander != data->is_expander)
1527     g_object_set (renderer, "is-expander", data->is_expander, NULL);
1528   
1529   g_object_get (renderer, "is-expanded", &is_expanded, NULL);
1530   if (is_expanded != data->is_expanded)
1531     g_object_set (renderer, "is-expanded", data->is_expanded, NULL);
1532
1533   /* Apply the attributes directly to the renderer */
1534   for (list = info->attributes; list; list = list->next)
1535     {
1536       attribute = list->data;
1537
1538       gtk_tree_model_get_value (data->model, data->iter, attribute->column, &value);
1539       g_object_set_property (G_OBJECT (renderer), attribute->attribute, &value);
1540       g_value_unset (&value);
1541     }
1542
1543   /* Call any GtkCellLayoutDataFunc that may have been set by the user
1544    */
1545   if (info->func)
1546     info->func (GTK_CELL_LAYOUT (data->area), renderer,
1547                 data->model, data->iter, info->data);
1548
1549   g_object_thaw_notify (G_OBJECT (renderer));
1550 }
1551
1552 /**
1553  * gtk_cell_area_apply_attributes
1554  * @area: a #GtkCellArea
1555  * @tree_model: a #GtkTreeModel to pull values from
1556  * @iter: the #GtkTreeIter in @tree_model to apply values for
1557  * @is_expander: whether @iter has children
1558  * @is_expanded: whether @iter is expanded in the view and
1559  *               children are visible
1560  *
1561  * Applies any connected attributes to the renderers in 
1562  * @area by pulling the values from @tree_model.
1563  */
1564 void
1565 gtk_cell_area_apply_attributes (GtkCellArea  *area,
1566                                 GtkTreeModel *tree_model,
1567                                 GtkTreeIter  *iter,
1568                                 gboolean      is_expander,
1569                                 gboolean      is_expanded)
1570 {
1571   GtkCellAreaPrivate *priv;
1572   AttributeData       data;
1573   GtkTreePath        *path;
1574
1575   g_return_if_fail (GTK_IS_CELL_AREA (area));
1576   g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
1577   g_return_if_fail (iter != NULL);
1578
1579   priv = area->priv;
1580
1581   /* Feed in data needed to apply to every renderer */
1582   data.area        = area;
1583   data.model       = tree_model;
1584   data.iter        = iter;
1585   data.is_expander = is_expander;
1586   data.is_expanded = is_expanded;
1587
1588   /* Go over any cells that have attributes or custom GtkCellLayoutDataFuncs and
1589    * apply the data from the treemodel */
1590   g_hash_table_foreach (priv->cell_info, (GHFunc)apply_cell_attributes, &data);
1591
1592   /* Update the currently applied path */
1593   g_free (priv->current_path);
1594   path               = gtk_tree_model_get_path (tree_model, iter);
1595   priv->current_path = gtk_tree_path_to_string (path);
1596   gtk_tree_path_free (path);
1597 }
1598
1599 /**
1600  * gtk_cell_area_get_current_path_string:
1601  * @area: a #GtkCellArea
1602  *
1603  * Gets the current #GtkTreePath string for the currently
1604  * applied #GtkTreeIter, this is implicitly updated when
1605  * gtk_cell_area_apply_attributes() is called and can be
1606  * used to interact with renderers from #GtkCellArea
1607  * subclasses.
1608  */
1609 const gchar *
1610 gtk_cell_area_get_current_path_string (GtkCellArea *area)
1611 {
1612   GtkCellAreaPrivate *priv;
1613
1614   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1615
1616   priv = area->priv;
1617
1618   return priv->current_path;
1619 }
1620
1621
1622 /*************************************************************
1623  *                    API: Cell Properties                   *
1624  *************************************************************/
1625 /**
1626  * gtk_cell_area_class_install_cell_property:
1627  * @aclass: a #GtkCellAreaClass
1628  * @property_id: the id for the property
1629  * @pspec: the #GParamSpec for the property
1630  *
1631  * Installs a cell property on a cell area class.
1632  */
1633 void
1634 gtk_cell_area_class_install_cell_property (GtkCellAreaClass   *aclass,
1635                                            guint               property_id,
1636                                            GParamSpec         *pspec)
1637 {
1638   g_return_if_fail (GTK_IS_CELL_AREA_CLASS (aclass));
1639   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1640   if (pspec->flags & G_PARAM_WRITABLE)
1641     g_return_if_fail (aclass->set_cell_property != NULL);
1642   if (pspec->flags & G_PARAM_READABLE)
1643     g_return_if_fail (aclass->get_cell_property != NULL);
1644   g_return_if_fail (property_id > 0);
1645   g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0);  /* paranoid */
1646   g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0);
1647
1648   if (g_param_spec_pool_lookup (cell_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (aclass), TRUE))
1649     {
1650       g_warning (G_STRLOC ": class `%s' already contains a cell property named `%s'",
1651                  G_OBJECT_CLASS_NAME (aclass), pspec->name);
1652       return;
1653     }
1654   g_param_spec_ref (pspec);
1655   g_param_spec_sink (pspec);
1656   PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
1657   g_param_spec_pool_insert (cell_property_pool, pspec, G_OBJECT_CLASS_TYPE (aclass));
1658 }
1659
1660 /**
1661  * gtk_cell_area_class_find_cell_property:
1662  * @aclass: a #GtkCellAreaClass
1663  * @property_name: the name of the child property to find
1664  * @returns: (allow-none): the #GParamSpec of the child property or %NULL if @aclass has no
1665  *   child property with that name.
1666  *
1667  * Finds a cell property of a cell area class by name.
1668  */
1669 GParamSpec*
1670 gtk_cell_area_class_find_cell_property (GtkCellAreaClass   *aclass,
1671                                         const gchar        *property_name)
1672 {
1673   g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
1674   g_return_val_if_fail (property_name != NULL, NULL);
1675
1676   return g_param_spec_pool_lookup (cell_property_pool,
1677                                    property_name,
1678                                    G_OBJECT_CLASS_TYPE (aclass),
1679                                    TRUE);
1680 }
1681
1682 /**
1683  * gtk_cell_area_class_list_cell_properties:
1684  * @aclass: a #GtkCellAreaClass
1685  * @n_properties: location to return the number of cell properties found
1686  * @returns: a newly allocated %NULL-terminated array of #GParamSpec*.
1687  *           The array must be freed with g_free().
1688  *
1689  * Returns all cell properties of a cell area class.
1690  */
1691 GParamSpec**
1692 gtk_cell_area_class_list_cell_properties (GtkCellAreaClass  *aclass,
1693                                           guint             *n_properties)
1694 {
1695   GParamSpec **pspecs;
1696   guint n;
1697
1698   g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
1699
1700   pspecs = g_param_spec_pool_list (cell_property_pool,
1701                                    G_OBJECT_CLASS_TYPE (aclass),
1702                                    &n);
1703   if (n_properties)
1704     *n_properties = n;
1705
1706   return pspecs;
1707 }
1708
1709 /**
1710  * gtk_cell_area_add_with_properties:
1711  * @area: a #GtkCellArea
1712  * @renderer: a #GtkCellRenderer to be placed inside @area
1713  * @first_prop_name: the name of the first cell property to set
1714  * @Varargs: a %NULL-terminated list of property names and values, starting
1715  *           with @first_prop_name
1716  *
1717  * Adds @renderer to @area, setting cell properties at the same time.
1718  * See gtk_cell_area_add() and gtk_cell_area_child_set() for more details.
1719  **/
1720 void
1721 gtk_cell_area_add_with_properties (GtkCellArea        *area,
1722                                    GtkCellRenderer    *renderer,
1723                                    const gchar        *first_prop_name,
1724                                    ...)
1725 {
1726   GtkCellAreaClass *class;
1727
1728   g_return_if_fail (GTK_IS_CELL_AREA (area));
1729   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1730
1731   class = GTK_CELL_AREA_GET_CLASS (area);
1732
1733   if (class->add)
1734     {
1735       va_list var_args;
1736
1737       class->add (area, renderer);
1738
1739       va_start (var_args, first_prop_name);
1740       gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1741       va_end (var_args);
1742     }
1743   else
1744     g_warning ("GtkCellAreaClass::add not implemented for `%s'", 
1745                g_type_name (G_TYPE_FROM_INSTANCE (area)));
1746 }
1747
1748 /**
1749  * gtk_cell_area_cell_set:
1750  * @area: a #GtkCellArea
1751  * @renderer: a #GtkCellRenderer which is a cell inside @area
1752  * @first_prop_name: the name of the first cell property to set
1753  * @Varargs: a %NULL-terminated list of property names and values, starting
1754  *           with @first_prop_name
1755  *
1756  * Sets one or more cell properties for @cell in @area.
1757  **/
1758 void
1759 gtk_cell_area_cell_set (GtkCellArea        *area,
1760                         GtkCellRenderer    *renderer,
1761                         const gchar        *first_prop_name,
1762                         ...)
1763 {
1764   va_list var_args;
1765
1766   g_return_if_fail (GTK_IS_CELL_AREA (area));
1767   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1768
1769   va_start (var_args, first_prop_name);
1770   gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1771   va_end (var_args);
1772 }
1773
1774 /**
1775  * gtk_cell_area_cell_get:
1776  * @area: a #GtkCellArea
1777  * @renderer: a #GtkCellRenderer which is inside @area
1778  * @first_prop_name: the name of the first cell property to get
1779  * @Varargs: return location for the first cell property, followed
1780  *     optionally by more name/return location pairs, followed by %NULL
1781  *
1782  * Gets the values of one or more cell properties for @renderer in @area.
1783  **/
1784 void
1785 gtk_cell_area_cell_get (GtkCellArea        *area,
1786                         GtkCellRenderer    *renderer,
1787                         const gchar        *first_prop_name,
1788                         ...)
1789 {
1790   va_list var_args;
1791
1792   g_return_if_fail (GTK_IS_CELL_AREA (area));
1793   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1794
1795   va_start (var_args, first_prop_name);
1796   gtk_cell_area_cell_get_valist (area, renderer, first_prop_name, var_args);
1797   va_end (var_args);
1798 }
1799
1800 static inline void
1801 area_get_cell_property (GtkCellArea     *area,
1802                         GtkCellRenderer *renderer,
1803                         GParamSpec      *pspec,
1804                         GValue          *value)
1805 {
1806   GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1807   
1808   class->get_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), value, pspec);
1809 }
1810
1811 static inline void
1812 area_set_cell_property (GtkCellArea     *area,
1813                         GtkCellRenderer *renderer,
1814                         GParamSpec      *pspec,
1815                         const GValue    *value)
1816 {
1817   GValue tmp_value = { 0, };
1818   GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1819
1820   /* provide a copy to work from, convert (if necessary) and validate */
1821   g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1822   if (!g_value_transform (value, &tmp_value))
1823     g_warning ("unable to set cell property `%s' of type `%s' from value of type `%s'",
1824                pspec->name,
1825                g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1826                G_VALUE_TYPE_NAME (value));
1827   else if (g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION))
1828     {
1829       gchar *contents = g_strdup_value_contents (value);
1830
1831       g_warning ("value \"%s\" of type `%s' is invalid for property `%s' of type `%s'",
1832                  contents,
1833                  G_VALUE_TYPE_NAME (value),
1834                  pspec->name,
1835                  g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
1836       g_free (contents);
1837     }
1838   else
1839     {
1840       class->set_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec);
1841     }
1842   g_value_unset (&tmp_value);
1843 }
1844
1845 /**
1846  * gtk_cell_area_cell_set_valist:
1847  * @area: a #GtkCellArea
1848  * @renderer: a #GtkCellRenderer which inside @area
1849  * @first_property_name: the name of the first cell property to set
1850  * @var_args: a %NULL-terminated list of property names and values, starting
1851  *           with @first_prop_name
1852  *
1853  * Sets one or more cell properties for @renderer in @area.
1854  **/
1855 void
1856 gtk_cell_area_cell_set_valist (GtkCellArea        *area,
1857                                GtkCellRenderer    *renderer,
1858                                const gchar        *first_property_name,
1859                                va_list             var_args)
1860 {
1861   const gchar *name;
1862
1863   g_return_if_fail (GTK_IS_CELL_AREA (area));
1864   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1865
1866   name = first_property_name;
1867   while (name)
1868     {
1869       GValue value = { 0, };
1870       gchar *error = NULL;
1871       GParamSpec *pspec = 
1872         g_param_spec_pool_lookup (cell_property_pool, name,
1873                                   G_OBJECT_TYPE (area), TRUE);
1874       if (!pspec)
1875         {
1876           g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1877                      G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1878           break;
1879         }
1880       if (!(pspec->flags & G_PARAM_WRITABLE))
1881         {
1882           g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1883                      G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1884           break;
1885         }
1886
1887       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1888       G_VALUE_COLLECT (&value, var_args, 0, &error);
1889       if (error)
1890         {
1891           g_warning ("%s: %s", G_STRLOC, error);
1892           g_free (error);
1893
1894           /* we purposely leak the value here, it might not be
1895            * in a sane state if an error condition occoured
1896            */
1897           break;
1898         }
1899       area_set_cell_property (area, renderer, pspec, &value);
1900       g_value_unset (&value);
1901       name = va_arg (var_args, gchar*);
1902     }
1903 }
1904
1905 /**
1906  * gtk_cell_area_cell_get_valist:
1907  * @area: a #GtkCellArea
1908  * @renderer: a #GtkCellRenderer inside @area
1909  * @first_property_name: the name of the first property to get
1910  * @var_args: return location for the first property, followed
1911  *     optionally by more name/return location pairs, followed by %NULL
1912  *
1913  * Gets the values of one or more cell properties for @renderer in @area.
1914  **/
1915 void
1916 gtk_cell_area_cell_get_valist (GtkCellArea        *area,
1917                                GtkCellRenderer    *renderer,
1918                                const gchar        *first_property_name,
1919                                va_list             var_args)
1920 {
1921   const gchar *name;
1922
1923   g_return_if_fail (GTK_IS_CELL_AREA (area));
1924   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1925
1926   name = first_property_name;
1927   while (name)
1928     {
1929       GValue value = { 0, };
1930       GParamSpec *pspec;
1931       gchar *error;
1932
1933       pspec = g_param_spec_pool_lookup (cell_property_pool, name,
1934                                         G_OBJECT_TYPE (area), TRUE);
1935       if (!pspec)
1936         {
1937           g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1938                      G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1939           break;
1940         }
1941       if (!(pspec->flags & G_PARAM_READABLE))
1942         {
1943           g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1944                      G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1945           break;
1946         }
1947
1948       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1949       area_get_cell_property (area, renderer, pspec, &value);
1950       G_VALUE_LCOPY (&value, var_args, 0, &error);
1951       if (error)
1952         {
1953           g_warning ("%s: %s", G_STRLOC, error);
1954           g_free (error);
1955           g_value_unset (&value);
1956           break;
1957         }
1958       g_value_unset (&value);
1959       name = va_arg (var_args, gchar*);
1960     }
1961 }
1962
1963 /**
1964  * gtk_cell_area_cell_set_property:
1965  * @area: a #GtkCellArea
1966  * @renderer: a #GtkCellRenderer inside @area
1967  * @property_name: the name of the cell property to set
1968  * @value: the value to set the cell property to
1969  *
1970  * Sets a cell property for @renderer in @area.
1971  **/
1972 void
1973 gtk_cell_area_cell_set_property (GtkCellArea        *area,
1974                                  GtkCellRenderer    *renderer,
1975                                  const gchar        *property_name,
1976                                  const GValue       *value)
1977 {
1978   GParamSpec *pspec;
1979
1980   g_return_if_fail (GTK_IS_CELL_AREA (area));
1981   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1982   g_return_if_fail (property_name != NULL);
1983   g_return_if_fail (G_IS_VALUE (value));
1984   
1985   pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1986                                     G_OBJECT_TYPE (area), TRUE);
1987   if (!pspec)
1988     g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1989                G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1990   else if (!(pspec->flags & G_PARAM_WRITABLE))
1991     g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1992                G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1993   else
1994     {
1995       area_set_cell_property (area, renderer, pspec, value);
1996     }
1997 }
1998
1999 /**
2000  * gtk_cell_area_cell_get_property:
2001  * @area: a #GtkCellArea
2002  * @renderer: a #GtkCellRenderer inside @area
2003  * @property_name: the name of the property to get
2004  * @value: a location to return the value
2005  *
2006  * Gets the value of a cell property for @renderer in @area.
2007  **/
2008 void
2009 gtk_cell_area_cell_get_property (GtkCellArea        *area,
2010                                  GtkCellRenderer    *renderer,
2011                                  const gchar        *property_name,
2012                                  GValue             *value)
2013 {
2014   GParamSpec *pspec;
2015
2016   g_return_if_fail (GTK_IS_CELL_AREA (area));
2017   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2018   g_return_if_fail (property_name != NULL);
2019   g_return_if_fail (G_IS_VALUE (value));
2020   
2021   pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
2022                                     G_OBJECT_TYPE (area), TRUE);
2023   if (!pspec)
2024     g_warning ("%s: cell area class `%s' has no cell property named `%s'",
2025                G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
2026   else if (!(pspec->flags & G_PARAM_READABLE))
2027     g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
2028                G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
2029   else
2030     {
2031       GValue *prop_value, tmp_value = { 0, };
2032
2033       /* auto-conversion of the callers value type
2034        */
2035       if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
2036         {
2037           g_value_reset (value);
2038           prop_value = value;
2039         }
2040       else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
2041         {
2042           g_warning ("can't retrieve cell property `%s' of type `%s' as value of type `%s'",
2043                      pspec->name,
2044                      g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
2045                      G_VALUE_TYPE_NAME (value));
2046           return;
2047         }
2048       else
2049         {
2050           g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
2051           prop_value = &tmp_value;
2052         }
2053
2054       area_get_cell_property (area, renderer, pspec, prop_value);
2055
2056       if (prop_value != value)
2057         {
2058           g_value_transform (prop_value, value);
2059           g_value_unset (&tmp_value);
2060         }
2061     }
2062 }
2063
2064 /*************************************************************
2065  *                         API: Focus                        *
2066  *************************************************************/
2067
2068 /**
2069  * gtk_cell_area_can_focus:
2070  * @area: a #GtkCellArea
2071  *
2072  * Returns whether the area can receive keyboard focus,
2073  * after applying new attributes to @area.
2074  *
2075  * Returns: whether @area can receive focus.
2076  */
2077 gboolean
2078 gtk_cell_area_can_focus (GtkCellArea *area)
2079 {
2080   g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2081
2082   return GTK_CELL_AREA_GET_CLASS (area)->can_focus (area);
2083 }
2084
2085 /**
2086  * gtk_cell_area_focus:
2087  * @area: a #GtkCellArea
2088  * @direction: the #GtkDirectionType
2089  *
2090  * This should be called by the @area's owning layout widget
2091  * when focus is to be passed to @area, or moved within @area
2092  * for a given @direction and row data.
2093  *
2094  * Implementing #GtkCellArea classes should implement this
2095  * method to receive and navigate focus in it's own way particular
2096  * to how it lays out cells.
2097  *
2098  * Returns: %TRUE if focus remains inside @area as a result of this call.
2099  */
2100 gboolean
2101 gtk_cell_area_focus (GtkCellArea      *area,
2102                      GtkDirectionType  direction)
2103 {
2104   GtkCellAreaClass *class;
2105
2106   g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2107
2108   class = GTK_CELL_AREA_GET_CLASS (area);
2109
2110   if (class->focus)
2111     return class->focus (area, direction);
2112
2113   g_warning ("GtkCellAreaClass::focus not implemented for `%s'", 
2114              g_type_name (G_TYPE_FROM_INSTANCE (area)));
2115
2116   return FALSE;
2117 }
2118
2119 /**
2120  * gtk_cell_area_activate:
2121  * @area: a #GtkCellArea
2122  * @context: the #GtkCellAreaContext in context with the current row data
2123  * @widget: the #GtkWidget that @area is rendering on
2124  * @cell_area: the size and location of @area relative to @widget's allocation
2125  * @flags: the #GtkCellRendererState flags for @area for this row of data.
2126  *
2127  * Activates @area, usually by activating the currently focused
2128  * cell, however some subclasses which embed widgets in the area
2129  * can also activate a widget if it currently has the focus.
2130  *
2131  * Returns: Whether @area was successfully activated.
2132  */
2133 gboolean
2134 gtk_cell_area_activate (GtkCellArea         *area,
2135                         GtkCellAreaContext  *context,
2136                         GtkWidget           *widget,
2137                         const GdkRectangle  *cell_area,
2138                         GtkCellRendererState flags)
2139 {
2140   g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2141
2142   return GTK_CELL_AREA_GET_CLASS (area)->activate (area, context, widget, cell_area, flags);
2143 }
2144
2145
2146 /**
2147  * gtk_cell_area_set_focus_cell:
2148  * @area: a #GtkCellArea
2149  * @focus_cell: the #GtkCellRenderer to give focus to
2150  *
2151  * This is generally called from #GtkCellArea implementations
2152  * either gtk_cell_area_grab_focus() or gtk_cell_area_update_focus()
2153  * is called. It's also up to the #GtkCellArea implementation
2154  * to update the focused cell when receiving events from
2155  * gtk_cell_area_event() appropriately.
2156  */
2157 void
2158 gtk_cell_area_set_focus_cell (GtkCellArea     *area,
2159                               GtkCellRenderer *renderer)
2160 {
2161   GtkCellAreaPrivate *priv;
2162
2163   g_return_if_fail (GTK_IS_CELL_AREA (area));
2164   g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer));
2165
2166   priv = area->priv;
2167
2168   if (priv->focus_cell != renderer)
2169     {
2170       if (priv->focus_cell)
2171         g_object_unref (priv->focus_cell);
2172
2173       priv->focus_cell = renderer;
2174
2175       if (priv->focus_cell)
2176         g_object_ref (priv->focus_cell);
2177
2178       g_object_notify (G_OBJECT (area), "focus-cell");
2179     }
2180
2181   /* Signal that the current focus renderer for this path changed
2182    * (it may be that the focus cell did not change, but the row
2183    * may have changed so we need to signal it) */
2184   g_signal_emit (area, cell_area_signals[SIGNAL_FOCUS_CHANGED], 0, 
2185                  priv->focus_cell, priv->current_path);
2186
2187 }
2188
2189 /**
2190  * gtk_cell_area_get_focus_cell:
2191  * @area: a #GtkCellArea
2192  *
2193  * Retrieves the currently focused cell for @area
2194  *
2195  * Returns: the currently focused cell in @area.
2196  */
2197 GtkCellRenderer *
2198 gtk_cell_area_get_focus_cell (GtkCellArea *area)
2199 {
2200   GtkCellAreaPrivate *priv;
2201
2202   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2203
2204   priv = area->priv;
2205
2206   return priv->focus_cell;
2207 }
2208
2209
2210 /*************************************************************
2211  *                    API: Focus Siblings                    *
2212  *************************************************************/
2213
2214 /**
2215  * gtk_cell_area_add_focus_sibling:
2216  * @area: a #GtkCellArea
2217  * @renderer: the #GtkCellRenderer expected to have focus
2218  * @sibling: the #GtkCellRenderer to add to @renderer's focus area
2219  *
2220  * Adds @sibling to @renderer's focusable area, focus will be drawn
2221  * around @renderer and all of it's siblings if @renderer can 
2222  * focus for a given row.
2223  *
2224  * Events handled by focus siblings can also activate the given
2225  * focusable @renderer.
2226  */
2227 void
2228 gtk_cell_area_add_focus_sibling (GtkCellArea     *area,
2229                                  GtkCellRenderer *renderer,
2230                                  GtkCellRenderer *sibling)
2231 {
2232   GtkCellAreaPrivate *priv;
2233   GList              *siblings;
2234
2235   g_return_if_fail (GTK_IS_CELL_AREA (area));
2236   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2237   g_return_if_fail (GTK_IS_CELL_RENDERER (sibling));
2238   g_return_if_fail (renderer != sibling);
2239   g_return_if_fail (gtk_cell_area_has_renderer (area, renderer));
2240   g_return_if_fail (gtk_cell_area_has_renderer (area, sibling));
2241   g_return_if_fail (!gtk_cell_area_is_focus_sibling (area, renderer, sibling));
2242
2243   /* XXX We should also check that sibling is not in any other renderer's sibling
2244    * list already, a renderer can be sibling of only one focusable renderer
2245    * at a time.
2246    */
2247
2248   priv = area->priv;
2249
2250   siblings = g_hash_table_lookup (priv->focus_siblings, renderer);
2251
2252   if (siblings)
2253     siblings = g_list_append (siblings, sibling);
2254   else
2255     {
2256       siblings = g_list_append (siblings, sibling);
2257       g_hash_table_insert (priv->focus_siblings, renderer, siblings);
2258     }
2259 }
2260
2261 /**
2262  * gtk_cell_area_remove_focus_sibling:
2263  * @area: a #GtkCellArea
2264  * @renderer: the #GtkCellRenderer expected to have focus
2265  * @sibling: the #GtkCellRenderer to remove from @renderer's focus area
2266  * 
2267  * Removes @sibling from @renderer's focus sibling list 
2268  * (see gtk_cell_area_add_focus_sibling()).
2269  */
2270 void
2271 gtk_cell_area_remove_focus_sibling (GtkCellArea     *area,
2272                                     GtkCellRenderer *renderer,
2273                                     GtkCellRenderer *sibling)
2274 {
2275   GtkCellAreaPrivate *priv;
2276   GList              *siblings;
2277
2278   g_return_if_fail (GTK_IS_CELL_AREA (area));
2279   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2280   g_return_if_fail (GTK_IS_CELL_RENDERER (sibling));
2281   g_return_if_fail (gtk_cell_area_is_focus_sibling (area, renderer, sibling));
2282
2283   priv = area->priv;
2284
2285   siblings = g_hash_table_lookup (priv->focus_siblings, renderer);
2286
2287   siblings = g_list_copy (siblings);
2288   siblings = g_list_remove (siblings, sibling);
2289
2290   if (!siblings)
2291     g_hash_table_remove (priv->focus_siblings, renderer);
2292   else
2293     g_hash_table_insert (priv->focus_siblings, renderer, siblings);
2294 }
2295
2296 /**
2297  * gtk_cell_area_is_focus_sibling:
2298  * @area: a #GtkCellArea
2299  * @renderer: the #GtkCellRenderer expected to have focus
2300  * @sibling: the #GtkCellRenderer to check against @renderer's sibling list
2301  * 
2302  * Returns %TRUE if @sibling is one of @renderer's focus siblings
2303  * (see gtk_cell_area_add_focus_sibling()).
2304  */
2305 gboolean
2306 gtk_cell_area_is_focus_sibling (GtkCellArea     *area,
2307                                 GtkCellRenderer *renderer,
2308                                 GtkCellRenderer *sibling)
2309 {
2310   GtkCellAreaPrivate *priv;
2311   GList              *siblings, *l;
2312
2313   g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2314   g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
2315   g_return_val_if_fail (GTK_IS_CELL_RENDERER (sibling), FALSE);
2316
2317   priv = area->priv;
2318
2319   siblings = g_hash_table_lookup (priv->focus_siblings, renderer);
2320
2321   for (l = siblings; l; l = l->next)
2322     {
2323       GtkCellRenderer *a_sibling = l->data;
2324
2325       if (a_sibling == sibling)
2326         return TRUE;
2327     }
2328
2329   return FALSE;
2330 }
2331
2332 /**
2333  * gtk_cell_area_get_focus_siblings:
2334  * @area: a #GtkCellArea
2335  * @renderer: the #GtkCellRenderer expected to have focus
2336  *
2337  * Gets the focus sibling cell renderers for @renderer.
2338  *
2339  * Returns: A #GList of #GtkCellRenderers. The returned list is internal and should not be freed.
2340  */
2341 const GList *
2342 gtk_cell_area_get_focus_siblings (GtkCellArea     *area,
2343                                   GtkCellRenderer *renderer)
2344 {
2345   GtkCellAreaPrivate *priv;
2346
2347   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2348   g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), NULL);
2349
2350   priv = area->priv;
2351
2352   return g_hash_table_lookup (priv->focus_siblings, renderer);  
2353 }
2354
2355 /**
2356  * gtk_cell_area_get_focus_from_sibling:
2357  * @area: a #GtkCellArea
2358  * @renderer: the #GtkCellRenderer
2359  *
2360  * Gets the #GtkCellRenderer which is expected to be focusable
2361  * for which @renderer is, or may be a sibling.
2362  *
2363  * This is handy for #GtkCellArea subclasses when handling events,
2364  * after determining the renderer at the event location it can
2365  * then chose to activate the focus cell for which the event
2366  * cell may have been a sibling.
2367  *
2368  * Returns: the #GtkCellRenderer for which @renderer is a sibling, or %NULL.
2369  */
2370 GtkCellRenderer *
2371 gtk_cell_area_get_focus_from_sibling (GtkCellArea          *area,
2372                                       GtkCellRenderer      *renderer)
2373 {
2374   GtkCellRenderer *ret_renderer = NULL;
2375   GList           *renderers, *l;
2376
2377   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2378   g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), NULL);
2379
2380   renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (area));
2381
2382   for (l = renderers; l; l = l->next)
2383     {
2384       GtkCellRenderer *a_renderer = l->data;
2385       const GList     *list;
2386
2387       for (list = gtk_cell_area_get_focus_siblings (area, a_renderer); 
2388            list; list = list->next)
2389         {
2390           GtkCellRenderer *sibling_renderer = list->data;
2391
2392           if (sibling_renderer == renderer)
2393             {
2394               ret_renderer = a_renderer;
2395               break;
2396             }
2397         }
2398     }
2399   g_list_free (renderers);
2400
2401   return ret_renderer;
2402 }
2403
2404 /*************************************************************
2405  *              API: Cell Activation/Editing                 *
2406  *************************************************************/
2407 static void
2408 gtk_cell_area_add_editable (GtkCellArea        *area,
2409                             GtkCellRenderer    *renderer,
2410                             GtkCellEditable    *editable,
2411                             GdkRectangle       *cell_area)
2412 {
2413   g_signal_emit (area, cell_area_signals[SIGNAL_ADD_EDITABLE], 0, 
2414                  renderer, editable, cell_area, area->priv->current_path);
2415 }
2416
2417 static void
2418 gtk_cell_area_remove_editable  (GtkCellArea        *area,
2419                                 GtkCellRenderer    *renderer,
2420                                 GtkCellEditable    *editable)
2421 {
2422   g_signal_emit (area, cell_area_signals[SIGNAL_REMOVE_EDITABLE], 0, renderer, editable);
2423 }
2424
2425 static void
2426 cell_area_remove_widget_cb (GtkCellEditable *editable,
2427                             GtkCellArea     *area)
2428 {
2429   GtkCellAreaPrivate *priv = area->priv;
2430
2431   g_assert (priv->edit_widget == editable);
2432   g_assert (priv->edited_cell != NULL);
2433
2434   gtk_cell_area_remove_editable (area, priv->edited_cell, priv->edit_widget);
2435
2436   /* Now that we're done with editing the widget and it can be removed,
2437    * remove our references to the widget and disconnect handlers */
2438   gtk_cell_area_set_edited_cell (area, NULL);
2439   gtk_cell_area_set_edit_widget (area, NULL);
2440 }
2441
2442 static void
2443 gtk_cell_area_set_edited_cell (GtkCellArea     *area,
2444                                GtkCellRenderer *renderer)
2445 {
2446   GtkCellAreaPrivate *priv;
2447
2448   g_return_if_fail (GTK_IS_CELL_AREA (area));
2449   g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer));
2450
2451   priv = area->priv;
2452
2453   if (priv->edited_cell != renderer)
2454     {
2455       if (priv->edited_cell)
2456         g_object_unref (priv->edited_cell);
2457
2458       priv->edited_cell = renderer;
2459
2460       if (priv->edited_cell)
2461         g_object_ref (priv->edited_cell);
2462
2463       g_object_notify (G_OBJECT (area), "edited-cell");
2464     }
2465 }
2466
2467 static void
2468 gtk_cell_area_set_edit_widget (GtkCellArea     *area,
2469                                GtkCellEditable *editable)
2470 {
2471   GtkCellAreaPrivate *priv;
2472
2473   g_return_if_fail (GTK_IS_CELL_AREA (area));
2474   g_return_if_fail (editable == NULL || GTK_IS_CELL_EDITABLE (editable));
2475
2476   priv = area->priv;
2477
2478   if (priv->edit_widget != editable)
2479     {
2480       if (priv->edit_widget)
2481         {
2482           g_signal_handler_disconnect (priv->edit_widget, priv->remove_widget_id);
2483
2484           g_object_unref (priv->edit_widget);
2485         }
2486
2487       priv->edit_widget = editable;
2488
2489       if (priv->edit_widget)
2490         {
2491           priv->remove_widget_id =
2492             g_signal_connect (priv->edit_widget, "remove-widget",
2493                               G_CALLBACK (cell_area_remove_widget_cb), area);
2494
2495           g_object_ref (priv->edit_widget);
2496         }
2497
2498       g_object_notify (G_OBJECT (area), "edit-widget");
2499     }
2500 }
2501
2502 /**
2503  * gtk_cell_area_get_edited_cell:
2504  * @area: a #GtkCellArea
2505  *
2506  * Gets the #GtkCellRenderer in @area that is currently
2507  * being edited.
2508  *
2509  * Returns: The currently edited #GtkCellRenderer
2510  */
2511 GtkCellRenderer   *
2512 gtk_cell_area_get_edited_cell (GtkCellArea *area)
2513 {
2514   GtkCellAreaPrivate *priv;
2515
2516   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2517
2518   priv = area->priv;
2519
2520   return priv->edited_cell;
2521 }
2522
2523 /**
2524  * gtk_cell_area_get_edit_widget:
2525  * @area: a #GtkCellArea
2526  *
2527  * Gets the #GtkCellEditable widget currently used
2528  * to edit the currently edited cell.
2529  *
2530  * Returns: The currently active #GtkCellEditable widget
2531  */
2532 GtkCellEditable *
2533 gtk_cell_area_get_edit_widget (GtkCellArea *area)
2534 {
2535   GtkCellAreaPrivate *priv;
2536
2537   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2538
2539   priv = area->priv;
2540
2541   return priv->edit_widget;
2542 }
2543
2544 /**
2545  * gtk_cell_area_activate_cell:
2546  * @area: a #GtkCellArea
2547  * @widget: the #GtkWidget that @area is rendering onto
2548  * @renderer: the #GtkCellRenderer in @area to activate
2549  * @event: the #GdkEvent for which cell activation should occur
2550  * @cell_area: the #GdkRectangle in @widget relative coordinates
2551  *             of @renderer for the current row.
2552  * @flags: the #GtkCellRendererState for @renderer
2553  *
2554  * This is used by #GtkCellArea subclasses when handling events
2555  * to activate cells, the base #GtkCellArea class activates cells
2556  * for keyboard events for free in it's own GtkCellArea->activate()
2557  * implementation.
2558  *
2559  * Returns: whether cell activation was successful
2560  */
2561 gboolean
2562 gtk_cell_area_activate_cell (GtkCellArea          *area,
2563                              GtkWidget            *widget,
2564                              GtkCellRenderer      *renderer,
2565                              GdkEvent             *event,
2566                              const GdkRectangle   *cell_area,
2567                              GtkCellRendererState  flags)
2568 {
2569   GtkCellRendererMode mode;
2570   GdkRectangle        inner_area;
2571   GtkCellAreaPrivate *priv;
2572   
2573   g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2574   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
2575   g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
2576   g_return_val_if_fail (cell_area != NULL, FALSE);
2577
2578   priv = area->priv;
2579
2580   /* Remove margins from the background area to produce the cell area.
2581    *
2582    * XXX Maybe have to do some rtl mode treatment here...
2583    */
2584   gtk_cell_area_inner_cell_area (area, cell_area, &inner_area);
2585
2586   g_object_get (renderer, "mode", &mode, NULL);
2587
2588   if (mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
2589     {
2590       if (gtk_cell_renderer_activate (renderer,
2591                                       event, widget,
2592                                       priv->current_path,
2593                                       cell_area,
2594                                       &inner_area,
2595                                       flags))
2596         return TRUE;
2597     }
2598   else if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
2599     {
2600       GtkCellEditable *editable_widget;
2601       
2602       editable_widget =
2603         gtk_cell_renderer_start_editing (renderer,
2604                                          event, widget,
2605                                          priv->current_path,
2606                                          cell_area,
2607                                          &inner_area,
2608                                          flags);
2609       
2610       if (editable_widget != NULL)
2611         {
2612           GdkRectangle edit_area;
2613
2614           g_return_val_if_fail (GTK_IS_CELL_EDITABLE (editable_widget), FALSE);
2615           
2616           gtk_cell_area_set_edited_cell (area, renderer);
2617           gtk_cell_area_set_edit_widget (area, editable_widget);
2618
2619           gtk_cell_area_aligned_cell_area (area, widget, renderer, &inner_area, &edit_area);
2620           
2621           /* Signal that editing started so that callers can get 
2622            * a handle on the editable_widget */
2623           gtk_cell_area_add_editable (area, priv->focus_cell, editable_widget, &edit_area);
2624
2625           /* If the signal was successfully handled start the editing */
2626           if (gtk_widget_get_parent (GTK_WIDGET (editable_widget)))
2627             {
2628               gtk_cell_editable_start_editing (editable_widget, NULL);
2629               gtk_widget_grab_focus (GTK_WIDGET (editable_widget));
2630             }
2631           else
2632             {
2633               /* Otherwise clear the editing state and fire a warning */
2634               gtk_cell_area_set_edited_cell (area, NULL);
2635               gtk_cell_area_set_edit_widget (area, NULL);
2636
2637               g_warning ("GtkCellArea::add-editable fired in the dark, no cell editing was started.");
2638             }
2639           
2640           return TRUE;
2641         }
2642     }
2643
2644   return FALSE;
2645 }
2646
2647 /**
2648  * gtk_cell_area_stop_editing:
2649  * @area: a #GtkCellArea
2650  * @canceled: whether editing was canceled.
2651  *
2652  * Explicitly stops the editing of the currently
2653  * edited cell (see gtk_cell_area_get_edited_cell()).
2654  *
2655  * If @canceled is %TRUE, the cell renderer will emit
2656  * the ::editing-canceled signal.
2657  */
2658 void
2659 gtk_cell_area_stop_editing (GtkCellArea *area,
2660                             gboolean     canceled)
2661 {
2662   GtkCellAreaPrivate *priv;
2663
2664   g_return_if_fail (GTK_IS_CELL_AREA (area));
2665
2666   priv = area->priv;
2667
2668   if (priv->edited_cell)
2669     {
2670       GtkCellEditable *edit_widget = g_object_ref (priv->edit_widget);
2671       GtkCellRenderer *edit_cell   = g_object_ref (priv->edited_cell);
2672
2673       /* Stop editing of the cell renderer */
2674       gtk_cell_renderer_stop_editing (priv->edited_cell, canceled);
2675       
2676       /* Remove any references to the editable widget */
2677       gtk_cell_area_set_edited_cell (area, NULL);
2678       gtk_cell_area_set_edit_widget (area, NULL);
2679
2680       /* Send the remove-widget signal explicitly (this is done after setting
2681        * the edit cell/widget NULL to avoid feedback)
2682        */
2683       gtk_cell_area_remove_editable (area, edit_cell, edit_widget);
2684       g_object_unref (edit_cell);
2685       g_object_unref (edit_widget);
2686     }
2687 }
2688
2689 /*************************************************************
2690  *                        API: Margins                       *
2691  *************************************************************/
2692 gint
2693 gtk_cell_area_get_cell_margin_left (GtkCellArea *area)
2694 {
2695   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
2696
2697   return area->priv->cell_border.left;
2698 }
2699
2700 void
2701 gtk_cell_area_set_cell_margin_left (GtkCellArea *area,
2702                                     gint         margin)
2703 {
2704   GtkCellAreaPrivate *priv;
2705
2706   g_return_if_fail (GTK_IS_CELL_AREA (area));
2707
2708   priv = area->priv;
2709
2710   if (priv->cell_border.left != margin)
2711     {
2712       priv->cell_border.left = margin;
2713
2714       g_object_notify (G_OBJECT (area), "cell-margin-left");
2715     }
2716 }
2717
2718 gint
2719 gtk_cell_area_get_cell_margin_right (GtkCellArea *area)
2720 {
2721   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
2722
2723   return area->priv->cell_border.right;
2724 }
2725
2726 void
2727 gtk_cell_area_set_cell_margin_right (GtkCellArea *area,
2728                                      gint         margin)
2729 {
2730   GtkCellAreaPrivate *priv;
2731
2732   g_return_if_fail (GTK_IS_CELL_AREA (area));
2733
2734   priv = area->priv;
2735
2736   if (priv->cell_border.right != margin)
2737     {
2738       priv->cell_border.right = margin;
2739
2740       g_object_notify (G_OBJECT (area), "cell-margin-right");
2741     }
2742 }
2743
2744 gint
2745 gtk_cell_area_get_cell_margin_top (GtkCellArea *area)
2746 {
2747   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
2748
2749   return area->priv->cell_border.top;
2750 }
2751
2752 void
2753 gtk_cell_area_set_cell_margin_top (GtkCellArea *area,
2754                                    gint         margin)
2755 {
2756   GtkCellAreaPrivate *priv;
2757
2758   g_return_if_fail (GTK_IS_CELL_AREA (area));
2759
2760   priv = area->priv;
2761
2762   if (priv->cell_border.top != margin)
2763     {
2764       priv->cell_border.top = margin;
2765
2766       g_object_notify (G_OBJECT (area), "cell-margin-top");
2767     }
2768 }
2769
2770 gint
2771 gtk_cell_area_get_cell_margin_bottom (GtkCellArea *area)
2772 {
2773   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
2774
2775   return area->priv->cell_border.bottom;
2776 }
2777
2778 void
2779 gtk_cell_area_set_cell_margin_bottom (GtkCellArea *area,
2780                                       gint         margin)
2781 {
2782   GtkCellAreaPrivate *priv;
2783
2784   g_return_if_fail (GTK_IS_CELL_AREA (area));
2785
2786   priv = area->priv;
2787
2788   if (priv->cell_border.bottom != margin)
2789     {
2790       priv->cell_border.bottom = margin;
2791
2792       g_object_notify (G_OBJECT (area), "cell-margin-bottom");
2793     }
2794 }
2795
2796 void
2797 gtk_cell_area_inner_cell_area (GtkCellArea        *area,
2798                                const GdkRectangle *cell_area,
2799                                GdkRectangle       *inner_area)
2800 {
2801   GtkCellAreaPrivate *priv;
2802
2803   g_return_if_fail (GTK_IS_CELL_AREA (area));
2804   g_return_if_fail (cell_area != NULL);
2805   g_return_if_fail (inner_area != NULL);
2806
2807   priv = area->priv;
2808
2809   *inner_area = *cell_area;
2810
2811   inner_area->x      += priv->cell_border.left;
2812   inner_area->width  -= (priv->cell_border.left + priv->cell_border.right);
2813   inner_area->y      += priv->cell_border.top;
2814   inner_area->height -= (priv->cell_border.top + priv->cell_border.bottom);
2815 }
2816
2817 void
2818 gtk_cell_area_aligned_cell_area (GtkCellArea        *area,
2819                                  GtkWidget          *widget,
2820                                  GtkCellRenderer    *renderer,
2821                                  const GdkRectangle *cell_area,
2822                                  GdkRectangle       *aligned_area)
2823 {
2824   GtkCellAreaPrivate *priv;
2825   gint                opposite_size, x_offset, y_offset;
2826
2827   g_return_if_fail (GTK_IS_CELL_AREA (area));
2828   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2829   g_return_if_fail (GTK_IS_WIDGET (widget));
2830   g_return_if_fail (cell_area != NULL);
2831   g_return_if_fail (aligned_area != NULL);
2832
2833   priv = area->priv;
2834
2835   *aligned_area = *cell_area;
2836
2837   /* Trim up the aligned size */
2838   if (gtk_cell_renderer_get_request_mode (renderer) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
2839     {
2840       gtk_cell_renderer_get_preferred_height_for_width (renderer, widget, 
2841                                                         aligned_area->width, 
2842                                                         NULL, &opposite_size);
2843
2844       aligned_area->height = MIN (opposite_size, aligned_area->height);
2845     }
2846   else
2847     {
2848       gtk_cell_renderer_get_preferred_width_for_height (renderer, widget, 
2849                                                         aligned_area->height, 
2850                                                         NULL, &opposite_size);
2851
2852       aligned_area->width = MIN (opposite_size, aligned_area->width);
2853     }
2854
2855   /* offset the cell position */
2856   _gtk_cell_renderer_calc_offset (renderer, cell_area, 
2857                                   gtk_widget_get_direction (widget),
2858                                   aligned_area->width, 
2859                                   aligned_area->height,
2860                                   &x_offset, &y_offset);
2861
2862   aligned_area->x += x_offset;
2863   aligned_area->y += y_offset;
2864 }
2865
2866 void
2867 gtk_cell_area_request_renderer (GtkCellArea        *area,
2868                                 GtkCellRenderer    *renderer,
2869                                 GtkOrientation      orientation,
2870                                 GtkWidget          *widget,
2871                                 gint                for_size,
2872                                 gint               *minimum_size,
2873                                 gint               *natural_size)
2874 {
2875   GtkCellAreaPrivate *priv;
2876
2877   g_return_if_fail (GTK_IS_CELL_AREA (area));
2878   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2879   g_return_if_fail (GTK_IS_WIDGET (widget));
2880   g_return_if_fail (minimum_size != NULL);
2881   g_return_if_fail (natural_size != NULL);
2882
2883   priv = area->priv;
2884
2885   if (orientation == GTK_ORIENTATION_HORIZONTAL)
2886     {
2887       if (for_size < 0)
2888           gtk_cell_renderer_get_preferred_width (renderer, widget, minimum_size, natural_size);
2889       else
2890         {
2891           for_size = MAX (0, for_size - (priv->cell_border.top + priv->cell_border.bottom));
2892
2893           gtk_cell_renderer_get_preferred_width_for_height (renderer, widget, for_size, 
2894                                                             minimum_size, natural_size);
2895         }
2896
2897       *minimum_size += (priv->cell_border.left + priv->cell_border.right);
2898       *natural_size += (priv->cell_border.left + priv->cell_border.right);
2899     }
2900   else /* GTK_ORIENTATION_VERTICAL */
2901     {
2902       if (for_size < 0)
2903         gtk_cell_renderer_get_preferred_height (renderer, widget, minimum_size, natural_size);
2904       else
2905         {
2906           for_size = MAX (0, for_size - (priv->cell_border.left + priv->cell_border.right));
2907
2908           gtk_cell_renderer_get_preferred_height_for_width (renderer, widget, for_size, 
2909                                                             minimum_size, natural_size);
2910         }
2911
2912       *minimum_size += (priv->cell_border.top + priv->cell_border.bottom);
2913       *natural_size += (priv->cell_border.top + priv->cell_border.bottom);
2914     }
2915 }