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