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