]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellarea.c
10190214e672d6ae3c56a0152a142f2f6af94c91
[~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 their 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_render                         (GtkCellArea          *area,
375                                                                     GtkCellAreaContext   *context,
376                                                                     GtkWidget            *widget,
377                                                                     cairo_t              *cr,
378                                                                     const GdkRectangle   *background_area,
379                                                                     const GdkRectangle   *cell_area,
380                                                                     GtkCellRendererState  flags,
381                                                                     gboolean              paint_focus);
382 static void      gtk_cell_area_real_apply_attributes               (GtkCellArea           *area,
383                                                                     GtkTreeModel          *tree_model,
384                                                                     GtkTreeIter           *iter,
385                                                                     gboolean               is_expander,
386                                                                     gboolean               is_expanded);
387 static void      gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea           *area,
388                                                                     GtkCellAreaContext    *context,
389                                                                     GtkWidget             *widget,
390                                                                     gint                   width,
391                                                                     gint                  *minimum_height,
392                                                                     gint                  *natural_height);
393 static void      gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea           *area,
394                                                                     GtkCellAreaContext    *context,
395                                                                     GtkWidget             *widget,
396                                                                     gint                   height,
397                                                                     gint                  *minimum_width,
398                                                                     gint                  *natural_width);
399 static gboolean  gtk_cell_area_real_is_activatable                 (GtkCellArea           *area);
400 static gboolean  gtk_cell_area_real_activate                       (GtkCellArea           *area,
401                                                                     GtkCellAreaContext    *context,
402                                                                     GtkWidget             *widget,
403                                                                     const GdkRectangle    *cell_area,
404                                                                     GtkCellRendererState   flags,
405                                                                     gboolean               edit_only);
406
407 /* GtkCellLayoutIface */
408 static void      gtk_cell_area_cell_layout_init              (GtkCellLayoutIface    *iface);
409 static void      gtk_cell_area_pack_default                  (GtkCellLayout         *cell_layout,
410                                                               GtkCellRenderer       *renderer,
411                                                               gboolean               expand);
412 static void      gtk_cell_area_clear                         (GtkCellLayout         *cell_layout);
413 static void      gtk_cell_area_add_attribute                 (GtkCellLayout         *cell_layout,
414                                                               GtkCellRenderer       *renderer,
415                                                               const gchar           *attribute,
416                                                               gint                   column);
417 static void      gtk_cell_area_set_cell_data_func            (GtkCellLayout         *cell_layout,
418                                                               GtkCellRenderer       *cell,
419                                                               GtkCellLayoutDataFunc  func,
420                                                               gpointer               func_data,
421                                                               GDestroyNotify         destroy);
422 static void      gtk_cell_area_clear_attributes              (GtkCellLayout         *cell_layout,
423                                                               GtkCellRenderer       *renderer);
424 static void      gtk_cell_area_reorder                       (GtkCellLayout         *cell_layout,
425                                                               GtkCellRenderer       *cell,
426                                                               gint                   position);
427 static GList    *gtk_cell_area_get_cells                     (GtkCellLayout         *cell_layout);
428 static GtkCellArea *gtk_cell_area_get_area                   (GtkCellLayout         *cell_layout);
429
430 /* GtkBuildableIface */
431 static void      gtk_cell_area_buildable_init                (GtkBuildableIface     *iface);
432 static void      gtk_cell_area_buildable_custom_tag_end      (GtkBuildable          *buildable,
433                                                               GtkBuilder            *builder,
434                                                               GObject               *child,
435                                                               const gchar           *tagname,
436                                                               gpointer              *data);
437
438 /* Used in foreach loop to check if a child renderer is present */
439 typedef struct {
440   GtkCellRenderer *renderer;
441   gboolean         has_renderer;
442 } HasRendererCheck;
443
444 /* Used in foreach loop to get a cell's allocation */
445 typedef struct {
446   GtkCellRenderer *renderer;
447   GdkRectangle     allocation;
448 } RendererAllocationData;
449
450 /* Used in foreach loop to render cells */
451 typedef struct {
452   GtkCellArea         *area;
453   GtkWidget           *widget;
454   cairo_t             *cr;
455   GdkRectangle         focus_rect;
456   GtkCellRendererState render_flags;
457   guint                paint_focus : 1;
458   guint                focus_all   : 1;
459   guint                first_focus : 1;
460 } CellRenderData;
461
462 /* Used in foreach loop to get a cell by position */
463 typedef struct {
464   gint             x;
465   gint             y;
466   GtkCellRenderer *renderer;
467   GdkRectangle     cell_area;
468 } CellByPositionData;
469
470 /* Attribute/Cell metadata */
471 typedef struct {
472   const gchar *attribute;
473   gint         column;
474 } CellAttribute;
475
476 typedef struct {
477   GSList          *attributes;
478
479   GtkCellLayoutDataFunc  func;
480   gpointer               data;
481   GDestroyNotify         destroy;
482 } CellInfo;
483
484 static CellInfo       *cell_info_new       (GtkCellLayoutDataFunc  func,
485                                             gpointer               data,
486                                             GDestroyNotify         destroy);
487 static void            cell_info_free      (CellInfo              *info);
488 static CellAttribute  *cell_attribute_new  (GtkCellRenderer       *renderer,
489                                             const gchar           *attribute,
490                                             gint                   column);
491 static void            cell_attribute_free (CellAttribute         *attribute);
492 static gint            cell_attribute_find (CellAttribute         *cell_attribute,
493                                             const gchar           *attribute);
494
495 /* Internal functions/signal emissions */
496 static void            gtk_cell_area_add_editable     (GtkCellArea        *area,
497                                                        GtkCellRenderer    *renderer,
498                                                        GtkCellEditable    *editable,
499                                                        const GdkRectangle *cell_area);
500 static void            gtk_cell_area_remove_editable  (GtkCellArea        *area,
501                                                        GtkCellRenderer    *renderer,
502                                                        GtkCellEditable    *editable);
503 static void            gtk_cell_area_set_edit_widget  (GtkCellArea        *area,
504                                                        GtkCellEditable    *editable);
505 static void            gtk_cell_area_set_edited_cell  (GtkCellArea        *area,
506                                                        GtkCellRenderer    *renderer);
507
508
509 /* Struct to pass data along while looping over 
510  * cell renderers to apply attributes
511  */
512 typedef struct {
513   GtkCellArea  *area;
514   GtkTreeModel *model;
515   GtkTreeIter  *iter;
516   gboolean      is_expander;
517   gboolean      is_expanded;
518 } AttributeData;
519
520 struct _GtkCellAreaPrivate
521 {
522   /* The GtkCellArea bookkeeps any connected 
523    * attributes in this hash table.
524    */
525   GHashTable      *cell_info;
526
527   /* Current path is saved as a side-effect
528    * of gtk_cell_area_apply_attributes() */
529   gchar           *current_path;
530
531   /* Current cell being edited and editable widget used */
532   GtkCellEditable *edit_widget;
533   GtkCellRenderer *edited_cell;
534
535   /* Signal connections to the editable widget */
536   gulong           remove_widget_id;
537
538   /* Currently focused cell */
539   GtkCellRenderer *focus_cell;
540
541   /* Tracking which cells are focus siblings of focusable cells */
542   GHashTable      *focus_siblings;
543
544   /* Detail string to pass to gtk_paint_*() functions */
545   gchar           *style_detail;
546 };
547
548 enum {
549   PROP_0,
550   PROP_FOCUS_CELL,
551   PROP_EDITED_CELL,
552   PROP_EDIT_WIDGET
553 };
554
555 enum {
556   SIGNAL_APPLY_ATTRIBUTES,
557   SIGNAL_ADD_EDITABLE,
558   SIGNAL_REMOVE_EDITABLE,
559   SIGNAL_FOCUS_CHANGED,
560   LAST_SIGNAL
561 };
562
563 /* Keep the paramspec pool internal, no need to deliver notifications
564  * on cells. at least no percieved need for now */
565 static GParamSpecPool *cell_property_pool = NULL;
566 static guint           cell_area_signals[LAST_SIGNAL] = { 0 };
567
568 #define PARAM_SPEC_PARAM_ID(pspec)              ((pspec)->param_id)
569 #define PARAM_SPEC_SET_PARAM_ID(pspec, id)      ((pspec)->param_id = (id))
570
571 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkCellArea, gtk_cell_area, G_TYPE_INITIALLY_UNOWNED,
572                                   G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
573                                                          gtk_cell_area_cell_layout_init)
574                                   G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
575                                                          gtk_cell_area_buildable_init))
576
577 static void
578 gtk_cell_area_init (GtkCellArea *area)
579 {
580   GtkCellAreaPrivate *priv;
581
582   area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area,
583                                             GTK_TYPE_CELL_AREA,
584                                             GtkCellAreaPrivate);
585   priv = area->priv;
586
587   priv->cell_info = g_hash_table_new_full (g_direct_hash, 
588                                            g_direct_equal,
589                                            NULL, 
590                                            (GDestroyNotify)cell_info_free);
591
592   priv->focus_siblings = g_hash_table_new_full (g_direct_hash, 
593                                                 g_direct_equal,
594                                                 NULL, 
595                                                 (GDestroyNotify)g_list_free);
596
597   priv->focus_cell         = NULL;
598   priv->edited_cell        = NULL;
599   priv->edit_widget        = NULL;
600
601   priv->remove_widget_id   = 0;
602 }
603
604 static void 
605 gtk_cell_area_class_init (GtkCellAreaClass *class)
606 {
607   GObjectClass *object_class = G_OBJECT_CLASS (class);
608   
609   /* GObjectClass */
610   object_class->dispose      = gtk_cell_area_dispose;
611   object_class->finalize     = gtk_cell_area_finalize;
612   object_class->get_property = gtk_cell_area_get_property;
613   object_class->set_property = gtk_cell_area_set_property;
614
615   /* general */
616   class->add              = NULL;
617   class->remove           = NULL;
618   class->foreach          = NULL;
619   class->event            = gtk_cell_area_real_event;
620   class->render           = gtk_cell_area_real_render;
621   class->apply_attributes = gtk_cell_area_real_apply_attributes;
622
623   /* geometry */
624   class->create_context                 = NULL;
625   class->get_request_mode               = NULL;
626   class->get_preferred_width            = NULL;
627   class->get_preferred_height           = NULL;
628   class->get_preferred_height_for_width = gtk_cell_area_real_get_preferred_height_for_width;
629   class->get_preferred_width_for_height = gtk_cell_area_real_get_preferred_width_for_height;
630
631   /* focus */
632   class->is_activatable = gtk_cell_area_real_is_activatable;
633   class->activate       = gtk_cell_area_real_activate;
634   class->focus          = NULL;
635
636   /* Signals */
637   /**
638    * GtkCellArea::apply-attributes:
639    * @area: the #GtkCellArea to apply the attributes to
640    * @model: the #GtkTreeModel to apply the attributes from
641    * @iter: the #GtkTreeIter indicating which row to apply the attributes of
642    * @is_expander: whether the view shows children for this row
643    * @is_expanded: whether the view is currently showing the children of this row
644    *
645    * This signal is emitted whenever applying attributes to @area from @model
646    *
647    * Since: 3.0
648    */
649   cell_area_signals[SIGNAL_APPLY_ATTRIBUTES] =
650     g_signal_new (I_("apply-attributes"),
651                   G_OBJECT_CLASS_TYPE (object_class),
652                   G_SIGNAL_RUN_FIRST,
653                   G_STRUCT_OFFSET (GtkCellAreaClass, apply_attributes),
654                   NULL, NULL,
655                   _gtk_marshal_VOID__OBJECT_BOXED_BOOLEAN_BOOLEAN,
656                   G_TYPE_NONE, 4,
657                   GTK_TYPE_TREE_MODEL,
658                   GTK_TYPE_TREE_ITER,
659                   G_TYPE_BOOLEAN,
660                   G_TYPE_BOOLEAN);
661
662   /**
663    * GtkCellArea::add-editable:
664    * @area: the #GtkCellArea where editing started
665    * @renderer: the #GtkCellRenderer that started the edited
666    * @editable: the #GtkCellEditable widget to add
667    * @cell_area: the #GtkWidget relative #GdkRectangle coordinates
668    *             where @editable should be added
669    * @path: the #GtkTreePath string this edit was initiated for
670    *
671    * Indicates that editing has started on @renderer and that @editable
672    * should be added to the owning cell layouting widget at @cell_area.
673    *
674    * Since: 3.0
675    */
676   cell_area_signals[SIGNAL_ADD_EDITABLE] =
677     g_signal_new (I_("add-editable"),
678                   G_OBJECT_CLASS_TYPE (object_class),
679                   G_SIGNAL_RUN_FIRST,
680                   0, /* No class closure here */
681                   NULL, NULL,
682                   _gtk_marshal_VOID__OBJECT_OBJECT_BOXED_STRING,
683                   G_TYPE_NONE, 4,
684                   GTK_TYPE_CELL_RENDERER,
685                   GTK_TYPE_CELL_EDITABLE,
686                   GDK_TYPE_RECTANGLE,
687                   G_TYPE_STRING);
688
689
690   /**
691    * GtkCellArea::remove-editable:
692    * @area: the #GtkCellArea where editing finished
693    * @renderer: the #GtkCellRenderer that finished editeding
694    * @editable: the #GtkCellEditable widget to remove
695    *
696    * Indicates that editing finished on @renderer and that @editable
697    * should be removed from the owning cell layouting widget.
698    *
699    * Since: 3.0
700    */
701   cell_area_signals[SIGNAL_REMOVE_EDITABLE] =
702     g_signal_new (I_("remove-editable"),
703                   G_OBJECT_CLASS_TYPE (object_class),
704                   G_SIGNAL_RUN_FIRST,
705                   0, /* No class closure here */
706                   NULL, NULL,
707                   _gtk_marshal_VOID__OBJECT_OBJECT,
708                   G_TYPE_NONE, 2,
709                   GTK_TYPE_CELL_RENDERER,
710                   GTK_TYPE_CELL_EDITABLE);
711
712   /**
713    * GtkCellArea::focus-changed:
714    * @area: the #GtkCellArea where focus changed
715    * @renderer: the #GtkCellRenderer that has focus
716    * @path: the current #GtkTreePath string set for @area
717    *
718    * Indicates that focus changed on this @area. This signal
719    * is emitted either as a result of focus handling or event
720    * handling.
721    *
722    * It's possible that the signal is emitted even if the
723    * currently focused renderer did not change, this is
724    * because focus may change to the same renderer in the
725    * same cell area for a different row of data.
726    *
727    * Since: 3.0
728    */
729   cell_area_signals[SIGNAL_FOCUS_CHANGED] =
730     g_signal_new (I_("focus-changed"),
731                   G_OBJECT_CLASS_TYPE (object_class),
732                   G_SIGNAL_RUN_FIRST,
733                   0, /* No class closure here */
734                   NULL, NULL,
735                   _gtk_marshal_VOID__OBJECT_STRING,
736                   G_TYPE_NONE, 2,
737                   GTK_TYPE_CELL_RENDERER,
738                   G_TYPE_STRING);
739
740   /* Properties */
741   /**
742    * GtkCellArea:focus-cell:
743    *
744    * The cell in the area that currently has focus
745    *
746    * Since: 3.0
747    */
748   g_object_class_install_property (object_class,
749                                    PROP_FOCUS_CELL,
750                                    g_param_spec_object
751                                    ("focus-cell",
752                                     P_("Focus Cell"),
753                                     P_("The cell which currently has focus"),
754                                     GTK_TYPE_CELL_RENDERER,
755                                     GTK_PARAM_READWRITE));
756
757   /**
758    * GtkCellArea:edited-cell:
759    *
760    * The cell in the area that is currently edited
761    *
762    * This property is read-only and only changes as
763    * a result of a call gtk_cell_area_activate_cell().
764    *
765    * Since: 3.0
766    */
767   g_object_class_install_property (object_class,
768                                    PROP_EDITED_CELL,
769                                    g_param_spec_object
770                                    ("edited-cell",
771                                     P_("Edited Cell"),
772                                     P_("The cell which is currently being edited"),
773                                     GTK_TYPE_CELL_RENDERER,
774                                     G_PARAM_READABLE));
775
776   /**
777    * GtkCellArea:edit-widget:
778    *
779    * The widget currently editing the edited cell
780    *
781    * This property is read-only and only changes as
782    * a result of a call gtk_cell_area_activate_cell().
783    *
784    * Since: 3.0
785    */
786   g_object_class_install_property (object_class,
787                                    PROP_EDIT_WIDGET,
788                                    g_param_spec_object
789                                    ("edit-widget",
790                                     P_("Edit Widget"),
791                                     P_("The widget currently editing the edited cell"),
792                                     GTK_TYPE_CELL_RENDERER,
793                                     G_PARAM_READABLE));
794
795   /* Pool for Cell Properties */
796   if (!cell_property_pool)
797     cell_property_pool = g_param_spec_pool_new (FALSE);
798
799   g_type_class_add_private (object_class, sizeof (GtkCellAreaPrivate));
800 }
801
802 /*************************************************************
803  *                    CellInfo Basics                        *
804  *************************************************************/
805 static CellInfo *
806 cell_info_new (GtkCellLayoutDataFunc  func,
807                gpointer               data,
808                GDestroyNotify         destroy)
809 {
810   CellInfo *info = g_slice_new0 (CellInfo);
811
812   info->func     = func;
813   info->data     = data;
814   info->destroy  = destroy;
815
816   return info;
817 }
818
819 static void
820 cell_info_free (CellInfo *info)
821 {
822   if (info->destroy)
823     info->destroy (info->data);
824
825   g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
826   g_slist_free (info->attributes);
827
828   g_slice_free (CellInfo, info);
829 }
830
831 static CellAttribute  *
832 cell_attribute_new  (GtkCellRenderer       *renderer,
833                      const gchar           *attribute,
834                      gint                   column)
835 {
836   GParamSpec *pspec;
837
838   /* Check if the attribute really exists and point to
839    * the property string installed on the cell renderer
840    * class (dont dup the string) 
841    */
842   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (renderer), attribute);
843
844   if (pspec)
845     {
846       CellAttribute *cell_attribute = g_slice_new (CellAttribute);
847
848       cell_attribute->attribute = pspec->name;
849       cell_attribute->column    = column;
850
851       return cell_attribute;
852     }
853
854   return NULL;
855 }
856
857 static void
858 cell_attribute_free (CellAttribute *attribute)
859 {
860   g_slice_free (CellAttribute, attribute);
861 }
862
863 /* GCompareFunc for g_slist_find_custom() */
864 static gint
865 cell_attribute_find (CellAttribute *cell_attribute,
866                      const gchar   *attribute)
867 {
868   return g_strcmp0 (cell_attribute->attribute, attribute);
869 }
870
871 /*************************************************************
872  *                      GObjectClass                         *
873  *************************************************************/
874 static void
875 gtk_cell_area_finalize (GObject *object)
876 {
877   GtkCellArea        *area   = GTK_CELL_AREA (object);
878   GtkCellAreaPrivate *priv   = area->priv;
879
880   /* All cell renderers should already be removed at this point,
881    * just kill our (empty) hash tables here. 
882    */
883   g_hash_table_destroy (priv->cell_info);
884   g_hash_table_destroy (priv->focus_siblings);
885
886   g_free (priv->current_path);
887
888   G_OBJECT_CLASS (gtk_cell_area_parent_class)->finalize (object);
889 }
890
891
892 static void
893 gtk_cell_area_dispose (GObject *object)
894 {
895   /* This removes every cell renderer that may be added to the GtkCellArea,
896    * subclasses should be breaking references to the GtkCellRenderers 
897    * at this point.
898    */
899   gtk_cell_layout_clear (GTK_CELL_LAYOUT (object));
900
901   /* Remove any ref to a focused/edited cell */
902   gtk_cell_area_set_focus_cell (GTK_CELL_AREA (object), NULL);
903   gtk_cell_area_set_edited_cell (GTK_CELL_AREA (object), NULL);
904   gtk_cell_area_set_edit_widget (GTK_CELL_AREA (object), NULL);
905
906   G_OBJECT_CLASS (gtk_cell_area_parent_class)->dispose (object);
907 }
908
909 static void
910 gtk_cell_area_set_property (GObject       *object,
911                             guint          prop_id,
912                             const GValue  *value,
913                             GParamSpec    *pspec)
914 {
915   GtkCellArea *area = GTK_CELL_AREA (object);
916
917   switch (prop_id)
918     {
919     case PROP_FOCUS_CELL:
920       gtk_cell_area_set_focus_cell (area, (GtkCellRenderer *)g_value_get_object (value));
921       break;
922     default:
923       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
924       break;
925     }
926 }
927
928 static void
929 gtk_cell_area_get_property (GObject     *object,
930                             guint        prop_id,
931                             GValue      *value,
932                             GParamSpec  *pspec)
933 {
934   GtkCellArea        *area = GTK_CELL_AREA (object);
935   GtkCellAreaPrivate *priv = area->priv;
936
937   switch (prop_id)
938     {
939     case PROP_FOCUS_CELL:
940       g_value_set_object (value, priv->focus_cell);
941       break;
942     case PROP_EDITED_CELL:
943       g_value_set_object (value, priv->edited_cell);
944       break;
945     case PROP_EDIT_WIDGET:
946       g_value_set_object (value, priv->edit_widget);
947       break;
948     default:
949       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
950       break;
951     }
952 }
953
954 /*************************************************************
955  *                    GtkCellAreaClass                       *
956  *************************************************************/
957 static gint
958 gtk_cell_area_real_event (GtkCellArea          *area,
959                           GtkCellAreaContext   *context,
960                           GtkWidget            *widget,
961                           GdkEvent             *event,
962                           const GdkRectangle   *cell_area,
963                           GtkCellRendererState  flags)
964 {
965   GtkCellAreaPrivate *priv = area->priv;
966   gboolean            retval = FALSE;
967
968   if (event->type == GDK_KEY_PRESS && (flags & GTK_CELL_RENDERER_FOCUSED) != 0)
969     {
970       GdkEventKey *key_event = (GdkEventKey *)event;
971
972       /* Cancel any edits in progress */
973       if (priv->edited_cell && (key_event->keyval == GDK_KEY_Escape))
974         {
975           gtk_cell_area_stop_editing (area, TRUE);
976           retval = TRUE;
977         }
978     }
979   else if (event->type == GDK_BUTTON_PRESS)
980     {
981       GdkEventButton *button_event = (GdkEventButton *)event;
982
983       if (button_event->button == 1)
984         {
985           GtkCellRenderer *renderer = NULL;
986           GtkCellRenderer *focus_renderer;
987           GdkRectangle     alloc_area;
988           gint             event_x, event_y;
989
990           /* We may need some semantics to tell us the offset of the event
991            * window we are handling events for (i.e. GtkTreeView has a bin_window) */
992           event_x = button_event->x;
993           event_y = button_event->y;
994
995           /* Dont try to search for an event coordinate that is not in the area, that will
996            * trigger a runtime warning.
997            */
998           if (event_x >= cell_area->x && event_x <= cell_area->x + cell_area->width &&
999               event_y >= cell_area->y && event_y <= cell_area->y + cell_area->height)
1000             renderer = 
1001               gtk_cell_area_get_cell_at_position (area, context, widget,
1002                                                   cell_area, event_x, event_y,
1003                                                   &alloc_area);
1004
1005           if (renderer)
1006             {
1007               focus_renderer = gtk_cell_area_get_focus_from_sibling (area, renderer);
1008               if (!focus_renderer)
1009                 focus_renderer = renderer;
1010
1011               /* If we're already editing, cancel it and set focus */
1012               if (gtk_cell_area_get_edited_cell (area))
1013                 {
1014                   /* XXX Was it really canceled in this case ? */
1015                   gtk_cell_area_stop_editing (area, TRUE);
1016                   gtk_cell_area_set_focus_cell (area, focus_renderer);
1017                   retval = TRUE;
1018                 }
1019               else
1020                 {
1021                   /* If we are activating via a focus sibling, 
1022                    * we need to fetch the right cell area for the real event renderer */
1023                   if (focus_renderer != renderer)
1024                     gtk_cell_area_get_cell_allocation (area, context, widget, focus_renderer,
1025                                                        cell_area, &alloc_area);
1026                   
1027                   gtk_cell_area_set_focus_cell (area, focus_renderer);
1028                   retval = gtk_cell_area_activate_cell (area, widget, focus_renderer,
1029                                                         event, &alloc_area, flags);
1030                 }
1031             }
1032         }
1033     }
1034
1035   return retval;
1036 }
1037
1038 static gboolean
1039 render_cell (GtkCellRenderer        *renderer,
1040              const GdkRectangle     *cell_area,
1041              const GdkRectangle     *cell_background,
1042              CellRenderData         *data)
1043 {
1044   GtkCellRenderer      *focus_cell;
1045   GtkCellRendererState  flags;
1046   GdkRectangle          inner_area;
1047
1048   focus_cell = gtk_cell_area_get_focus_cell (data->area);
1049   flags      = data->render_flags;
1050
1051   gtk_cell_area_inner_cell_area (data->area, data->widget, cell_area, &inner_area);
1052
1053   if ((flags & GTK_CELL_RENDERER_FOCUSED) &&
1054       (data->focus_all || 
1055        (focus_cell && 
1056         (renderer == focus_cell || 
1057          gtk_cell_area_is_focus_sibling (data->area, focus_cell, renderer)))))
1058     {
1059       gint focus_line_width;
1060       GdkRectangle cell_focus;
1061
1062       gtk_cell_renderer_get_aligned_area (renderer, data->widget, flags, &inner_area, &cell_focus);
1063
1064       gtk_widget_style_get (data->widget,
1065                             "focus-line-width", &focus_line_width,
1066                             NULL);
1067
1068       /* The focus rectangle is located around the aligned area of the cell */
1069       cell_focus.x -= focus_line_width;
1070       cell_focus.y -= focus_line_width;
1071       cell_focus.width += 2 * focus_line_width;
1072       cell_focus.height += 2 * focus_line_width;
1073
1074       if (data->first_focus)
1075         {
1076           data->first_focus = FALSE;
1077           data->focus_rect  = cell_focus;
1078         }
1079       else
1080         {
1081           gdk_rectangle_union (&data->focus_rect, &cell_focus, &data->focus_rect);
1082         }
1083     }
1084   else
1085     flags &= ~GTK_CELL_RENDERER_FOCUSED;
1086
1087   gtk_cell_renderer_render (renderer, data->cr, data->widget,
1088                             cell_background, &inner_area, flags);
1089
1090   return FALSE;
1091 }
1092
1093 static void
1094 gtk_cell_area_real_render (GtkCellArea          *area,
1095                            GtkCellAreaContext   *context,
1096                            GtkWidget            *widget,
1097                            cairo_t              *cr,
1098                            const GdkRectangle   *background_area,
1099                            const GdkRectangle   *cell_area,
1100                            GtkCellRendererState  flags,
1101                            gboolean              paint_focus)
1102 {
1103   CellRenderData render_data = 
1104     { 
1105       area, 
1106       widget, 
1107       cr, 
1108       { 0, }, 
1109       flags, 
1110       paint_focus, 
1111       FALSE, TRUE
1112     };
1113
1114   /* Make sure we dont paint a focus rectangle while there
1115    * is an editable widget in play 
1116    */
1117   if (gtk_cell_area_get_edited_cell (area))
1118     render_data.paint_focus = FALSE;
1119
1120   /* If no cell can activate but the caller wants focus painted,
1121    * then we paint focus around all cells */
1122   if ((flags & GTK_CELL_RENDERER_FOCUSED) != 0 && paint_focus && 
1123       !gtk_cell_area_is_activatable (area))
1124     render_data.focus_all = TRUE;
1125
1126   gtk_cell_area_foreach_alloc (area, context, widget, cell_area, background_area, 
1127                                (GtkCellAllocCallback)render_cell, &render_data);
1128
1129   if (render_data.paint_focus && 
1130       render_data.focus_rect.width != 0 && 
1131       render_data.focus_rect.height != 0)
1132     {
1133       GtkStateType renderer_state = 
1134         flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
1135         (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
1136          (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL));
1137
1138       gtk_paint_focus (gtk_widget_get_style (widget), cr, 
1139                        renderer_state, widget,
1140                        gtk_cell_area_get_style_detail (area),
1141                        render_data.focus_rect.x,     render_data.focus_rect.y,
1142                        render_data.focus_rect.width, render_data.focus_rect.height);
1143     }
1144 }
1145
1146 static void
1147 apply_cell_attributes (GtkCellRenderer *renderer,
1148                        CellInfo        *info,
1149                        AttributeData   *data)
1150 {
1151   CellAttribute *attribute;
1152   GSList        *list;
1153   GValue         value = { 0, };
1154   gboolean       is_expander;
1155   gboolean       is_expanded;
1156
1157   g_object_freeze_notify (G_OBJECT (renderer));
1158
1159   /* Whether a row expands or is presently expanded can only be 
1160    * provided by the view (as these states can vary across views
1161    * accessing the same model).
1162    */
1163   g_object_get (renderer, "is-expander", &is_expander, NULL);
1164   if (is_expander != data->is_expander)
1165     g_object_set (renderer, "is-expander", data->is_expander, NULL);
1166   
1167   g_object_get (renderer, "is-expanded", &is_expanded, NULL);
1168   if (is_expanded != data->is_expanded)
1169     g_object_set (renderer, "is-expanded", data->is_expanded, NULL);
1170
1171   /* Apply the attributes directly to the renderer */
1172   for (list = info->attributes; list; list = list->next)
1173     {
1174       attribute = list->data;
1175
1176       gtk_tree_model_get_value (data->model, data->iter, attribute->column, &value);
1177       g_object_set_property (G_OBJECT (renderer), attribute->attribute, &value);
1178       g_value_unset (&value);
1179     }
1180
1181   /* Call any GtkCellLayoutDataFunc that may have been set by the user
1182    */
1183   if (info->func)
1184     info->func (GTK_CELL_LAYOUT (data->area), renderer,
1185                 data->model, data->iter, info->data);
1186
1187   g_object_thaw_notify (G_OBJECT (renderer));
1188 }
1189
1190 static void
1191 gtk_cell_area_real_apply_attributes (GtkCellArea           *area,
1192                                      GtkTreeModel          *tree_model,
1193                                      GtkTreeIter           *iter,
1194                                      gboolean               is_expander,
1195                                      gboolean               is_expanded)
1196 {
1197
1198   GtkCellAreaPrivate *priv;
1199   AttributeData       data;
1200   GtkTreePath        *path;
1201
1202   priv = area->priv;
1203
1204   /* Feed in data needed to apply to every renderer */
1205   data.area        = area;
1206   data.model       = tree_model;
1207   data.iter        = iter;
1208   data.is_expander = is_expander;
1209   data.is_expanded = is_expanded;
1210
1211   /* Go over any cells that have attributes or custom GtkCellLayoutDataFuncs and
1212    * apply the data from the treemodel */
1213   g_hash_table_foreach (priv->cell_info, (GHFunc)apply_cell_attributes, &data);
1214
1215   /* Update the currently applied path */
1216   g_free (priv->current_path);
1217   path               = gtk_tree_model_get_path (tree_model, iter);
1218   priv->current_path = gtk_tree_path_to_string (path);
1219   gtk_tree_path_free (path);
1220 }
1221
1222 static void
1223 gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea        *area,
1224                                                    GtkCellAreaContext *context,
1225                                                    GtkWidget          *widget,
1226                                                    gint                width,
1227                                                    gint               *minimum_height,
1228                                                    gint               *natural_height)
1229 {
1230   /* If the area doesnt do height-for-width, fallback on base preferred height */
1231   GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, context, widget, minimum_height, natural_height);
1232 }
1233
1234 static void
1235 gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea        *area,
1236                                                    GtkCellAreaContext *context,
1237                                                    GtkWidget          *widget,
1238                                                    gint                height,
1239                                                    gint               *minimum_width,
1240                                                    gint               *natural_width)
1241 {
1242   /* If the area doesnt do width-for-height, fallback on base preferred width */
1243   GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, context, widget, minimum_width, natural_width);
1244 }
1245
1246 static gboolean
1247 get_is_activatable (GtkCellRenderer *renderer,
1248                     gboolean        *activatable)
1249 {
1250
1251   if (gtk_cell_renderer_is_activatable (renderer))
1252     *activatable = TRUE;
1253
1254   return *activatable;
1255 }
1256
1257 static gboolean
1258 gtk_cell_area_real_is_activatable (GtkCellArea *area)
1259 {
1260   gboolean activatable = FALSE;
1261
1262   /* Checks if any renderer can focus for the currently applied
1263    * attributes.
1264    *
1265    * Subclasses can override this in the case that they are also
1266    * rendering widgets as well as renderers.
1267    */
1268   gtk_cell_area_foreach (area, (GtkCellCallback)get_is_activatable, &activatable);
1269
1270   return activatable;
1271 }
1272
1273 static gboolean
1274 gtk_cell_area_real_activate (GtkCellArea         *area,
1275                              GtkCellAreaContext  *context,
1276                              GtkWidget           *widget,
1277                              const GdkRectangle  *cell_area,
1278                              GtkCellRendererState flags,
1279                              gboolean             edit_only)
1280 {
1281   GtkCellAreaPrivate *priv = area->priv;
1282   GdkRectangle        renderer_area;
1283   GtkCellRenderer    *activate_cell = NULL;
1284   GtkCellRendererMode mode;
1285
1286   if (priv->focus_cell)
1287     {
1288       g_object_get (priv->focus_cell, "mode", &mode, NULL);
1289
1290       if (gtk_cell_renderer_get_visible (priv->focus_cell) &&
1291           (edit_only ? mode == GTK_CELL_RENDERER_MODE_EDITABLE :
1292            mode != GTK_CELL_RENDERER_MODE_INERT))
1293         activate_cell = priv->focus_cell;
1294     }
1295   else
1296     {
1297       GList *cells, *l;
1298
1299       /* GtkTreeView sometimes wants to activate a cell when no
1300        * cells are in focus.
1301        */
1302       cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (area));
1303       for (l = cells; l && !activate_cell; l = l->next)
1304         {
1305           GtkCellRenderer *renderer = l->data;
1306
1307           g_object_get (renderer, "mode", &mode, NULL);
1308
1309           if (gtk_cell_renderer_get_visible (renderer) &&
1310               (edit_only ? mode == GTK_CELL_RENDERER_MODE_EDITABLE :
1311                mode != GTK_CELL_RENDERER_MODE_INERT))
1312             activate_cell = renderer;
1313         }
1314       g_list_free (cells);
1315     }
1316
1317   if (activate_cell)
1318     {
1319       /* Get the allocation of the focused cell.
1320        */
1321       gtk_cell_area_get_cell_allocation (area, context, widget, activate_cell,
1322                                          cell_area, &renderer_area);
1323       
1324       /* Activate or Edit the cell
1325        *
1326        * Currently just not sending an event, renderers afaics dont use
1327        * the event argument anyway, worst case is we can synthesize one.
1328        */
1329       if (gtk_cell_area_activate_cell (area, widget, activate_cell, NULL,
1330                                        &renderer_area, flags))
1331         return TRUE;
1332     }
1333
1334   return FALSE;
1335 }
1336
1337 /*************************************************************
1338  *                   GtkCellLayoutIface                      *
1339  *************************************************************/
1340 static void
1341 gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface)
1342 {
1343   iface->pack_start         = gtk_cell_area_pack_default;
1344   iface->pack_end           = gtk_cell_area_pack_default;
1345   iface->clear              = gtk_cell_area_clear;
1346   iface->add_attribute      = gtk_cell_area_add_attribute;
1347   iface->set_cell_data_func = gtk_cell_area_set_cell_data_func;
1348   iface->clear_attributes   = gtk_cell_area_clear_attributes;
1349   iface->reorder            = gtk_cell_area_reorder;
1350   iface->get_cells          = gtk_cell_area_get_cells;
1351   iface->get_area           = gtk_cell_area_get_area;
1352 }
1353
1354 static void
1355 gtk_cell_area_pack_default (GtkCellLayout         *cell_layout,
1356                             GtkCellRenderer       *renderer,
1357                             gboolean               expand)
1358 {
1359   gtk_cell_area_add (GTK_CELL_AREA (cell_layout), renderer);
1360 }
1361
1362 static void
1363 gtk_cell_area_clear (GtkCellLayout *cell_layout)
1364 {
1365   GtkCellArea *area = GTK_CELL_AREA (cell_layout);
1366   GList *l, *cells  =
1367     gtk_cell_layout_get_cells (cell_layout);
1368
1369   for (l = cells; l; l = l->next)
1370     {
1371       GtkCellRenderer *renderer = l->data;
1372       gtk_cell_area_remove (area, renderer);
1373     }
1374
1375   g_list_free (cells);
1376 }
1377
1378 static void
1379 gtk_cell_area_add_attribute (GtkCellLayout         *cell_layout,
1380                              GtkCellRenderer       *renderer,
1381                              const gchar           *attribute,
1382                              gint                   column)
1383 {
1384   gtk_cell_area_attribute_connect (GTK_CELL_AREA (cell_layout),
1385                                    renderer, attribute, column);
1386 }
1387
1388 static void
1389 gtk_cell_area_set_cell_data_func (GtkCellLayout         *cell_layout,
1390                                   GtkCellRenderer       *renderer,
1391                                   GtkCellLayoutDataFunc  func,
1392                                   gpointer               func_data,
1393                                   GDestroyNotify         destroy)
1394 {
1395   GtkCellArea        *area   = GTK_CELL_AREA (cell_layout);
1396   GtkCellAreaPrivate *priv   = area->priv;
1397   CellInfo           *info;
1398
1399   info = g_hash_table_lookup (priv->cell_info, renderer);
1400
1401   if (info)
1402     {
1403       if (info->destroy && info->data)
1404         info->destroy (info->data);
1405
1406       if (func)
1407         {
1408           info->func    = func;
1409           info->data    = func_data;
1410           info->destroy = destroy;
1411         }
1412       else
1413         {
1414           info->func    = NULL;
1415           info->data    = NULL;
1416           info->destroy = NULL;
1417         }
1418     }
1419   else
1420     {
1421       info = cell_info_new (func, func_data, destroy);
1422
1423       g_hash_table_insert (priv->cell_info, renderer, info);
1424     }
1425 }
1426
1427 static void
1428 gtk_cell_area_clear_attributes (GtkCellLayout         *cell_layout,
1429                                 GtkCellRenderer       *renderer)
1430 {
1431   GtkCellArea        *area = GTK_CELL_AREA (cell_layout);
1432   GtkCellAreaPrivate *priv = area->priv;
1433   CellInfo           *info;
1434
1435   info = g_hash_table_lookup (priv->cell_info, renderer);
1436
1437   if (info)
1438     {
1439       g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
1440       g_slist_free (info->attributes);
1441
1442       info->attributes = NULL;
1443     }
1444 }
1445
1446 static void 
1447 gtk_cell_area_reorder (GtkCellLayout   *cell_layout,
1448                        GtkCellRenderer *cell,
1449                        gint             position)
1450 {
1451   g_warning ("GtkCellLayout::reorder not implemented for `%s'", 
1452              g_type_name (G_TYPE_FROM_INSTANCE (cell_layout)));
1453 }
1454
1455 static gboolean
1456 accum_cells (GtkCellRenderer *renderer,
1457              GList          **accum)
1458 {
1459   *accum = g_list_prepend (*accum, renderer);
1460
1461   return FALSE;
1462 }
1463
1464 static GList *
1465 gtk_cell_area_get_cells (GtkCellLayout *cell_layout)
1466 {
1467   GList *cells = NULL;
1468
1469   gtk_cell_area_foreach (GTK_CELL_AREA (cell_layout), 
1470                          (GtkCellCallback)accum_cells,
1471                          &cells);
1472
1473   return g_list_reverse (cells);
1474 }
1475
1476 static GtkCellArea *
1477 gtk_cell_area_get_area (GtkCellLayout *cell_layout)
1478 {
1479   return GTK_CELL_AREA (cell_layout);
1480 }
1481
1482 /*************************************************************
1483  *                   GtkBuildableIface                       *
1484  *************************************************************/
1485 static void
1486 gtk_cell_area_buildable_init (GtkBuildableIface *iface)
1487 {
1488   iface->add_child = _gtk_cell_layout_buildable_add_child;
1489   iface->custom_tag_start = _gtk_cell_layout_buildable_custom_tag_start;
1490   iface->custom_tag_end = gtk_cell_area_buildable_custom_tag_end;
1491 }
1492
1493 static void
1494 gtk_cell_area_buildable_custom_tag_end (GtkBuildable *buildable,
1495                                         GtkBuilder   *builder,
1496                                         GObject      *child,
1497                                         const gchar  *tagname,
1498                                         gpointer     *data)
1499 {
1500   /* Just ignore the boolean return from here */
1501   _gtk_cell_layout_buildable_custom_tag_end (buildable, builder, child, tagname, data);
1502 }
1503
1504 /*************************************************************
1505  *                            API                            *
1506  *************************************************************/
1507
1508 /**
1509  * gtk_cell_area_add:
1510  * @area: a #GtkCellArea
1511  * @renderer: the #GtkCellRenderer to add to @area
1512  *
1513  * Adds @renderer to @area with the default child cell properties.
1514  *
1515  * Since: 3.0
1516  */
1517 void
1518 gtk_cell_area_add (GtkCellArea        *area,
1519                    GtkCellRenderer    *renderer)
1520 {
1521   GtkCellAreaClass *class;
1522
1523   g_return_if_fail (GTK_IS_CELL_AREA (area));
1524   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1525
1526   class = GTK_CELL_AREA_GET_CLASS (area);
1527
1528   if (class->add)
1529     class->add (area, renderer);
1530   else
1531     g_warning ("GtkCellAreaClass::add not implemented for `%s'", 
1532                g_type_name (G_TYPE_FROM_INSTANCE (area)));
1533 }
1534
1535 /**
1536  * gtk_cell_area_remove:
1537  * @area: a #GtkCellArea
1538  * @renderer: the #GtkCellRenderer to remove from @area
1539  *
1540  * Removes @renderer from @area.
1541  *
1542  * Since: 3.0
1543  */
1544 void
1545 gtk_cell_area_remove (GtkCellArea        *area,
1546                       GtkCellRenderer    *renderer)
1547 {
1548   GtkCellAreaClass   *class;
1549   GtkCellAreaPrivate *priv;
1550   GList              *renderers, *l;
1551
1552   g_return_if_fail (GTK_IS_CELL_AREA (area));
1553   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1554
1555   class = GTK_CELL_AREA_GET_CLASS (area);
1556   priv  = area->priv;
1557
1558   /* Remove any custom attributes and custom cell data func here first */
1559   g_hash_table_remove (priv->cell_info, renderer);
1560
1561   /* Remove focus siblings of this renderer */
1562   g_hash_table_remove (priv->focus_siblings, renderer);
1563
1564   /* Remove this renderer from any focus renderer's sibling list */ 
1565   renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (area));
1566
1567   for (l = renderers; l; l = l->next)
1568     {
1569       GtkCellRenderer *focus_renderer = l->data;
1570
1571       if (gtk_cell_area_is_focus_sibling (area, focus_renderer, renderer))
1572         {
1573           gtk_cell_area_remove_focus_sibling (area, focus_renderer, renderer);
1574           break;
1575         }
1576     }
1577
1578   g_list_free (renderers);
1579
1580   if (class->remove)
1581     class->remove (area, renderer);
1582   else
1583     g_warning ("GtkCellAreaClass::remove not implemented for `%s'", 
1584                g_type_name (G_TYPE_FROM_INSTANCE (area)));
1585 }
1586
1587 static gboolean
1588 get_has_renderer (GtkCellRenderer  *renderer,
1589                   HasRendererCheck *check)
1590 {
1591   if (renderer == check->renderer)
1592     check->has_renderer = TRUE;
1593
1594   return check->has_renderer;
1595 }
1596
1597 /**
1598  * gtk_cell_area_has_renderer:
1599  * @area: a #GtkCellArea
1600  * @renderer: the #GtkCellRenderer to check
1601  *
1602  * Checks if @area contains @renderer.
1603  *
1604  * Return value: %TRUE if @renderer is in the @area.
1605  *
1606  * Since: 3.0
1607  */
1608 gboolean
1609 gtk_cell_area_has_renderer (GtkCellArea     *area,
1610                             GtkCellRenderer *renderer)
1611 {
1612   HasRendererCheck check = { renderer, FALSE };
1613
1614   g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
1615   g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
1616
1617   gtk_cell_area_foreach (area, (GtkCellCallback)get_has_renderer, &check);
1618
1619   return check.has_renderer;
1620 }
1621
1622 /**
1623  * gtk_cell_area_foreach:
1624  * @area: a #GtkCellArea
1625  * @callback: the #GtkCellCallback to call
1626  * @callback_data: user provided data pointer
1627  *
1628  * Calls @callback for every #GtkCellRenderer in @area.
1629  *
1630  * Since: 3.0
1631  */
1632 void
1633 gtk_cell_area_foreach (GtkCellArea        *area,
1634                        GtkCellCallback     callback,
1635                        gpointer            callback_data)
1636 {
1637   GtkCellAreaClass *class;
1638
1639   g_return_if_fail (GTK_IS_CELL_AREA (area));
1640   g_return_if_fail (callback != NULL);
1641
1642   class = GTK_CELL_AREA_GET_CLASS (area);
1643
1644   if (class->foreach)
1645     class->foreach (area, callback, callback_data);
1646   else
1647     g_warning ("GtkCellAreaClass::foreach not implemented for `%s'", 
1648                g_type_name (G_TYPE_FROM_INSTANCE (area)));
1649 }
1650
1651 /**
1652  * gtk_cell_area_foreach_alloc:
1653  * @area: a #GtkCellArea
1654  * @context: the #GtkCellAreaContext for this row of data.
1655  * @widget: the #GtkWidget that @area is rendering to
1656  * @cell_area: the @widget relative coordinates and size for @area
1657  * @background_area: the @widget relative coordinates of the background area
1658  * @callback: the #GtkCellAllocCallback to call
1659  * @callback_data: user provided data pointer
1660  *
1661  * Calls @callback for every #GtkCellRenderer in @area with the
1662  * allocated rectangle inside @cell_area.
1663  *
1664  * Since: 3.0
1665  */
1666 void
1667 gtk_cell_area_foreach_alloc (GtkCellArea          *area,
1668                              GtkCellAreaContext   *context,
1669                              GtkWidget            *widget,
1670                              const GdkRectangle   *cell_area,
1671                              const GdkRectangle   *background_area,
1672                              GtkCellAllocCallback  callback,
1673                              gpointer              callback_data)
1674 {
1675   GtkCellAreaClass *class;
1676
1677   g_return_if_fail (GTK_IS_CELL_AREA (area));
1678   g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
1679   g_return_if_fail (GTK_IS_WIDGET (widget));
1680   g_return_if_fail (cell_area != NULL);
1681   g_return_if_fail (callback != NULL);
1682
1683   class = GTK_CELL_AREA_GET_CLASS (area);
1684
1685   if (class->foreach_alloc)
1686     class->foreach_alloc (area, context, widget, cell_area, background_area, callback, callback_data);
1687   else
1688     g_warning ("GtkCellAreaClass::foreach_alloc not implemented for `%s'", 
1689                g_type_name (G_TYPE_FROM_INSTANCE (area)));
1690 }
1691
1692 /**
1693  * gtk_cell_area_event:
1694  * @area: a #GtkCellArea
1695  * @context: the #GtkCellAreaContext for this row of data.
1696  * @widget: the #GtkWidget that @area is rendering to
1697  * @event: the #GdkEvent to handle
1698  * @cell_area: the @widget relative coordinates for @area
1699  * @flags: the #GtkCellRendererState for @area in this row.
1700  *
1701  * Delegates event handling to a #GtkCellArea.
1702  *
1703  * Return value: %TRUE if the event was handled by @area.
1704  *
1705  * Since: 3.0
1706  */
1707 gint
1708 gtk_cell_area_event (GtkCellArea          *area,
1709                      GtkCellAreaContext   *context,
1710                      GtkWidget            *widget,
1711                      GdkEvent             *event,
1712                      const GdkRectangle   *cell_area,
1713                      GtkCellRendererState  flags)
1714 {
1715   GtkCellAreaClass *class;
1716
1717   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1718   g_return_val_if_fail (GTK_IS_CELL_AREA_CONTEXT (context), 0);
1719   g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
1720   g_return_val_if_fail (event != NULL, 0);
1721   g_return_val_if_fail (cell_area != NULL, 0);
1722
1723   class = GTK_CELL_AREA_GET_CLASS (area);
1724
1725   if (class->event)
1726     return class->event (area, context, widget, event, cell_area, flags);
1727
1728   g_warning ("GtkCellAreaClass::event not implemented for `%s'", 
1729              g_type_name (G_TYPE_FROM_INSTANCE (area)));
1730   return 0;
1731 }
1732
1733 /**
1734  * gtk_cell_area_render:
1735  * @area: a #GtkCellArea
1736  * @context: the #GtkCellAreaContext for this row of data.
1737  * @widget: the #GtkWidget that @area is rendering to
1738  * @cr: the #cairo_t to render with
1739  * @background_area: the @widget relative coordinates for @area's background
1740  * @cell_area: the @widget relative coordinates for @area
1741  * @flags: the #GtkCellRendererState for @area in this row.
1742  * @paint_focus: whether @area should paint focus on focused cells for focused rows or not.
1743  *
1744  * Renders @area's cells according to @area's layout onto @widget at
1745  * the given coordinates.
1746  *
1747  * Since: 3.0
1748  */
1749 void
1750 gtk_cell_area_render (GtkCellArea          *area,
1751                       GtkCellAreaContext   *context,
1752                       GtkWidget            *widget,
1753                       cairo_t              *cr,
1754                       const GdkRectangle   *background_area,
1755                       const GdkRectangle   *cell_area,
1756                       GtkCellRendererState  flags,
1757                       gboolean              paint_focus)
1758 {
1759   GtkCellAreaClass *class;
1760
1761   g_return_if_fail (GTK_IS_CELL_AREA (area));
1762   g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
1763   g_return_if_fail (GTK_IS_WIDGET (widget));
1764   g_return_if_fail (cr != NULL);
1765   g_return_if_fail (background_area != NULL);
1766   g_return_if_fail (cell_area != NULL);
1767
1768   class = GTK_CELL_AREA_GET_CLASS (area);
1769
1770   if (class->render)
1771     class->render (area, context, widget, cr, background_area, cell_area, flags, paint_focus);
1772   else
1773     g_warning ("GtkCellAreaClass::render not implemented for `%s'", 
1774                g_type_name (G_TYPE_FROM_INSTANCE (area)));
1775 }
1776
1777 /**
1778  * gtk_cell_area_set_style_detail:
1779  * @area: a #GtkCellArea
1780  * @detail: the #GtkStyle detail string to set
1781  *
1782  * Sets the detail string used in any gtk_paint_*() functions
1783  * used by @area.
1784  *
1785  * Since: 3.0
1786  */
1787 void
1788 gtk_cell_area_set_style_detail (GtkCellArea *area,
1789                                 const gchar *detail)
1790 {
1791   GtkCellAreaPrivate *priv;
1792
1793   g_return_if_fail (GTK_IS_CELL_AREA (area));
1794
1795   priv = area->priv;
1796
1797   if (g_strcmp0 (priv->style_detail, detail) != 0)
1798     {
1799       g_free (priv->style_detail);
1800       priv->style_detail = g_strdup (detail);
1801     }
1802 }
1803
1804 /**
1805  * gtk_cell_area_get_style_detail:
1806  * @area: a #GtkCellArea
1807  *
1808  * Gets the detail string used in any gtk_paint_*() functions
1809  * used by @area.
1810  *
1811  * Return value: the detail string, the string belongs to the area and should not be freed.
1812  *
1813  * Since: 3.0
1814  */
1815 G_CONST_RETURN gchar *
1816 gtk_cell_area_get_style_detail (GtkCellArea *area)
1817 {
1818   GtkCellAreaPrivate *priv;
1819
1820   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1821
1822   priv = area->priv;
1823
1824   return priv->style_detail;
1825 }
1826
1827 static gboolean
1828 get_cell_allocation (GtkCellRenderer        *renderer,
1829                      const GdkRectangle     *cell_area,
1830                      const GdkRectangle     *cell_background,
1831                      RendererAllocationData *data)
1832 {
1833   if (data->renderer == renderer)
1834     data->allocation = *cell_area;
1835
1836   return (data->renderer == renderer);
1837 }
1838
1839 /**
1840  * gtk_cell_area_get_cell_allocation:
1841  * @area: a #GtkCellArea
1842  * @context: the #GtkCellAreaContext used to hold sizes for @area.
1843  * @widget: the #GtkWidget that @area is rendering on
1844  * @renderer: the #GtkCellRenderer to get the allocation for
1845  * @cell_area: the whole allocated area for @area in @widget
1846  *             for this row
1847  * @allocation: (out): where to store the allocation for @renderer
1848  *
1849  * Derives the allocation of @renderer inside @area if @area
1850  * were to be renderered in @cell_area.
1851  *
1852  * Since: 3.0
1853  */
1854 void
1855 gtk_cell_area_get_cell_allocation (GtkCellArea          *area,
1856                                    GtkCellAreaContext   *context,       
1857                                    GtkWidget            *widget,
1858                                    GtkCellRenderer      *renderer,
1859                                    const GdkRectangle   *cell_area,
1860                                    GdkRectangle         *allocation)
1861 {
1862   RendererAllocationData data = { renderer, { 0, } };
1863
1864   g_return_if_fail (GTK_IS_CELL_AREA (area));
1865   g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
1866   g_return_if_fail (GTK_IS_WIDGET (widget));
1867   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1868   g_return_if_fail (cell_area != NULL);
1869   g_return_if_fail (allocation != NULL);
1870
1871   gtk_cell_area_foreach_alloc (area, context, widget, cell_area, cell_area, 
1872                                (GtkCellAllocCallback)get_cell_allocation, &data);
1873
1874   *allocation = data.allocation;
1875 }
1876
1877 static gboolean
1878 get_cell_by_position (GtkCellRenderer     *renderer,
1879                       const GdkRectangle  *cell_area,
1880                       const GdkRectangle  *cell_background,
1881                       CellByPositionData  *data)
1882 {
1883   if (data->x >= cell_area->x && data->x < cell_area->x + cell_area->width &&
1884       data->y >= cell_area->y && data->y < cell_area->y + cell_area->height)
1885     {
1886       data->renderer  = renderer;
1887       data->cell_area = *cell_area;
1888     }
1889
1890   return (data->renderer != NULL);
1891 }
1892
1893 /**
1894  * gtk_cell_area_get_cell_at_position:
1895  * @area: a #GtkCellArea
1896  * @context: the #GtkCellAreaContext used to hold sizes for @area.
1897  * @widget: the #GtkWidget that @area is rendering on
1898  * @cell_area: the whole allocated area for @area in @widget
1899  *             for this row
1900  * @x: the x position
1901  * @y: the y position
1902  * @alloc_area: (out) (allow-none): where to store the inner allocated area of the 
1903  *                                  returned cell renderer, or %NULL.
1904  *
1905  * Gets the #GtkCellRenderer at @x and @y coordinates inside @area and optionally
1906  * returns the full cell allocation for it inside @cell_area.
1907  *
1908  * Return value: the #GtkCellRenderer at @x and @y.
1909  *
1910  * Since: 3.0
1911  */
1912 GtkCellRenderer *
1913 gtk_cell_area_get_cell_at_position (GtkCellArea          *area,
1914                                     GtkCellAreaContext   *context,
1915                                     GtkWidget            *widget,
1916                                     const GdkRectangle   *cell_area,
1917                                     gint                  x,
1918                                     gint                  y,
1919                                     GdkRectangle         *alloc_area)
1920 {
1921   CellByPositionData data = { x, y, NULL, { 0, } };
1922
1923   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1924   g_return_val_if_fail (GTK_IS_CELL_AREA_CONTEXT (context), NULL);
1925   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1926   g_return_val_if_fail (cell_area != NULL, NULL);
1927   g_return_val_if_fail (x >= cell_area->x && x <= cell_area->x + cell_area->width, NULL);
1928   g_return_val_if_fail (y >= cell_area->y && y <= cell_area->y + cell_area->height, NULL);
1929
1930   gtk_cell_area_foreach_alloc (area, context, widget, cell_area, cell_area, 
1931                                (GtkCellAllocCallback)get_cell_by_position, &data);
1932
1933   if (alloc_area)
1934     *alloc_area = data.cell_area;
1935
1936   return data.renderer;
1937 }
1938
1939 /*************************************************************
1940  *                      API: Geometry                        *
1941  *************************************************************/
1942 /**
1943  * gtk_cell_area_create_context:
1944  * @area: a #GtkCellArea
1945  *
1946  * Creates a #GtkCellAreaContext to be used with @area for
1947  * all purposes. #GtkCellAreaContext stores geometry information
1948  * for rows for which it was operated on, it is important to use
1949  * the same context for the same row of data at all times (i.e.
1950  * one should render and handle events with the same #GtkCellAreaContext
1951  * which was used to request the size of those rows of data).
1952  *
1953  * Return value: (transfer full): a newly created #GtkCellAreaContext which can be used with @area.
1954  *
1955  * Since: 3.0
1956  */
1957 GtkCellAreaContext *
1958 gtk_cell_area_create_context (GtkCellArea *area)
1959 {
1960   GtkCellAreaClass *class;
1961
1962   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1963
1964   class = GTK_CELL_AREA_GET_CLASS (area);
1965
1966   if (class->create_context)
1967     return class->create_context (area);
1968
1969   g_warning ("GtkCellAreaClass::create_context not implemented for `%s'", 
1970              g_type_name (G_TYPE_FROM_INSTANCE (area)));
1971   
1972   return NULL;
1973 }
1974
1975 /**
1976  * gtk_cell_area_copy_context:
1977  * @area: a #GtkCellArea
1978  * @context: the #GtkCellAreaContext to copy
1979  *
1980  * This is sometimes needed for cases where rows need to share
1981  * alignments in one orientation but may be separately grouped
1982  * in the opposing orientation.
1983  *
1984  * For instance, #GtkIconView creates all icons (rows) to have
1985  * the same width and the cells theirin to have the same
1986  * horizontal alignments. However each row of icons may have
1987  * a separate collective height. #GtkIconView uses this to
1988  * request the heights of each row based on a context which
1989  * was already used to request all the row widths that are
1990  * to be displayed.
1991  *
1992  * Return value: (transfer full): a newly created #GtkCellAreaContext copy of @context.
1993  *
1994  * Since: 3.0
1995  */
1996 GtkCellAreaContext *
1997 gtk_cell_area_copy_context (GtkCellArea        *area,
1998                             GtkCellAreaContext *context)
1999 {
2000   GtkCellAreaClass *class;
2001
2002   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2003   g_return_val_if_fail (GTK_IS_CELL_AREA_CONTEXT (context), NULL);
2004
2005   class = GTK_CELL_AREA_GET_CLASS (area);
2006
2007   if (class->copy_context)
2008     return class->copy_context (area, context);
2009
2010   g_warning ("GtkCellAreaClass::copy_context not implemented for `%s'", 
2011              g_type_name (G_TYPE_FROM_INSTANCE (area)));
2012   
2013   return NULL;
2014 }
2015
2016 /**
2017  * gtk_cell_area_get_request_mode:
2018  * @area: a #GtkCellArea
2019  *
2020  * Gets whether the area prefers a height-for-width layout
2021  * or a width-for-height layout.
2022  *
2023  * Return value: The #GtkSizeRequestMode preferred by @area.
2024  *
2025  * Since: 3.0
2026  */
2027 GtkSizeRequestMode 
2028 gtk_cell_area_get_request_mode (GtkCellArea *area)
2029 {
2030   GtkCellAreaClass *class;
2031
2032   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 
2033                         GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH);
2034
2035   class = GTK_CELL_AREA_GET_CLASS (area);
2036
2037   if (class->get_request_mode)
2038     return class->get_request_mode (area);
2039
2040   g_warning ("GtkCellAreaClass::get_request_mode not implemented for `%s'", 
2041              g_type_name (G_TYPE_FROM_INSTANCE (area)));
2042   
2043   return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
2044 }
2045
2046 /**
2047  * gtk_cell_area_get_preferred_width:
2048  * @area: a #GtkCellArea
2049  * @context: the #GtkCellAreaContext to perform this request with
2050  * @widget: the #GtkWidget where @area will be rendering
2051  * @minimum_width: (out) (allow-none): location to store the minimum width, or %NULL
2052  * @natural_width: (out) (allow-none): location to store the natural width, or %NULL
2053  *
2054  * Retrieves a cell area's initial minimum and natural width.
2055  *
2056  * @area will store some geometrical information in @context along the way,
2057  * when requesting sizes over an arbitrary number of rows, its not important
2058  * to check the @minimum_width and @natural_width of this call but rather to
2059  * consult gtk_cell_area_context_get_preferred_width() after a series of
2060  * requests.
2061  *
2062  * Since: 3.0
2063  */
2064 void
2065 gtk_cell_area_get_preferred_width (GtkCellArea        *area,
2066                                    GtkCellAreaContext *context,
2067                                    GtkWidget          *widget,
2068                                    gint               *minimum_width,
2069                                    gint               *natural_width)
2070 {
2071   GtkCellAreaClass *class;
2072
2073   g_return_if_fail (GTK_IS_CELL_AREA (area));
2074   g_return_if_fail (GTK_IS_WIDGET (widget));
2075
2076   class = GTK_CELL_AREA_GET_CLASS (area);
2077
2078   if (class->get_preferred_width)
2079     class->get_preferred_width (area, context, widget, minimum_width, natural_width);
2080   else
2081     g_warning ("GtkCellAreaClass::get_preferred_width not implemented for `%s'", 
2082                g_type_name (G_TYPE_FROM_INSTANCE (area)));
2083 }
2084
2085 /**
2086  * gtk_cell_area_get_preferred_height_for_width:
2087  * @area: a #GtkCellArea
2088  * @context: the #GtkCellAreaContext which has already been requested for widths.
2089  * @widget: the #GtkWidget where @area will be rendering
2090  * @width: the width for which to check the height of this area
2091  * @minimum_height: (out) (allow-none): location to store the minimum height, or %NULL
2092  * @natural_height: (out) (allow-none): location to store the natural height, or %NULL
2093  *
2094  * Retrieves a cell area's minimum and natural height if it would be given
2095  * the specified @width.
2096  *
2097  * @area stores some geometrical information in @context along the way
2098  * while calling gtk_cell_area_get_preferred_width(), it's important to
2099  * perform a series of gtk_cell_area_get_preferred_width() requests with
2100  * @context first and then call gtk_cell_area_get_preferred_height_for_width()
2101  * on each cell area individually to get the height for width of each
2102  * fully requested row.
2103  *
2104  * If at some point, the width of a single row changes, it should be
2105  * requested with gtk_cell_area_get_preferred_width() again and then
2106  * the full width of the requested rows checked again with
2107  * gtk_cell_area_context_get_preferred_width().
2108  *
2109  * Since: 3.0
2110  */
2111 void
2112 gtk_cell_area_get_preferred_height_for_width (GtkCellArea        *area,
2113                                               GtkCellAreaContext *context,
2114                                               GtkWidget          *widget,
2115                                               gint                width,
2116                                               gint               *minimum_height,
2117                                               gint               *natural_height)
2118 {
2119   GtkCellAreaClass *class;
2120
2121   g_return_if_fail (GTK_IS_CELL_AREA (area));
2122   g_return_if_fail (GTK_IS_WIDGET (widget));
2123
2124   class = GTK_CELL_AREA_GET_CLASS (area);
2125   class->get_preferred_height_for_width (area, context, widget, width, minimum_height, natural_height);
2126 }
2127
2128
2129 /**
2130  * gtk_cell_area_get_preferred_height:
2131  * @area: a #GtkCellArea
2132  * @context: the #GtkCellAreaContext to perform this request with
2133  * @widget: the #GtkWidget where @area will be rendering
2134  * @minimum_height: (out) (allow-none): location to store the minimum height, or %NULL
2135  * @natural_height: (out) (allow-none): location to store the natural height, or %NULL
2136  *
2137  * Retrieves a cell area's initial minimum and natural height.
2138  *
2139  * @area will store some geometrical information in @context along the way,
2140  * when requesting sizes over an arbitrary number of rows, its not important
2141  * to check the @minimum_height and @natural_height of this call but rather to
2142  * consult gtk_cell_area_context_get_preferred_height() after a series of
2143  * requests.
2144  *
2145  * Since: 3.0
2146  */
2147 void
2148 gtk_cell_area_get_preferred_height (GtkCellArea        *area,
2149                                     GtkCellAreaContext *context,
2150                                     GtkWidget          *widget,
2151                                     gint               *minimum_height,
2152                                     gint               *natural_height)
2153 {
2154   GtkCellAreaClass *class;
2155
2156   g_return_if_fail (GTK_IS_CELL_AREA (area));
2157   g_return_if_fail (GTK_IS_WIDGET (widget));
2158
2159   class = GTK_CELL_AREA_GET_CLASS (area);
2160
2161   if (class->get_preferred_height)
2162     class->get_preferred_height (area, context, widget, minimum_height, natural_height);
2163   else
2164     g_warning ("GtkCellAreaClass::get_preferred_height not implemented for `%s'", 
2165                g_type_name (G_TYPE_FROM_INSTANCE (area)));
2166 }
2167
2168 /**
2169  * gtk_cell_area_get_preferred_width_for_height:
2170  * @area: a #GtkCellArea
2171  * @context: the #GtkCellAreaContext which has already been requested for widths.
2172  * @widget: the #GtkWidget where @area will be rendering
2173  * @height: the height for which to check the width of this area
2174  * @minimum_width: (out) (allow-none): location to store the minimum width, or %NULL
2175  * @natural_width: (out) (allow-none): location to store the natural width, or %NULL
2176  *
2177  * Retrieves a cell area's minimum and natural width if it would be given
2178  * the specified @height.
2179  *
2180  * @area stores some geometrical information in @context along the way
2181  * while calling gtk_cell_area_get_preferred_height(), it's important to
2182  * perform a series of gtk_cell_area_get_preferred_height() requests with
2183  * @context first and then call gtk_cell_area_get_preferred_width_for_height()
2184  * on each cell area individually to get the height for width of each
2185  * fully requested row.
2186  *
2187  * If at some point, the height of a single row changes, it should be
2188  * requested with gtk_cell_area_get_preferred_height() again and then
2189  * the full height of the requested rows checked again with
2190  * gtk_cell_area_context_get_preferred_height().
2191  *
2192  * Since: 3.0
2193  */
2194 void
2195 gtk_cell_area_get_preferred_width_for_height (GtkCellArea        *area,
2196                                               GtkCellAreaContext *context,
2197                                               GtkWidget          *widget,
2198                                               gint                height,
2199                                               gint               *minimum_width,
2200                                               gint               *natural_width)
2201 {
2202   GtkCellAreaClass *class;
2203
2204   g_return_if_fail (GTK_IS_CELL_AREA (area));
2205   g_return_if_fail (GTK_IS_WIDGET (widget));
2206
2207   class = GTK_CELL_AREA_GET_CLASS (area);
2208   class->get_preferred_width_for_height (area, context, widget, height, minimum_width, natural_width);
2209 }
2210
2211 /*************************************************************
2212  *                      API: Attributes                      *
2213  *************************************************************/
2214
2215 /**
2216  * gtk_cell_area_attribute_connect:
2217  * @area: a #GtkCellArea
2218  * @renderer: the #GtkCellRenderer to connect an attribute for
2219  * @attribute: the attribute name
2220  * @column: the #GtkTreeModel column to fetch attribute values from
2221  *
2222  * Connects an @attribute to apply values from @column for the
2223  * #GtkTreeModel in use.
2224  *
2225  * Since: 3.0
2226  */
2227 void
2228 gtk_cell_area_attribute_connect (GtkCellArea        *area,
2229                                  GtkCellRenderer    *renderer,
2230                                  const gchar        *attribute,
2231                                  gint                column)
2232
2233   GtkCellAreaPrivate *priv;
2234   CellInfo           *info;
2235   CellAttribute      *cell_attribute;
2236
2237   g_return_if_fail (GTK_IS_CELL_AREA (area));
2238   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2239   g_return_if_fail (attribute != NULL);
2240   g_return_if_fail (gtk_cell_area_has_renderer (area, renderer));
2241
2242   priv = area->priv;
2243   info = g_hash_table_lookup (priv->cell_info, renderer);
2244
2245   if (!info)
2246     {
2247       info = cell_info_new (NULL, NULL, NULL);
2248
2249       g_hash_table_insert (priv->cell_info, renderer, info);
2250     }
2251   else
2252     {
2253       GSList *node;
2254
2255       /* Check we are not adding the same attribute twice */
2256       if ((node = g_slist_find_custom (info->attributes, attribute,
2257                                        (GCompareFunc)cell_attribute_find)) != NULL)
2258         {
2259           cell_attribute = node->data;
2260
2261           g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
2262                      "since `%s' is already attributed to column %d", 
2263                      attribute,
2264                      g_type_name (G_TYPE_FROM_INSTANCE (area)),
2265                      attribute, cell_attribute->column);
2266           return;
2267         }
2268     }
2269
2270   cell_attribute = cell_attribute_new (renderer, attribute, column);
2271
2272   if (!cell_attribute)
2273     {
2274       g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
2275                  "since attribute does not exist", 
2276                  attribute,
2277                  g_type_name (G_TYPE_FROM_INSTANCE (area)));
2278       return;
2279     }
2280
2281   info->attributes = g_slist_prepend (info->attributes, cell_attribute);
2282 }
2283
2284 /**
2285  * gtk_cell_area_attribute_disconnect:
2286  * @area: a #GtkCellArea
2287  * @renderer: the #GtkCellRenderer to disconnect an attribute for
2288  * @attribute: the attribute name
2289  *
2290  * Disconnects @attribute for the @renderer in @area so that
2291  * attribute will no longer be updated with values from the
2292  * model.
2293  *
2294  * Since: 3.0
2295  */
2296 void 
2297 gtk_cell_area_attribute_disconnect (GtkCellArea        *area,
2298                                     GtkCellRenderer    *renderer,
2299                                     const gchar        *attribute)
2300 {
2301   GtkCellAreaPrivate *priv;
2302   CellInfo           *info;
2303   CellAttribute      *cell_attribute;
2304   GSList             *node;
2305
2306   g_return_if_fail (GTK_IS_CELL_AREA (area));
2307   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2308   g_return_if_fail (attribute != NULL);
2309   g_return_if_fail (gtk_cell_area_has_renderer (area, renderer));
2310
2311   priv = area->priv;
2312   info = g_hash_table_lookup (priv->cell_info, renderer);
2313
2314   if (info)
2315     {
2316       node = g_slist_find_custom (info->attributes, attribute,
2317                                   (GCompareFunc)cell_attribute_find);
2318       if (node)
2319         {
2320           cell_attribute = node->data;
2321
2322           cell_attribute_free (cell_attribute);
2323
2324           info->attributes = g_slist_delete_link (info->attributes, node);
2325         }
2326     }
2327 }
2328
2329 /**
2330  * gtk_cell_area_apply_attributes
2331  * @area: a #GtkCellArea
2332  * @tree_model: the #GtkTreeModel to pull values from
2333  * @iter: the #GtkTreeIter in @tree_model to apply values for
2334  * @is_expander: whether @iter has children
2335  * @is_expanded: whether @iter is expanded in the view and
2336  *               children are visible
2337  *
2338  * Applies any connected attributes to the renderers in 
2339  * @area by pulling the values from @tree_model.
2340  *
2341  * Since: 3.0
2342  */
2343 void
2344 gtk_cell_area_apply_attributes (GtkCellArea  *area,
2345                                 GtkTreeModel *tree_model,
2346                                 GtkTreeIter  *iter,
2347                                 gboolean      is_expander,
2348                                 gboolean      is_expanded)
2349 {
2350   g_return_if_fail (GTK_IS_CELL_AREA (area));
2351   g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
2352   g_return_if_fail (iter != NULL);
2353
2354   g_signal_emit (area, cell_area_signals[SIGNAL_APPLY_ATTRIBUTES], 0, 
2355                  tree_model, iter, is_expander, is_expanded);
2356 }
2357
2358 /**
2359  * gtk_cell_area_get_current_path_string:
2360  * @area: a #GtkCellArea
2361  *
2362  * Gets the current #GtkTreePath string for the currently
2363  * applied #GtkTreeIter, this is implicitly updated when
2364  * gtk_cell_area_apply_attributes() is called and can be
2365  * used to interact with renderers from #GtkCellArea
2366  * subclasses.
2367  *
2368  * Return value: The current #GtkTreePath string for the current
2369  * attributes applied to @area. This string belongs to the area and
2370  * should not be freed.
2371  *
2372  * Since: 3.0
2373  */
2374 G_CONST_RETURN gchar *
2375 gtk_cell_area_get_current_path_string (GtkCellArea *area)
2376 {
2377   GtkCellAreaPrivate *priv;
2378
2379   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2380
2381   priv = area->priv;
2382
2383   return priv->current_path;
2384 }
2385
2386
2387 /*************************************************************
2388  *                    API: Cell Properties                   *
2389  *************************************************************/
2390 /**
2391  * gtk_cell_area_class_install_cell_property:
2392  * @aclass: a #GtkCellAreaClass
2393  * @property_id: the id for the property
2394  * @pspec: the #GParamSpec for the property
2395  *
2396  * Installs a cell property on a cell area class.
2397  *
2398  * Since: 3.0
2399  */
2400 void
2401 gtk_cell_area_class_install_cell_property (GtkCellAreaClass   *aclass,
2402                                            guint               property_id,
2403                                            GParamSpec         *pspec)
2404 {
2405   g_return_if_fail (GTK_IS_CELL_AREA_CLASS (aclass));
2406   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
2407   if (pspec->flags & G_PARAM_WRITABLE)
2408     g_return_if_fail (aclass->set_cell_property != NULL);
2409   if (pspec->flags & G_PARAM_READABLE)
2410     g_return_if_fail (aclass->get_cell_property != NULL);
2411   g_return_if_fail (property_id > 0);
2412   g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0);  /* paranoid */
2413   g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0);
2414
2415   if (g_param_spec_pool_lookup (cell_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (aclass), TRUE))
2416     {
2417       g_warning (G_STRLOC ": class `%s' already contains a cell property named `%s'",
2418                  G_OBJECT_CLASS_NAME (aclass), pspec->name);
2419       return;
2420     }
2421   g_param_spec_ref (pspec);
2422   g_param_spec_sink (pspec);
2423   PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
2424   g_param_spec_pool_insert (cell_property_pool, pspec, G_OBJECT_CLASS_TYPE (aclass));
2425 }
2426
2427 /**
2428  * gtk_cell_area_class_find_cell_property:
2429  * @aclass: a #GtkCellAreaClass
2430  * @property_name: the name of the child property to find
2431  *
2432  * Finds a cell property of a cell area class by name.
2433  *
2434  * Return value: (allow-none): the #GParamSpec of the child property or %NULL if @aclass has no
2435  *   child property with that name.
2436  *
2437  * Since: 3.0
2438  */
2439 GParamSpec*
2440 gtk_cell_area_class_find_cell_property (GtkCellAreaClass   *aclass,
2441                                         const gchar        *property_name)
2442 {
2443   g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
2444   g_return_val_if_fail (property_name != NULL, NULL);
2445
2446   return g_param_spec_pool_lookup (cell_property_pool,
2447                                    property_name,
2448                                    G_OBJECT_CLASS_TYPE (aclass),
2449                                    TRUE);
2450 }
2451
2452 /**
2453  * gtk_cell_area_class_list_cell_properties:
2454  * @aclass: a #GtkCellAreaClass
2455  * @n_properties: location to return the number of cell properties found
2456  *
2457  * Returns all cell properties of a cell area class.
2458  *
2459  * Return value: a newly allocated %NULL-terminated array of #GParamSpec*.
2460  *           The array must be freed with g_free().
2461  *
2462  * Since: 3.0
2463  */
2464 GParamSpec**
2465 gtk_cell_area_class_list_cell_properties (GtkCellAreaClass  *aclass,
2466                                           guint             *n_properties)
2467 {
2468   GParamSpec **pspecs;
2469   guint n;
2470
2471   g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
2472
2473   pspecs = g_param_spec_pool_list (cell_property_pool,
2474                                    G_OBJECT_CLASS_TYPE (aclass),
2475                                    &n);
2476   if (n_properties)
2477     *n_properties = n;
2478
2479   return pspecs;
2480 }
2481
2482 /**
2483  * gtk_cell_area_add_with_properties:
2484  * @area: a #GtkCellArea
2485  * @renderer: a #GtkCellRenderer to be placed inside @area
2486  * @first_prop_name: the name of the first cell property to set
2487  * @Varargs: a %NULL-terminated list of property names and values, starting
2488  *           with @first_prop_name
2489  *
2490  * Adds @renderer to @area, setting cell properties at the same time.
2491  * See gtk_cell_area_add() and gtk_cell_area_child_set() for more details.
2492  *
2493  * Since: 3.0
2494  */
2495 void
2496 gtk_cell_area_add_with_properties (GtkCellArea        *area,
2497                                    GtkCellRenderer    *renderer,
2498                                    const gchar        *first_prop_name,
2499                                    ...)
2500 {
2501   GtkCellAreaClass *class;
2502
2503   g_return_if_fail (GTK_IS_CELL_AREA (area));
2504   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2505
2506   class = GTK_CELL_AREA_GET_CLASS (area);
2507
2508   if (class->add)
2509     {
2510       va_list var_args;
2511
2512       class->add (area, renderer);
2513
2514       va_start (var_args, first_prop_name);
2515       gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
2516       va_end (var_args);
2517     }
2518   else
2519     g_warning ("GtkCellAreaClass::add not implemented for `%s'", 
2520                g_type_name (G_TYPE_FROM_INSTANCE (area)));
2521 }
2522
2523 /**
2524  * gtk_cell_area_cell_set:
2525  * @area: a #GtkCellArea
2526  * @renderer: a #GtkCellRenderer which is a cell inside @area
2527  * @first_prop_name: the name of the first cell property to set
2528  * @Varargs: a %NULL-terminated list of property names and values, starting
2529  *           with @first_prop_name
2530  *
2531  * Sets one or more cell properties for @cell in @area.
2532  *
2533  * Since: 3.0
2534  */
2535 void
2536 gtk_cell_area_cell_set (GtkCellArea        *area,
2537                         GtkCellRenderer    *renderer,
2538                         const gchar        *first_prop_name,
2539                         ...)
2540 {
2541   va_list var_args;
2542
2543   g_return_if_fail (GTK_IS_CELL_AREA (area));
2544   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2545
2546   va_start (var_args, first_prop_name);
2547   gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
2548   va_end (var_args);
2549 }
2550
2551 /**
2552  * gtk_cell_area_cell_get:
2553  * @area: a #GtkCellArea
2554  * @renderer: a #GtkCellRenderer which is inside @area
2555  * @first_prop_name: the name of the first cell property to get
2556  * @Varargs: return location for the first cell property, followed
2557  *     optionally by more name/return location pairs, followed by %NULL
2558  *
2559  * Gets the values of one or more cell properties for @renderer in @area.
2560  *
2561  * Since: 3.0
2562  */
2563 void
2564 gtk_cell_area_cell_get (GtkCellArea        *area,
2565                         GtkCellRenderer    *renderer,
2566                         const gchar        *first_prop_name,
2567                         ...)
2568 {
2569   va_list var_args;
2570
2571   g_return_if_fail (GTK_IS_CELL_AREA (area));
2572   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2573
2574   va_start (var_args, first_prop_name);
2575   gtk_cell_area_cell_get_valist (area, renderer, first_prop_name, var_args);
2576   va_end (var_args);
2577 }
2578
2579 static inline void
2580 area_get_cell_property (GtkCellArea     *area,
2581                         GtkCellRenderer *renderer,
2582                         GParamSpec      *pspec,
2583                         GValue          *value)
2584 {
2585   GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
2586   
2587   class->get_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), value, pspec);
2588 }
2589
2590 static inline void
2591 area_set_cell_property (GtkCellArea     *area,
2592                         GtkCellRenderer *renderer,
2593                         GParamSpec      *pspec,
2594                         const GValue    *value)
2595 {
2596   GValue tmp_value = { 0, };
2597   GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
2598
2599   /* provide a copy to work from, convert (if necessary) and validate */
2600   g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
2601   if (!g_value_transform (value, &tmp_value))
2602     g_warning ("unable to set cell property `%s' of type `%s' from value of type `%s'",
2603                pspec->name,
2604                g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
2605                G_VALUE_TYPE_NAME (value));
2606   else if (g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION))
2607     {
2608       gchar *contents = g_strdup_value_contents (value);
2609
2610       g_warning ("value \"%s\" of type `%s' is invalid for property `%s' of type `%s'",
2611                  contents,
2612                  G_VALUE_TYPE_NAME (value),
2613                  pspec->name,
2614                  g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
2615       g_free (contents);
2616     }
2617   else
2618     {
2619       class->set_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec);
2620     }
2621   g_value_unset (&tmp_value);
2622 }
2623
2624 /**
2625  * gtk_cell_area_cell_set_valist:
2626  * @area: a #GtkCellArea
2627  * @renderer: a #GtkCellRenderer which inside @area
2628  * @first_property_name: the name of the first cell property to set
2629  * @var_args: a %NULL-terminated list of property names and values, starting
2630  *           with @first_prop_name
2631  *
2632  * Sets one or more cell properties for @renderer in @area.
2633  *
2634  * Since: 3.0
2635  */
2636 void
2637 gtk_cell_area_cell_set_valist (GtkCellArea        *area,
2638                                GtkCellRenderer    *renderer,
2639                                const gchar        *first_property_name,
2640                                va_list             var_args)
2641 {
2642   const gchar *name;
2643
2644   g_return_if_fail (GTK_IS_CELL_AREA (area));
2645   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2646
2647   name = first_property_name;
2648   while (name)
2649     {
2650       GValue value = { 0, };
2651       gchar *error = NULL;
2652       GParamSpec *pspec = 
2653         g_param_spec_pool_lookup (cell_property_pool, name,
2654                                   G_OBJECT_TYPE (area), TRUE);
2655       if (!pspec)
2656         {
2657           g_warning ("%s: cell area class `%s' has no cell property named `%s'",
2658                      G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
2659           break;
2660         }
2661       if (!(pspec->flags & G_PARAM_WRITABLE))
2662         {
2663           g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
2664                      G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
2665           break;
2666         }
2667
2668       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
2669       G_VALUE_COLLECT (&value, var_args, 0, &error);
2670       if (error)
2671         {
2672           g_warning ("%s: %s", G_STRLOC, error);
2673           g_free (error);
2674
2675           /* we purposely leak the value here, it might not be
2676            * in a sane state if an error condition occoured
2677            */
2678           break;
2679         }
2680       area_set_cell_property (area, renderer, pspec, &value);
2681       g_value_unset (&value);
2682       name = va_arg (var_args, gchar*);
2683     }
2684 }
2685
2686 /**
2687  * gtk_cell_area_cell_get_valist:
2688  * @area: a #GtkCellArea
2689  * @renderer: a #GtkCellRenderer inside @area
2690  * @first_property_name: the name of the first property to get
2691  * @var_args: return location for the first property, followed
2692  *     optionally by more name/return location pairs, followed by %NULL
2693  *
2694  * Gets the values of one or more cell properties for @renderer in @area.
2695  *
2696  * Since: 3.0
2697  */
2698 void
2699 gtk_cell_area_cell_get_valist (GtkCellArea        *area,
2700                                GtkCellRenderer    *renderer,
2701                                const gchar        *first_property_name,
2702                                va_list             var_args)
2703 {
2704   const gchar *name;
2705
2706   g_return_if_fail (GTK_IS_CELL_AREA (area));
2707   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2708
2709   name = first_property_name;
2710   while (name)
2711     {
2712       GValue value = { 0, };
2713       GParamSpec *pspec;
2714       gchar *error;
2715
2716       pspec = g_param_spec_pool_lookup (cell_property_pool, name,
2717                                         G_OBJECT_TYPE (area), TRUE);
2718       if (!pspec)
2719         {
2720           g_warning ("%s: cell area class `%s' has no cell property named `%s'",
2721                      G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
2722           break;
2723         }
2724       if (!(pspec->flags & G_PARAM_READABLE))
2725         {
2726           g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
2727                      G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
2728           break;
2729         }
2730
2731       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
2732       area_get_cell_property (area, renderer, pspec, &value);
2733       G_VALUE_LCOPY (&value, var_args, 0, &error);
2734       if (error)
2735         {
2736           g_warning ("%s: %s", G_STRLOC, error);
2737           g_free (error);
2738           g_value_unset (&value);
2739           break;
2740         }
2741       g_value_unset (&value);
2742       name = va_arg (var_args, gchar*);
2743     }
2744 }
2745
2746 /**
2747  * gtk_cell_area_cell_set_property:
2748  * @area: a #GtkCellArea
2749  * @renderer: a #GtkCellRenderer inside @area
2750  * @property_name: the name of the cell property to set
2751  * @value: the value to set the cell property to
2752  *
2753  * Sets a cell property for @renderer in @area.
2754  *
2755  * Since: 3.0
2756  */
2757 void
2758 gtk_cell_area_cell_set_property (GtkCellArea        *area,
2759                                  GtkCellRenderer    *renderer,
2760                                  const gchar        *property_name,
2761                                  const GValue       *value)
2762 {
2763   GParamSpec *pspec;
2764
2765   g_return_if_fail (GTK_IS_CELL_AREA (area));
2766   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2767   g_return_if_fail (property_name != NULL);
2768   g_return_if_fail (G_IS_VALUE (value));
2769   
2770   pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
2771                                     G_OBJECT_TYPE (area), TRUE);
2772   if (!pspec)
2773     g_warning ("%s: cell area class `%s' has no cell property named `%s'",
2774                G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
2775   else if (!(pspec->flags & G_PARAM_WRITABLE))
2776     g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
2777                G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
2778   else
2779     {
2780       area_set_cell_property (area, renderer, pspec, value);
2781     }
2782 }
2783
2784 /**
2785  * gtk_cell_area_cell_get_property:
2786  * @area: a #GtkCellArea
2787  * @renderer: a #GtkCellRenderer inside @area
2788  * @property_name: the name of the property to get
2789  * @value: a location to return the value
2790  *
2791  * Gets the value of a cell property for @renderer in @area.
2792  *
2793  * Since: 3.0
2794  */
2795 void
2796 gtk_cell_area_cell_get_property (GtkCellArea        *area,
2797                                  GtkCellRenderer    *renderer,
2798                                  const gchar        *property_name,
2799                                  GValue             *value)
2800 {
2801   GParamSpec *pspec;
2802
2803   g_return_if_fail (GTK_IS_CELL_AREA (area));
2804   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2805   g_return_if_fail (property_name != NULL);
2806   g_return_if_fail (G_IS_VALUE (value));
2807   
2808   pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
2809                                     G_OBJECT_TYPE (area), TRUE);
2810   if (!pspec)
2811     g_warning ("%s: cell area class `%s' has no cell property named `%s'",
2812                G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
2813   else if (!(pspec->flags & G_PARAM_READABLE))
2814     g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
2815                G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
2816   else
2817     {
2818       GValue *prop_value, tmp_value = { 0, };
2819
2820       /* auto-conversion of the callers value type
2821        */
2822       if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
2823         {
2824           g_value_reset (value);
2825           prop_value = value;
2826         }
2827       else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
2828         {
2829           g_warning ("can't retrieve cell property `%s' of type `%s' as value of type `%s'",
2830                      pspec->name,
2831                      g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
2832                      G_VALUE_TYPE_NAME (value));
2833           return;
2834         }
2835       else
2836         {
2837           g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
2838           prop_value = &tmp_value;
2839         }
2840
2841       area_get_cell_property (area, renderer, pspec, prop_value);
2842
2843       if (prop_value != value)
2844         {
2845           g_value_transform (prop_value, value);
2846           g_value_unset (&tmp_value);
2847         }
2848     }
2849 }
2850
2851 /*************************************************************
2852  *                         API: Focus                        *
2853  *************************************************************/
2854
2855 /**
2856  * gtk_cell_area_is_activatable:
2857  * @area: a #GtkCellArea
2858  *
2859  * Returns whether the area can do anything when activated,
2860  * after applying new attributes to @area.
2861  *
2862  * Return value: whether @area can do anything when activated.
2863  *
2864  * Since: 3.0
2865  */
2866 gboolean
2867 gtk_cell_area_is_activatable (GtkCellArea *area)
2868 {
2869   g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2870
2871   return GTK_CELL_AREA_GET_CLASS (area)->is_activatable (area);
2872 }
2873
2874 /**
2875  * gtk_cell_area_focus:
2876  * @area: a #GtkCellArea
2877  * @direction: the #GtkDirectionType
2878  *
2879  * This should be called by the @area's owning layout widget
2880  * when focus is to be passed to @area, or moved within @area
2881  * for a given @direction and row data.
2882  *
2883  * Implementing #GtkCellArea classes should implement this
2884  * method to receive and navigate focus in it's own way particular
2885  * to how it lays out cells.
2886  *
2887  * Return value: %TRUE if focus remains inside @area as a result of this call.
2888  *
2889  * Since: 3.0
2890  */
2891 gboolean
2892 gtk_cell_area_focus (GtkCellArea      *area,
2893                      GtkDirectionType  direction)
2894 {
2895   GtkCellAreaClass *class;
2896
2897   g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2898
2899   class = GTK_CELL_AREA_GET_CLASS (area);
2900
2901   if (class->focus)
2902     return class->focus (area, direction);
2903
2904   g_warning ("GtkCellAreaClass::focus not implemented for `%s'", 
2905              g_type_name (G_TYPE_FROM_INSTANCE (area)));
2906
2907   return FALSE;
2908 }
2909
2910 /**
2911  * gtk_cell_area_activate:
2912  * @area: a #GtkCellArea
2913  * @context: the #GtkCellAreaContext in context with the current row data
2914  * @widget: the #GtkWidget that @area is rendering on
2915  * @cell_area: the size and location of @area relative to @widget's allocation
2916  * @flags: the #GtkCellRendererState flags for @area for this row of data.
2917  * @edit_only: if %TRUE then only cell renderers that are %GTK_CELL_RENDERER_MODE_EDITABLE
2918  *             will be activated.
2919  *
2920  * Activates @area, usually by activating the currently focused
2921  * cell, however some subclasses which embed widgets in the area
2922  * can also activate a widget if it currently has the focus.
2923  *
2924  * Return value: Whether @area was successfully activated.
2925  *
2926  * Since: 3.0
2927  */
2928 gboolean
2929 gtk_cell_area_activate (GtkCellArea         *area,
2930                         GtkCellAreaContext  *context,
2931                         GtkWidget           *widget,
2932                         const GdkRectangle  *cell_area,
2933                         GtkCellRendererState flags,
2934                         gboolean             edit_only)
2935 {
2936   g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2937
2938   return GTK_CELL_AREA_GET_CLASS (area)->activate (area, context, widget, cell_area, flags, edit_only);
2939 }
2940
2941
2942 /**
2943  * gtk_cell_area_set_focus_cell:
2944  * @area: a #GtkCellArea
2945  * @focus_cell: the #GtkCellRenderer to give focus to
2946  *
2947  * This is generally called from #GtkCellArea implementations
2948  * either gtk_cell_area_grab_focus() or gtk_cell_area_update_focus()
2949  * is called. It's also up to the #GtkCellArea implementation
2950  * to update the focused cell when receiving events from
2951  * gtk_cell_area_event() appropriately.
2952  *
2953  * Since: 3.0
2954  */
2955 void
2956 gtk_cell_area_set_focus_cell (GtkCellArea     *area,
2957                               GtkCellRenderer *renderer)
2958 {
2959   GtkCellAreaPrivate *priv;
2960
2961   g_return_if_fail (GTK_IS_CELL_AREA (area));
2962   g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer));
2963
2964   priv = area->priv;
2965
2966   if (priv->focus_cell != renderer)
2967     {
2968       if (priv->focus_cell)
2969         g_object_unref (priv->focus_cell);
2970
2971       priv->focus_cell = renderer;
2972
2973       if (priv->focus_cell)
2974         g_object_ref (priv->focus_cell);
2975
2976       g_object_notify (G_OBJECT (area), "focus-cell");
2977     }
2978
2979   /* Signal that the current focus renderer for this path changed
2980    * (it may be that the focus cell did not change, but the row
2981    * may have changed so we need to signal it) */
2982   g_signal_emit (area, cell_area_signals[SIGNAL_FOCUS_CHANGED], 0, 
2983                  priv->focus_cell, priv->current_path);
2984
2985 }
2986
2987 /**
2988  * gtk_cell_area_get_focus_cell:
2989  * @area: a #GtkCellArea
2990  *
2991  * Retrieves the currently focused cell for @area
2992  *
2993  * Return value: the currently focused cell in @area.
2994  *
2995  * Since: 3.0
2996  */
2997 GtkCellRenderer *
2998 gtk_cell_area_get_focus_cell (GtkCellArea *area)
2999 {
3000   GtkCellAreaPrivate *priv;
3001
3002   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
3003
3004   priv = area->priv;
3005
3006   return priv->focus_cell;
3007 }
3008
3009
3010 /*************************************************************
3011  *                    API: Focus Siblings                    *
3012  *************************************************************/
3013
3014 /**
3015  * gtk_cell_area_add_focus_sibling:
3016  * @area: a #GtkCellArea
3017  * @renderer: the #GtkCellRenderer expected to have focus
3018  * @sibling: the #GtkCellRenderer to add to @renderer's focus area
3019  *
3020  * Adds @sibling to @renderer's focusable area, focus will be drawn
3021  * around @renderer and all of it's siblings if @renderer can 
3022  * focus for a given row.
3023  *
3024  * Events handled by focus siblings can also activate the given
3025  * focusable @renderer.
3026  *
3027  * Since: 3.0
3028  */
3029 void
3030 gtk_cell_area_add_focus_sibling (GtkCellArea     *area,
3031                                  GtkCellRenderer *renderer,
3032                                  GtkCellRenderer *sibling)
3033 {
3034   GtkCellAreaPrivate *priv;
3035   GList              *siblings;
3036
3037   g_return_if_fail (GTK_IS_CELL_AREA (area));
3038   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
3039   g_return_if_fail (GTK_IS_CELL_RENDERER (sibling));
3040   g_return_if_fail (renderer != sibling);
3041   g_return_if_fail (gtk_cell_area_has_renderer (area, renderer));
3042   g_return_if_fail (gtk_cell_area_has_renderer (area, sibling));
3043   g_return_if_fail (!gtk_cell_area_is_focus_sibling (area, renderer, sibling));
3044
3045   /* XXX We should also check that sibling is not in any other renderer's sibling
3046    * list already, a renderer can be sibling of only one focusable renderer
3047    * at a time.
3048    */
3049
3050   priv = area->priv;
3051
3052   siblings = g_hash_table_lookup (priv->focus_siblings, renderer);
3053
3054   if (siblings)
3055     siblings = g_list_append (siblings, sibling);
3056   else
3057     {
3058       siblings = g_list_append (siblings, sibling);
3059       g_hash_table_insert (priv->focus_siblings, renderer, siblings);
3060     }
3061 }
3062
3063 /**
3064  * gtk_cell_area_remove_focus_sibling:
3065  * @area: a #GtkCellArea
3066  * @renderer: the #GtkCellRenderer expected to have focus
3067  * @sibling: the #GtkCellRenderer to remove from @renderer's focus area
3068  * 
3069  * Removes @sibling from @renderer's focus sibling list 
3070  * (see gtk_cell_area_add_focus_sibling()).
3071  *
3072  * Since: 3.0
3073  */
3074 void
3075 gtk_cell_area_remove_focus_sibling (GtkCellArea     *area,
3076                                     GtkCellRenderer *renderer,
3077                                     GtkCellRenderer *sibling)
3078 {
3079   GtkCellAreaPrivate *priv;
3080   GList              *siblings;
3081
3082   g_return_if_fail (GTK_IS_CELL_AREA (area));
3083   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
3084   g_return_if_fail (GTK_IS_CELL_RENDERER (sibling));
3085   g_return_if_fail (gtk_cell_area_is_focus_sibling (area, renderer, sibling));
3086
3087   priv = area->priv;
3088
3089   siblings = g_hash_table_lookup (priv->focus_siblings, renderer);
3090
3091   siblings = g_list_copy (siblings);
3092   siblings = g_list_remove (siblings, sibling);
3093
3094   if (!siblings)
3095     g_hash_table_remove (priv->focus_siblings, renderer);
3096   else
3097     g_hash_table_insert (priv->focus_siblings, renderer, siblings);
3098 }
3099
3100 /**
3101  * gtk_cell_area_is_focus_sibling:
3102  * @area: a #GtkCellArea
3103  * @renderer: the #GtkCellRenderer expected to have focus
3104  * @sibling: the #GtkCellRenderer to check against @renderer's sibling list
3105  * 
3106  * Returns %TRUE if @sibling is one of @renderer's focus siblings
3107  * (see gtk_cell_area_add_focus_sibling()).
3108  *
3109  * Since: 3.0
3110  */
3111 gboolean
3112 gtk_cell_area_is_focus_sibling (GtkCellArea     *area,
3113                                 GtkCellRenderer *renderer,
3114                                 GtkCellRenderer *sibling)
3115 {
3116   GtkCellAreaPrivate *priv;
3117   GList              *siblings, *l;
3118
3119   g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
3120   g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
3121   g_return_val_if_fail (GTK_IS_CELL_RENDERER (sibling), FALSE);
3122
3123   priv = area->priv;
3124
3125   siblings = g_hash_table_lookup (priv->focus_siblings, renderer);
3126
3127   for (l = siblings; l; l = l->next)
3128     {
3129       GtkCellRenderer *a_sibling = l->data;
3130
3131       if (a_sibling == sibling)
3132         return TRUE;
3133     }
3134
3135   return FALSE;
3136 }
3137
3138 /**
3139  * gtk_cell_area_get_focus_siblings:
3140  * @area: a #GtkCellArea
3141  * @renderer: the #GtkCellRenderer expected to have focus
3142  *
3143  * Gets the focus sibling cell renderers for @renderer.
3144  *
3145  * Return value: (element-type GtkCellRenderer) (transfer none): A #GList of #GtkCellRenderers. 
3146  *       The returned list is internal and should not be freed.
3147  *
3148  * Since: 3.0
3149  */
3150 const GList *
3151 gtk_cell_area_get_focus_siblings (GtkCellArea     *area,
3152                                   GtkCellRenderer *renderer)
3153 {
3154   GtkCellAreaPrivate *priv;
3155
3156   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
3157   g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), NULL);
3158
3159   priv = area->priv;
3160
3161   return g_hash_table_lookup (priv->focus_siblings, renderer);  
3162 }
3163
3164 /**
3165  * gtk_cell_area_get_focus_from_sibling:
3166  * @area: a #GtkCellArea
3167  * @renderer: the #GtkCellRenderer
3168  *
3169  * Gets the #GtkCellRenderer which is expected to be focusable
3170  * for which @renderer is, or may be a sibling.
3171  *
3172  * This is handy for #GtkCellArea subclasses when handling events,
3173  * after determining the renderer at the event location it can
3174  * then chose to activate the focus cell for which the event
3175  * cell may have been a sibling.
3176  *
3177  * Return value: the #GtkCellRenderer for which @renderer is a sibling, or %NULL.
3178  *
3179  * Since: 3.0
3180  */
3181 GtkCellRenderer *
3182 gtk_cell_area_get_focus_from_sibling (GtkCellArea          *area,
3183                                       GtkCellRenderer      *renderer)
3184 {
3185   GtkCellRenderer *ret_renderer = NULL;
3186   GList           *renderers, *l;
3187
3188   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
3189   g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), NULL);
3190
3191   renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (area));
3192
3193   for (l = renderers; l; l = l->next)
3194     {
3195       GtkCellRenderer *a_renderer = l->data;
3196       const GList     *list;
3197
3198       for (list = gtk_cell_area_get_focus_siblings (area, a_renderer); 
3199            list; list = list->next)
3200         {
3201           GtkCellRenderer *sibling_renderer = list->data;
3202
3203           if (sibling_renderer == renderer)
3204             {
3205               ret_renderer = a_renderer;
3206               break;
3207             }
3208         }
3209     }
3210   g_list_free (renderers);
3211
3212   return ret_renderer;
3213 }
3214
3215 /*************************************************************
3216  *              API: Cell Activation/Editing                 *
3217  *************************************************************/
3218 static void
3219 gtk_cell_area_add_editable (GtkCellArea        *area,
3220                             GtkCellRenderer    *renderer,
3221                             GtkCellEditable    *editable,
3222                             const GdkRectangle *cell_area)
3223 {
3224   g_signal_emit (area, cell_area_signals[SIGNAL_ADD_EDITABLE], 0, 
3225                  renderer, editable, cell_area, area->priv->current_path);
3226 }
3227
3228 static void
3229 gtk_cell_area_remove_editable  (GtkCellArea        *area,
3230                                 GtkCellRenderer    *renderer,
3231                                 GtkCellEditable    *editable)
3232 {
3233   g_signal_emit (area, cell_area_signals[SIGNAL_REMOVE_EDITABLE], 0, renderer, editable);
3234 }
3235
3236 static void
3237 cell_area_remove_widget_cb (GtkCellEditable *editable,
3238                             GtkCellArea     *area)
3239 {
3240   GtkCellAreaPrivate *priv = area->priv;
3241
3242   g_assert (priv->edit_widget == editable);
3243   g_assert (priv->edited_cell != NULL);
3244
3245   gtk_cell_area_remove_editable (area, priv->edited_cell, priv->edit_widget);
3246
3247   /* Now that we're done with editing the widget and it can be removed,
3248    * remove our references to the widget and disconnect handlers */
3249   gtk_cell_area_set_edited_cell (area, NULL);
3250   gtk_cell_area_set_edit_widget (area, NULL);
3251 }
3252
3253 static void
3254 gtk_cell_area_set_edited_cell (GtkCellArea     *area,
3255                                GtkCellRenderer *renderer)
3256 {
3257   GtkCellAreaPrivate *priv;
3258
3259   g_return_if_fail (GTK_IS_CELL_AREA (area));
3260   g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer));
3261
3262   priv = area->priv;
3263
3264   if (priv->edited_cell != renderer)
3265     {
3266       if (priv->edited_cell)
3267         g_object_unref (priv->edited_cell);
3268
3269       priv->edited_cell = renderer;
3270
3271       if (priv->edited_cell)
3272         g_object_ref (priv->edited_cell);
3273
3274       g_object_notify (G_OBJECT (area), "edited-cell");
3275     }
3276 }
3277
3278 static void
3279 gtk_cell_area_set_edit_widget (GtkCellArea     *area,
3280                                GtkCellEditable *editable)
3281 {
3282   GtkCellAreaPrivate *priv;
3283
3284   g_return_if_fail (GTK_IS_CELL_AREA (area));
3285   g_return_if_fail (editable == NULL || GTK_IS_CELL_EDITABLE (editable));
3286
3287   priv = area->priv;
3288
3289   if (priv->edit_widget != editable)
3290     {
3291       if (priv->edit_widget)
3292         {
3293           g_signal_handler_disconnect (priv->edit_widget, priv->remove_widget_id);
3294
3295           g_object_unref (priv->edit_widget);
3296         }
3297
3298       priv->edit_widget = editable;
3299
3300       if (priv->edit_widget)
3301         {
3302           priv->remove_widget_id =
3303             g_signal_connect (priv->edit_widget, "remove-widget",
3304                               G_CALLBACK (cell_area_remove_widget_cb), area);
3305
3306           g_object_ref (priv->edit_widget);
3307         }
3308
3309       g_object_notify (G_OBJECT (area), "edit-widget");
3310     }
3311 }
3312
3313 /**
3314  * gtk_cell_area_get_edited_cell:
3315  * @area: a #GtkCellArea
3316  *
3317  * Gets the #GtkCellRenderer in @area that is currently
3318  * being edited.
3319  *
3320  * Return value: The currently edited #GtkCellRenderer
3321  *
3322  * Since: 3.0
3323  */
3324 GtkCellRenderer   *
3325 gtk_cell_area_get_edited_cell (GtkCellArea *area)
3326 {
3327   GtkCellAreaPrivate *priv;
3328
3329   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
3330
3331   priv = area->priv;
3332
3333   return priv->edited_cell;
3334 }
3335
3336 /**
3337  * gtk_cell_area_get_edit_widget:
3338  * @area: a #GtkCellArea
3339  *
3340  * Gets the #GtkCellEditable widget currently used
3341  * to edit the currently edited cell.
3342  *
3343  * Return value: The currently active #GtkCellEditable widget
3344  *
3345  * Since: 3.0
3346  */
3347 GtkCellEditable *
3348 gtk_cell_area_get_edit_widget (GtkCellArea *area)
3349 {
3350   GtkCellAreaPrivate *priv;
3351
3352   g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
3353
3354   priv = area->priv;
3355
3356   return priv->edit_widget;
3357 }
3358
3359 /**
3360  * gtk_cell_area_activate_cell:
3361  * @area: a #GtkCellArea
3362  * @widget: the #GtkWidget that @area is rendering onto
3363  * @renderer: the #GtkCellRenderer in @area to activate
3364  * @event: the #GdkEvent for which cell activation should occur
3365  * @cell_area: the #GdkRectangle in @widget relative coordinates
3366  *             of @renderer for the current row.
3367  * @flags: the #GtkCellRendererState for @renderer
3368  *
3369  * This is used by #GtkCellArea subclasses when handling events
3370  * to activate cells, the base #GtkCellArea class activates cells
3371  * for keyboard events for free in it's own GtkCellArea->activate()
3372  * implementation.
3373  *
3374  * Return value: whether cell activation was successful
3375  *
3376  * Since: 3.0
3377  */
3378 gboolean
3379 gtk_cell_area_activate_cell (GtkCellArea          *area,
3380                              GtkWidget            *widget,
3381                              GtkCellRenderer      *renderer,
3382                              GdkEvent             *event,
3383                              const GdkRectangle   *cell_area,
3384                              GtkCellRendererState  flags)
3385 {
3386   GtkCellRendererMode mode;
3387   GtkCellAreaPrivate *priv;
3388   
3389   g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
3390   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
3391   g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
3392   g_return_val_if_fail (cell_area != NULL, FALSE);
3393
3394   priv = area->priv;
3395
3396   g_object_get (renderer, "mode", &mode, NULL);
3397
3398   if (mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
3399     {
3400       if (gtk_cell_renderer_activate (renderer,
3401                                       event, widget,
3402                                       priv->current_path,
3403                                       cell_area,
3404                                       cell_area,
3405                                       flags))
3406         return TRUE;
3407     }
3408   else if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
3409     {
3410       GtkCellEditable *editable_widget;
3411       
3412       editable_widget =
3413         gtk_cell_renderer_start_editing (renderer,
3414                                          event, widget,
3415                                          priv->current_path,
3416                                          cell_area,
3417                                          cell_area,
3418                                          flags);
3419       
3420       if (editable_widget != NULL)
3421         {
3422           g_return_val_if_fail (GTK_IS_CELL_EDITABLE (editable_widget), FALSE);
3423           
3424           gtk_cell_area_set_edited_cell (area, renderer);
3425           gtk_cell_area_set_edit_widget (area, editable_widget);
3426           
3427           /* Signal that editing started so that callers can get 
3428            * a handle on the editable_widget */
3429           gtk_cell_area_add_editable (area, priv->focus_cell, editable_widget, cell_area);
3430
3431           /* If the signal was successfully handled start the editing */
3432           if (gtk_widget_get_parent (GTK_WIDGET (editable_widget)))
3433             {
3434               gtk_cell_editable_start_editing (editable_widget, NULL);
3435               gtk_widget_grab_focus (GTK_WIDGET (editable_widget));
3436             }
3437           else
3438             {
3439               /* Otherwise clear the editing state and fire a warning */
3440               gtk_cell_area_set_edited_cell (area, NULL);
3441               gtk_cell_area_set_edit_widget (area, NULL);
3442
3443               g_warning ("GtkCellArea::add-editable fired in the dark, no cell editing was started.");
3444             }
3445           
3446           return TRUE;
3447         }
3448     }
3449
3450   return FALSE;
3451 }
3452
3453 /**
3454  * gtk_cell_area_stop_editing:
3455  * @area: a #GtkCellArea
3456  * @canceled: whether editing was canceled.
3457  *
3458  * Explicitly stops the editing of the currently
3459  * edited cell (see gtk_cell_area_get_edited_cell()).
3460  *
3461  * If @canceled is %TRUE, the cell renderer will emit
3462  * the ::editing-canceled signal.
3463  *
3464  * Since: 3.0
3465  */
3466 void
3467 gtk_cell_area_stop_editing (GtkCellArea *area,
3468                             gboolean     canceled)
3469 {
3470   GtkCellAreaPrivate *priv;
3471
3472   g_return_if_fail (GTK_IS_CELL_AREA (area));
3473
3474   priv = area->priv;
3475
3476   if (priv->edited_cell)
3477     {
3478       GtkCellEditable *edit_widget = g_object_ref (priv->edit_widget);
3479       GtkCellRenderer *edit_cell   = g_object_ref (priv->edited_cell);
3480
3481       /* Stop editing of the cell renderer */
3482       gtk_cell_renderer_stop_editing (priv->edited_cell, canceled);
3483       
3484       /* Remove any references to the editable widget */
3485       gtk_cell_area_set_edited_cell (area, NULL);
3486       gtk_cell_area_set_edit_widget (area, NULL);
3487
3488       /* Send the remove-widget signal explicitly (this is done after setting
3489        * the edit cell/widget NULL to avoid feedback)
3490        */
3491       gtk_cell_area_remove_editable (area, edit_cell, edit_widget);
3492       g_object_unref (edit_cell);
3493       g_object_unref (edit_widget);
3494     }
3495 }
3496
3497 /*************************************************************
3498  *         API: Convenience for area implementations         *
3499  *************************************************************/
3500
3501 /**
3502  * gtk_cell_area_inner_cell_area:
3503  * @area: a #GtkCellArea
3504  * @widget: the #GtkWidget that @area is rendering onto
3505  * @cell_area: the @widget relative coordinates where one of @area's cells 
3506  *             is to be placed
3507  * @inner_area: (out): the return location for the inner cell area
3508  *
3509  * This is a convenience function for #GtkCellArea implementations
3510  * to get the inner area where a given #GtkCellRenderer will be
3511  * rendered. It removes any padding previously added by gtk_cell_area_request_renderer().
3512  *
3513  * Since: 3.0
3514  */
3515 void
3516 gtk_cell_area_inner_cell_area (GtkCellArea        *area,
3517                                GtkWidget          *widget,
3518                                const GdkRectangle *cell_area,
3519                                GdkRectangle       *inner_area)
3520 {
3521   gint focus_line_width;
3522
3523   g_return_if_fail (GTK_IS_CELL_AREA (area));
3524   g_return_if_fail (GTK_IS_WIDGET (widget));
3525   g_return_if_fail (cell_area != NULL);
3526   g_return_if_fail (inner_area != NULL);
3527
3528   gtk_widget_style_get (widget, "focus-line-width", &focus_line_width, NULL);
3529
3530   *inner_area = *cell_area;
3531
3532   inner_area->x      += focus_line_width;
3533   inner_area->width  -= focus_line_width * 2;
3534   inner_area->y      += focus_line_width;
3535   inner_area->height -= focus_line_width * 2;
3536 }
3537
3538 /**
3539  * gtk_cell_area_request_renderer:
3540  * @area: a #GtkCellArea
3541  * @renderer: the #GtkCellRenderer to request size for
3542  * @orientation: the #GtkOrientation in which to request size
3543  * @widget: the #GtkWidget that @area is rendering onto
3544  * @for_size: the allocation contextual size to request for, or -1 if
3545  * the base request for the orientation is to be returned.
3546  * @minimum_size: (out) (allow-none): location to store the minimum size, or %NULL
3547  * @natural_size: (out) (allow-none): location to store the natural size, or %NULL
3548  *
3549  * This is a convenience function for #GtkCellArea implementations
3550  * to request size for cell renderers. It's important to use this
3551  * function to request size and then use gtk_cell_area_inner_cell_area()
3552  * at render and event time since this function will add padding
3553  * around the cell for focus painting.
3554  *
3555  * Since: 3.0
3556  */
3557 void
3558 gtk_cell_area_request_renderer (GtkCellArea        *area,
3559                                 GtkCellRenderer    *renderer,
3560                                 GtkOrientation      orientation,
3561                                 GtkWidget          *widget,
3562                                 gint                for_size,
3563                                 gint               *minimum_size,
3564                                 gint               *natural_size)
3565 {
3566   GtkCellAreaPrivate *priv;
3567   gint                focus_line_width;
3568
3569   g_return_if_fail (GTK_IS_CELL_AREA (area));
3570   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
3571   g_return_if_fail (GTK_IS_WIDGET (widget));
3572   g_return_if_fail (minimum_size != NULL);
3573   g_return_if_fail (natural_size != NULL);
3574
3575   priv = area->priv;
3576
3577   gtk_widget_style_get (widget, "focus-line-width", &focus_line_width, NULL);
3578
3579   focus_line_width *= 2;
3580
3581   if (orientation == GTK_ORIENTATION_HORIZONTAL)
3582     {
3583       if (for_size < 0)
3584           gtk_cell_renderer_get_preferred_width (renderer, widget, minimum_size, natural_size);
3585       else
3586         {
3587           for_size = MAX (0, for_size - focus_line_width);
3588
3589           gtk_cell_renderer_get_preferred_width_for_height (renderer, widget, for_size, 
3590                                                             minimum_size, natural_size);
3591         }
3592     }
3593   else /* GTK_ORIENTATION_VERTICAL */
3594     {
3595       if (for_size < 0)
3596         gtk_cell_renderer_get_preferred_height (renderer, widget, minimum_size, natural_size);
3597       else
3598         {
3599           for_size = MAX (0, for_size - focus_line_width);
3600
3601           gtk_cell_renderer_get_preferred_height_for_width (renderer, widget, for_size, 
3602                                                             minimum_size, natural_size);
3603         }
3604     }
3605
3606   *minimum_size += focus_line_width;
3607   *natural_size += focus_line_width;
3608 }