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