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