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