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