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