3 * Copyright (C) 2010 Openismus GmbH
6 * Tristan Van Berkom <tristanvb@openismus.com>
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.
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.
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.
26 * @Short_Description: An abstract class for laying out GtkCellRenderers
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.
34 * The cell area handles events, focus navigation, drawing and
35 * size requests and allocations for a given row of data.
37 * Usually users dont have to interact with the #GtkCellArea directly
38 * unless they are implementing a cell-layouting widget themselves.
40 * <refsect2 id="cell-area-geometry-management">
41 * <title>Requesting area sizes</title>
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.
49 * When requesting the size of a cell area one needs to calculate
50 * the size for a handful of rows, and 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.
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).
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.
75 * In order to request the width of all the rows at the root level
76 * of a #GtkTreeModel one would do the following:
78 * <title>Requesting the width of a handful of GtkTreeModel rows</title>
84 * valid = gtk_tree_model_get_iter_first (model, &iter);
87 * gtk_cell_area_apply_attributes (area, model, &iter, FALSE, FALSE);
88 * gtk_cell_area_get_preferred_width (area, context, widget, NULL, NULL);
90 * valid = gtk_tree_model_iter_next (model, &iter);
92 * gtk_cell_area_context_get_preferred_width (context, &minimum_width, &natural_width);
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
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.
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:
114 * <title>A typical get_preferred_width() implementation</title>
117 * foo_get_preferred_width (GtkWidget *widget,
118 * gint *minimum_size,
119 * gint *natural_size)
121 * Foo *foo = FOO (widget);
122 * FooPrivate *priv = foo->priv;
124 * foo_ensure_at_least_one_handfull_of_rows_have_been_requested (foo);
126 * gtk_cell_area_context_get_preferred_width (priv->context, minimum_size, natural_size);
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.
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).
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:
146 * <title>Requesting the height for width of a handful of GtkTreeModel rows</title>
149 * gint minimum_height;
150 * gint natural_height;
151 * gint full_minimum_height = 0;
152 * gint full_natural_height = 0;
154 * valid = gtk_tree_model_get_iter_first (model, &iter);
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);
161 * if (width_is_for_allocation)
162 * cache_row_height (&iter, minimum_height, natural_height);
164 * full_minimum_height += minimum_height;
165 * full_natural_height += natural_height;
167 * valid = gtk_tree_model_iter_next (model, &iter);
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
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.
193 * <refsect2 id="cell-area-rendering">
194 * <title>Rendering Areas</title>
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.
200 * A crude example of how to render all the rows at the root level
203 * <title>Requesting the width of a handful of GtkTreeModel rows</title>
205 * GtkAllocation allocation;
206 * GdkRectangle cell_area = { 0, };
208 * gint minimum_width;
209 * gint natural_width;
211 * gtk_widget_get_allocation (widget, &allocation);
212 * cell_area.width = allocation.width;
214 * valid = gtk_tree_model_get_iter_first (model, &iter);
217 * cell_area.height = get_cached_height_for_row (&iter);
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);
223 * cell_area.y += cell_area.height;
225 * valid = gtk_tree_model_iter_next (model, &iter);
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 its 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().
237 * <refsect2 id="cell-area-events-and-focus">
238 * <title>Handling Events and Driving Keyboard Focus</title>
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.
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.
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
265 * A basic example of how the #GtkWidgetClass.focus() virtual method
266 * should be implemented:
268 * <title>Implementing keyboard focus navigation</title>
271 * foo_focus (GtkWidget *widget,
272 * GtkDirectionType direction)
274 * Foo *foo = FOO (widget);
275 * FooPrivate *priv = foo->priv;
277 * gboolean have_focus = FALSE;
279 * focus_row = priv->focus_row;
281 * if (!gtk_widget_has_focus (widget))
282 * gtk_widget_grab_focus (widget);
284 * valid = gtk_tree_model_iter_nth_child (priv->model, &iter, NULL, priv->focus_row);
287 * gtk_cell_area_apply_attributes (priv->area, priv->model, &iter, FALSE, FALSE);
289 * if (gtk_cell_area_focus (priv->area, direction))
291 * priv->focus_row = focus_row;
297 * if (direction == GTK_DIR_RIGHT ||
298 * direction == GTK_DIR_LEFT)
300 * else if (direction == GTK_DIR_UP ||
301 * direction == GTK_DIR_TAB_BACKWARD)
303 * if (focus_row == 0)
308 * valid = gtk_tree_model_iter_nth_child (priv->model, &iter, NULL, focus_row);
313 * if (focus_row == last_row)
318 * valid = gtk_tree_model_iter_next (priv->model, &iter);
327 * Note that the layouting widget is responsible for matching the
328 * GtkDirectionType values to the way it lays out its cells.
331 * <refsect2 id="cell-properties">
332 * <title>Cell Properties</title>
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 its 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.
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.
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().
364 #include "gtkcelllayout.h"
365 #include "gtkcellarea.h"
366 #include "gtkcellareacontext.h"
367 #include "gtkmarshalers.h"
368 #include "gtkprivate.h"
370 #include <gobject/gvaluecollector.h>
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,
380 static void gtk_cell_area_get_property (GObject *object,
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,
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,
404 const GdkRectangle *cell_area,
405 GtkCellRendererState flags);
406 static void gtk_cell_area_real_render (GtkCellArea *area,
407 GtkCellAreaContext *context,
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,
417 gboolean is_expander,
418 gboolean is_expanded);
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,
428 gint *natural_width);
429 static void gtk_cell_area_real_get_preferred_height (GtkCellArea *area,
430 GtkCellAreaContext *context,
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,
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,
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,
450 const GdkRectangle *cell_area,
451 GtkCellRendererState flags,
453 static gboolean gtk_cell_area_real_focus (GtkCellArea *area,
454 GtkDirectionType direction);
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,
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,
466 static void gtk_cell_area_set_cell_data_func (GtkCellLayout *cell_layout,
467 GtkCellRenderer *cell,
468 GtkCellLayoutDataFunc func,
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,
476 static GList *gtk_cell_area_get_cells (GtkCellLayout *cell_layout);
477 static GtkCellArea *gtk_cell_area_get_area (GtkCellLayout *cell_layout);
479 /* GtkBuildableIface */
480 static void gtk_cell_area_buildable_init (GtkBuildableIface *iface);
481 static void gtk_cell_area_buildable_custom_tag_end (GtkBuildable *buildable,
484 const gchar *tagname,
487 /* Used in foreach loop to check if a child renderer is present */
489 GtkCellRenderer *renderer;
490 gboolean has_renderer;
493 /* Used in foreach loop to get a cell's allocation */
495 GtkCellRenderer *renderer;
496 GdkRectangle allocation;
497 } RendererAllocationData;
499 /* Used in foreach loop to render cells */
504 GdkRectangle focus_rect;
505 GtkCellRendererState render_flags;
506 guint paint_focus : 1;
508 guint first_focus : 1;
511 /* Used in foreach loop to get a cell by position */
515 GtkCellRenderer *renderer;
516 GdkRectangle cell_area;
517 } CellByPositionData;
519 /* Attribute/Cell metadata */
521 const gchar *attribute;
528 GtkCellLayoutDataFunc func;
530 GDestroyNotify destroy;
531 GtkCellLayout *proxy;
534 static CellInfo *cell_info_new (GtkCellLayoutDataFunc func,
536 GDestroyNotify destroy);
537 static void cell_info_free (CellInfo *info);
538 static CellAttribute *cell_attribute_new (GtkCellRenderer *renderer,
539 const gchar *attribute,
541 static void cell_attribute_free (CellAttribute *attribute);
542 static gint cell_attribute_find (CellAttribute *cell_attribute,
543 const gchar *attribute);
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);
559 /* Struct to pass data along while looping over
560 * cell renderers to apply attributes
566 gboolean is_expander;
567 gboolean is_expanded;
570 struct _GtkCellAreaPrivate
572 /* The GtkCellArea bookkeeps any connected
573 * attributes in this hash table.
575 GHashTable *cell_info;
577 /* Current path is saved as a side-effect
578 * of gtk_cell_area_apply_attributes()
582 /* Current cell being edited and editable widget used */
583 GtkCellEditable *edit_widget;
584 GtkCellRenderer *edited_cell;
586 /* Signal connections to the editable widget */
587 gulong remove_widget_id;
589 /* Currently focused cell */
590 GtkCellRenderer *focus_cell;
592 /* Tracking which cells are focus siblings of focusable cells */
593 GHashTable *focus_siblings;
604 SIGNAL_APPLY_ATTRIBUTES,
606 SIGNAL_REMOVE_EDITABLE,
607 SIGNAL_FOCUS_CHANGED,
611 /* Keep the paramspec pool internal, no need to deliver notifications
612 * on cells. at least no perceived need for now
614 static GParamSpecPool *cell_property_pool = NULL;
615 static guint cell_area_signals[LAST_SIGNAL] = { 0 };
617 #define PARAM_SPEC_PARAM_ID(pspec) ((pspec)->param_id)
618 #define PARAM_SPEC_SET_PARAM_ID(pspec, id) ((pspec)->param_id = (id))
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))
627 gtk_cell_area_init (GtkCellArea *area)
629 GtkCellAreaPrivate *priv;
631 area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area,
636 priv->cell_info = g_hash_table_new_full (g_direct_hash,
639 (GDestroyNotify)cell_info_free);
641 priv->focus_siblings = g_hash_table_new_full (g_direct_hash,
644 (GDestroyNotify)g_list_free);
646 priv->focus_cell = NULL;
647 priv->edited_cell = NULL;
648 priv->edit_widget = NULL;
650 priv->remove_widget_id = 0;
654 gtk_cell_area_class_init (GtkCellAreaClass *class)
656 GObjectClass *object_class = G_OBJECT_CLASS (class);
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;
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;
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;
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;
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
696 * This signal is emitted whenever applying attributes to @area from @model
700 cell_area_signals[SIGNAL_APPLY_ATTRIBUTES] =
701 g_signal_new (I_("apply-attributes"),
702 G_OBJECT_CLASS_TYPE (object_class),
704 G_STRUCT_OFFSET (GtkCellAreaClass, apply_attributes),
706 _gtk_marshal_VOID__OBJECT_BOXED_BOOLEAN_BOOLEAN,
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
722 * Indicates that editing has started on @renderer and that @editable
723 * should be added to the owning cell-layouting widget at @cell_area.
727 cell_area_signals[SIGNAL_ADD_EDITABLE] =
728 g_signal_new (I_("add-editable"),
729 G_OBJECT_CLASS_TYPE (object_class),
731 0, /* No class closure here */
733 _gtk_marshal_VOID__OBJECT_OBJECT_BOXED_STRING,
735 GTK_TYPE_CELL_RENDERER,
736 GTK_TYPE_CELL_EDITABLE,
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
747 * Indicates that editing finished on @renderer and that @editable
748 * should be removed from the owning cell-layouting widget.
752 cell_area_signals[SIGNAL_REMOVE_EDITABLE] =
753 g_signal_new (I_("remove-editable"),
754 G_OBJECT_CLASS_TYPE (object_class),
756 0, /* No class closure here */
758 _gtk_marshal_VOID__OBJECT_OBJECT,
760 GTK_TYPE_CELL_RENDERER,
761 GTK_TYPE_CELL_EDITABLE);
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
769 * Indicates that focus changed on this @area. This signal
770 * is emitted either as a result of focus handling or event
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.
780 cell_area_signals[SIGNAL_FOCUS_CHANGED] =
781 g_signal_new (I_("focus-changed"),
782 G_OBJECT_CLASS_TYPE (object_class),
784 0, /* No class closure here */
786 _gtk_marshal_VOID__OBJECT_STRING,
788 GTK_TYPE_CELL_RENDERER,
793 * GtkCellArea:focus-cell:
795 * The cell in the area that currently has focus
799 g_object_class_install_property (object_class,
804 P_("The cell which currently has focus"),
805 GTK_TYPE_CELL_RENDERER,
806 GTK_PARAM_READWRITE));
809 * GtkCellArea:edited-cell:
811 * The cell in the area that is currently edited
813 * This property is read-only and only changes as
814 * a result of a call gtk_cell_area_activate_cell().
818 g_object_class_install_property (object_class,
823 P_("The cell which is currently being edited"),
824 GTK_TYPE_CELL_RENDERER,
828 * GtkCellArea:edit-widget:
830 * The widget currently editing the edited cell
832 * This property is read-only and only changes as
833 * a result of a call gtk_cell_area_activate_cell().
837 g_object_class_install_property (object_class,
842 P_("The widget currently editing the edited cell"),
843 GTK_TYPE_CELL_EDITABLE,
846 /* Pool for Cell Properties */
847 if (!cell_property_pool)
848 cell_property_pool = g_param_spec_pool_new (FALSE);
850 g_type_class_add_private (object_class, sizeof (GtkCellAreaPrivate));
853 /*************************************************************
855 *************************************************************/
857 cell_info_new (GtkCellLayoutDataFunc func,
859 GDestroyNotify destroy)
861 CellInfo *info = g_slice_new0 (CellInfo);
865 info->destroy = destroy;
871 cell_info_free (CellInfo *info)
874 info->destroy (info->data);
876 g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
877 g_slist_free (info->attributes);
879 g_slice_free (CellInfo, info);
882 static CellAttribute *
883 cell_attribute_new (GtkCellRenderer *renderer,
884 const gchar *attribute,
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)
893 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (renderer), attribute);
897 CellAttribute *cell_attribute = g_slice_new (CellAttribute);
899 cell_attribute->attribute = pspec->name;
900 cell_attribute->column = column;
902 return cell_attribute;
909 cell_attribute_free (CellAttribute *attribute)
911 g_slice_free (CellAttribute, attribute);
914 /* GCompareFunc for g_slist_find_custom() */
916 cell_attribute_find (CellAttribute *cell_attribute,
917 const gchar *attribute)
919 return g_strcmp0 (cell_attribute->attribute, attribute);
922 /*************************************************************
924 *************************************************************/
926 gtk_cell_area_finalize (GObject *object)
928 GtkCellArea *area = GTK_CELL_AREA (object);
929 GtkCellAreaPrivate *priv = area->priv;
931 /* All cell renderers should already be removed at this point,
932 * just kill our (empty) hash tables here.
934 g_hash_table_destroy (priv->cell_info);
935 g_hash_table_destroy (priv->focus_siblings);
937 g_free (priv->current_path);
939 G_OBJECT_CLASS (gtk_cell_area_parent_class)->finalize (object);
944 gtk_cell_area_dispose (GObject *object)
946 /* This removes every cell renderer that may be added to the GtkCellArea,
947 * subclasses should be breaking references to the GtkCellRenderers
950 gtk_cell_layout_clear (GTK_CELL_LAYOUT (object));
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);
957 G_OBJECT_CLASS (gtk_cell_area_parent_class)->dispose (object);
961 gtk_cell_area_set_property (GObject *object,
966 GtkCellArea *area = GTK_CELL_AREA (object);
970 case PROP_FOCUS_CELL:
971 gtk_cell_area_set_focus_cell (area, (GtkCellRenderer *)g_value_get_object (value));
974 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
980 gtk_cell_area_get_property (GObject *object,
985 GtkCellArea *area = GTK_CELL_AREA (object);
986 GtkCellAreaPrivate *priv = area->priv;
990 case PROP_FOCUS_CELL:
991 g_value_set_object (value, priv->focus_cell);
993 case PROP_EDITED_CELL:
994 g_value_set_object (value, priv->edited_cell);
996 case PROP_EDIT_WIDGET:
997 g_value_set_object (value, priv->edit_widget);
1000 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1005 /*************************************************************
1006 * GtkCellAreaClass *
1007 *************************************************************/
1009 gtk_cell_area_real_add (GtkCellArea *area,
1010 GtkCellRenderer *renderer)
1012 g_warning ("GtkCellAreaClass::add not implemented for `%s'",
1013 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1017 gtk_cell_area_real_remove (GtkCellArea *area,
1018 GtkCellRenderer *renderer)
1020 g_warning ("GtkCellAreaClass::remove not implemented for `%s'",
1021 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1025 gtk_cell_area_real_foreach (GtkCellArea *area,
1026 GtkCellCallback callback,
1027 gpointer callback_data)
1029 g_warning ("GtkCellAreaClass::foreach not implemented for `%s'",
1030 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1034 gtk_cell_area_real_foreach_alloc (GtkCellArea *area,
1035 GtkCellAreaContext *context,
1037 const GdkRectangle *cell_area,
1038 const GdkRectangle *background_area,
1039 GtkCellAllocCallback callback,
1040 gpointer callback_data)
1042 g_warning ("GtkCellAreaClass::foreach_alloc not implemented for `%s'",
1043 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1047 gtk_cell_area_real_event (GtkCellArea *area,
1048 GtkCellAreaContext *context,
1051 const GdkRectangle *cell_area,
1052 GtkCellRendererState flags)
1054 GtkCellAreaPrivate *priv = area->priv;
1055 gboolean retval = FALSE;
1057 if (event->type == GDK_KEY_PRESS && (flags & GTK_CELL_RENDERER_FOCUSED) != 0)
1059 GdkEventKey *key_event = (GdkEventKey *)event;
1061 /* Cancel any edits in progress */
1062 if (priv->edited_cell && (key_event->keyval == GDK_KEY_Escape))
1064 gtk_cell_area_stop_editing (area, TRUE);
1068 else if (event->type == GDK_BUTTON_PRESS)
1070 GdkEventButton *button_event = (GdkEventButton *)event;
1072 if (button_event->button == 1)
1074 GtkCellRenderer *renderer = NULL;
1075 GtkCellRenderer *focus_renderer;
1076 GdkRectangle alloc_area;
1077 gint event_x, event_y;
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;
1084 /* Dont try to search for an event coordinate that is not in the area, that will
1085 * trigger a runtime warning.
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)
1090 gtk_cell_area_get_cell_at_position (area, context, widget,
1091 cell_area, event_x, event_y,
1096 focus_renderer = gtk_cell_area_get_focus_from_sibling (area, renderer);
1097 if (!focus_renderer)
1098 focus_renderer = renderer;
1100 /* If we're already editing, cancel it and set focus */
1101 if (gtk_cell_area_get_edited_cell (area))
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);
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);
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);
1128 render_cell (GtkCellRenderer *renderer,
1129 const GdkRectangle *cell_area,
1130 const GdkRectangle *cell_background,
1131 CellRenderData *data)
1133 GtkCellRenderer *focus_cell;
1134 GtkCellRendererState flags;
1135 GdkRectangle inner_area;
1137 focus_cell = gtk_cell_area_get_focus_cell (data->area);
1138 flags = data->render_flags;
1140 gtk_cell_area_inner_cell_area (data->area, data->widget, cell_area, &inner_area);
1142 if ((flags & GTK_CELL_RENDERER_FOCUSED) &&
1145 (renderer == focus_cell ||
1146 gtk_cell_area_is_focus_sibling (data->area, focus_cell, renderer)))))
1148 gint focus_line_width;
1149 GdkRectangle cell_focus;
1151 gtk_cell_renderer_get_aligned_area (renderer, data->widget, flags, &inner_area, &cell_focus);
1153 gtk_widget_style_get (data->widget,
1154 "focus-line-width", &focus_line_width,
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;
1163 if (data->first_focus)
1165 data->first_focus = FALSE;
1166 data->focus_rect = cell_focus;
1170 gdk_rectangle_union (&data->focus_rect, &cell_focus, &data->focus_rect);
1174 gtk_cell_renderer_render (renderer, data->cr, data->widget,
1175 cell_background, &inner_area, flags);
1181 gtk_cell_area_real_render (GtkCellArea *area,
1182 GtkCellAreaContext *context,
1185 const GdkRectangle *background_area,
1186 const GdkRectangle *cell_area,
1187 GtkCellRendererState flags,
1188 gboolean paint_focus)
1190 CellRenderData render_data =
1201 /* Make sure we dont paint a focus rectangle while there
1202 * is an editable widget in play
1204 if (gtk_cell_area_get_edited_cell (area))
1205 render_data.paint_focus = FALSE;
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;
1213 gtk_cell_area_foreach_alloc (area, context, widget, cell_area, background_area,
1214 (GtkCellAllocCallback)render_cell, &render_data);
1216 if (render_data.paint_focus &&
1217 render_data.focus_rect.width != 0 &&
1218 render_data.focus_rect.height != 0)
1220 GtkStyleContext *style_context;
1221 GtkStateFlags renderer_state = 0;
1223 style_context = gtk_widget_get_style_context (widget);
1224 gtk_style_context_save (style_context);
1226 renderer_state = gtk_cell_renderer_get_state (NULL, widget, flags);
1227 gtk_style_context_set_state (style_context, renderer_state);
1231 gdk_cairo_rectangle (cr, background_area);
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);
1238 gtk_style_context_restore (style_context);
1244 apply_cell_attributes (GtkCellRenderer *renderer,
1246 AttributeData *data)
1248 CellAttribute *attribute;
1250 GValue value = { 0, };
1251 gboolean is_expander;
1252 gboolean is_expanded;
1254 g_object_freeze_notify (G_OBJECT (renderer));
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).
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);
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);
1268 /* Apply the attributes directly to the renderer */
1269 for (list = info->attributes; list; list = list->next)
1271 attribute = list->data;
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);
1278 /* Call any GtkCellLayoutDataFunc that may have been set by the user
1281 info->func (info->proxy ? info->proxy : GTK_CELL_LAYOUT (data->area), renderer,
1282 data->model, data->iter, info->data);
1284 g_object_thaw_notify (G_OBJECT (renderer));
1288 gtk_cell_area_real_apply_attributes (GtkCellArea *area,
1289 GtkTreeModel *tree_model,
1291 gboolean is_expander,
1292 gboolean is_expanded)
1295 GtkCellAreaPrivate *priv;
1301 /* Feed in data needed to apply to every renderer */
1303 data.model = tree_model;
1305 data.is_expander = is_expander;
1306 data.is_expanded = is_expanded;
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);
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);
1319 static GtkCellAreaContext *
1320 gtk_cell_area_real_create_context (GtkCellArea *area)
1322 g_warning ("GtkCellAreaClass::create_context not implemented for `%s'",
1323 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1328 static GtkCellAreaContext *
1329 gtk_cell_area_real_copy_context (GtkCellArea *area,
1330 GtkCellAreaContext *context)
1332 g_warning ("GtkCellAreaClass::copy_context not implemented for `%s'",
1333 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1338 static GtkSizeRequestMode
1339 gtk_cell_area_real_get_request_mode (GtkCellArea *area)
1341 /* By default cell areas are height-for-width. */
1342 return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
1346 gtk_cell_area_real_get_preferred_width (GtkCellArea *area,
1347 GtkCellAreaContext *context,
1349 gint *minimum_width,
1350 gint *natural_width)
1352 g_warning ("GtkCellAreaClass::get_preferred_width not implemented for `%s'",
1353 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1357 gtk_cell_area_real_get_preferred_height (GtkCellArea *area,
1358 GtkCellAreaContext *context,
1360 gint *minimum_height,
1361 gint *natural_height)
1363 g_warning ("GtkCellAreaClass::get_preferred_height not implemented for `%s'",
1364 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1368 gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area,
1369 GtkCellAreaContext *context,
1372 gint *minimum_height,
1373 gint *natural_height)
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);
1380 gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area,
1381 GtkCellAreaContext *context,
1384 gint *minimum_width,
1385 gint *natural_width)
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);
1392 get_is_activatable (GtkCellRenderer *renderer,
1393 gboolean *activatable)
1396 if (gtk_cell_renderer_is_activatable (renderer))
1397 *activatable = TRUE;
1399 return *activatable;
1403 gtk_cell_area_real_is_activatable (GtkCellArea *area)
1405 gboolean activatable = FALSE;
1407 /* Checks if any renderer can focus for the currently applied
1410 * Subclasses can override this in the case that they are also
1411 * rendering widgets as well as renderers.
1413 gtk_cell_area_foreach (area, (GtkCellCallback)get_is_activatable, &activatable);
1419 gtk_cell_area_real_activate (GtkCellArea *area,
1420 GtkCellAreaContext *context,
1422 const GdkRectangle *cell_area,
1423 GtkCellRendererState flags,
1426 GtkCellAreaPrivate *priv = area->priv;
1427 GdkRectangle renderer_area;
1428 GtkCellRenderer *activate_cell = NULL;
1429 GtkCellRendererMode mode;
1431 if (priv->focus_cell)
1433 g_object_get (priv->focus_cell, "mode", &mode, NULL);
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;
1444 /* GtkTreeView sometimes wants to activate a cell when no
1445 * cells are in focus.
1447 cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (area));
1448 for (l = cells; l && !activate_cell; l = l->next)
1450 GtkCellRenderer *renderer = l->data;
1452 g_object_get (renderer, "mode", &mode, NULL);
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;
1459 g_list_free (cells);
1464 /* Get the allocation of the focused cell.
1466 gtk_cell_area_get_cell_allocation (area, context, widget, activate_cell,
1467 cell_area, &renderer_area);
1469 /* Activate or Edit the cell
1471 * Currently just not sending an event, renderers afaics dont use
1472 * the event argument anyway, worst case is we can synthesize one.
1474 if (gtk_cell_area_activate_cell (area, widget, activate_cell, NULL,
1475 &renderer_area, flags))
1483 gtk_cell_area_real_focus (GtkCellArea *area,
1484 GtkDirectionType direction)
1486 g_warning ("GtkCellAreaClass::focus not implemented for `%s'",
1487 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1491 /*************************************************************
1492 * GtkCellLayoutIface *
1493 *************************************************************/
1495 gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface)
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;
1509 gtk_cell_area_pack_default (GtkCellLayout *cell_layout,
1510 GtkCellRenderer *renderer,
1513 gtk_cell_area_add (GTK_CELL_AREA (cell_layout), renderer);
1517 gtk_cell_area_clear (GtkCellLayout *cell_layout)
1519 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
1521 gtk_cell_layout_get_cells (cell_layout);
1523 for (l = cells; l; l = l->next)
1525 GtkCellRenderer *renderer = l->data;
1526 gtk_cell_area_remove (area, renderer);
1529 g_list_free (cells);
1533 gtk_cell_area_add_attribute (GtkCellLayout *cell_layout,
1534 GtkCellRenderer *renderer,
1535 const gchar *attribute,
1538 gtk_cell_area_attribute_connect (GTK_CELL_AREA (cell_layout),
1539 renderer, attribute, column);
1543 gtk_cell_area_set_cell_data_func (GtkCellLayout *cell_layout,
1544 GtkCellRenderer *renderer,
1545 GtkCellLayoutDataFunc func,
1547 GDestroyNotify destroy)
1549 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
1551 _gtk_cell_area_set_cell_data_func_with_proxy (area, renderer, (GFunc)func, func_data, destroy, NULL);
1555 gtk_cell_area_clear_attributes (GtkCellLayout *cell_layout,
1556 GtkCellRenderer *renderer)
1558 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
1559 GtkCellAreaPrivate *priv = area->priv;
1562 info = g_hash_table_lookup (priv->cell_info, renderer);
1566 g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
1567 g_slist_free (info->attributes);
1569 info->attributes = NULL;
1574 gtk_cell_area_reorder (GtkCellLayout *cell_layout,
1575 GtkCellRenderer *cell,
1578 g_warning ("GtkCellLayout::reorder not implemented for `%s'",
1579 g_type_name (G_TYPE_FROM_INSTANCE (cell_layout)));
1583 accum_cells (GtkCellRenderer *renderer,
1586 *accum = g_list_prepend (*accum, renderer);
1592 gtk_cell_area_get_cells (GtkCellLayout *cell_layout)
1594 GList *cells = NULL;
1596 gtk_cell_area_foreach (GTK_CELL_AREA (cell_layout),
1597 (GtkCellCallback)accum_cells,
1600 return g_list_reverse (cells);
1603 static GtkCellArea *
1604 gtk_cell_area_get_area (GtkCellLayout *cell_layout)
1606 return GTK_CELL_AREA (cell_layout);
1609 /*************************************************************
1610 * GtkBuildableIface *
1611 *************************************************************/
1613 gtk_cell_area_buildable_init (GtkBuildableIface *iface)
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;
1621 gtk_cell_area_buildable_custom_tag_end (GtkBuildable *buildable,
1622 GtkBuilder *builder,
1624 const gchar *tagname,
1627 /* Just ignore the boolean return from here */
1628 _gtk_cell_layout_buildable_custom_tag_end (buildable, builder, child, tagname, data);
1631 /*************************************************************
1633 *************************************************************/
1636 * gtk_cell_area_add:
1637 * @area: a #GtkCellArea
1638 * @renderer: the #GtkCellRenderer to add to @area
1640 * Adds @renderer to @area with the default child cell properties.
1645 gtk_cell_area_add (GtkCellArea *area,
1646 GtkCellRenderer *renderer)
1648 g_return_if_fail (GTK_IS_CELL_AREA (area));
1649 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1651 GTK_CELL_AREA_GET_CLASS (area)->add (area, renderer);
1655 * gtk_cell_area_remove:
1656 * @area: a #GtkCellArea
1657 * @renderer: the #GtkCellRenderer to remove from @area
1659 * Removes @renderer from @area.
1664 gtk_cell_area_remove (GtkCellArea *area,
1665 GtkCellRenderer *renderer)
1667 GtkCellAreaPrivate *priv;
1668 GList *renderers, *l;
1670 g_return_if_fail (GTK_IS_CELL_AREA (area));
1671 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1675 /* Remove any custom attributes and custom cell data func here first */
1676 g_hash_table_remove (priv->cell_info, renderer);
1678 /* Remove focus siblings of this renderer */
1679 g_hash_table_remove (priv->focus_siblings, renderer);
1681 /* Remove this renderer from any focus renderer's sibling list */
1682 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (area));
1684 for (l = renderers; l; l = l->next)
1686 GtkCellRenderer *focus_renderer = l->data;
1688 if (gtk_cell_area_is_focus_sibling (area, focus_renderer, renderer))
1690 gtk_cell_area_remove_focus_sibling (area, focus_renderer, renderer);
1695 g_list_free (renderers);
1697 GTK_CELL_AREA_GET_CLASS (area)->remove (area, renderer);
1701 get_has_renderer (GtkCellRenderer *renderer,
1702 HasRendererCheck *check)
1704 if (renderer == check->renderer)
1705 check->has_renderer = TRUE;
1707 return check->has_renderer;
1711 * gtk_cell_area_has_renderer:
1712 * @area: a #GtkCellArea
1713 * @renderer: the #GtkCellRenderer to check
1715 * Checks if @area contains @renderer.
1717 * Return value: %TRUE if @renderer is in the @area.
1722 gtk_cell_area_has_renderer (GtkCellArea *area,
1723 GtkCellRenderer *renderer)
1725 HasRendererCheck check = { renderer, FALSE };
1727 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
1728 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
1730 gtk_cell_area_foreach (area, (GtkCellCallback)get_has_renderer, &check);
1732 return check.has_renderer;
1736 * gtk_cell_area_foreach:
1737 * @area: a #GtkCellArea
1738 * @callback: (scope call): the #GtkCellCallback to call
1739 * @callback_data: user provided data pointer
1741 * Calls @callback for every #GtkCellRenderer in @area.
1746 gtk_cell_area_foreach (GtkCellArea *area,
1747 GtkCellCallback callback,
1748 gpointer callback_data)
1750 g_return_if_fail (GTK_IS_CELL_AREA (area));
1751 g_return_if_fail (callback != NULL);
1753 GTK_CELL_AREA_GET_CLASS (area)->foreach (area, callback, callback_data);
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
1766 * Calls @callback for every #GtkCellRenderer in @area with the
1767 * allocated rectangle inside @cell_area.
1772 gtk_cell_area_foreach_alloc (GtkCellArea *area,
1773 GtkCellAreaContext *context,
1775 const GdkRectangle *cell_area,
1776 const GdkRectangle *background_area,
1777 GtkCellAllocCallback callback,
1778 gpointer callback_data)
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);
1786 GTK_CELL_AREA_GET_CLASS (area)->foreach_alloc (area, context, widget,
1787 cell_area, background_area,
1788 callback, callback_data);
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.
1800 * Delegates event handling to a #GtkCellArea.
1802 * Return value: %TRUE if the event was handled by @area.
1807 gtk_cell_area_event (GtkCellArea *area,
1808 GtkCellAreaContext *context,
1811 const GdkRectangle *cell_area,
1812 GtkCellRendererState flags)
1814 GtkCellAreaClass *class;
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);
1822 class = GTK_CELL_AREA_GET_CLASS (area);
1825 return class->event (area, context, widget, event, cell_area, flags);
1827 g_warning ("GtkCellAreaClass::event not implemented for `%s'",
1828 g_type_name (G_TYPE_FROM_INSTANCE (area)));
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.
1843 * Renders @area's cells according to @area's layout onto @widget at
1844 * the given coordinates.
1849 gtk_cell_area_render (GtkCellArea *area,
1850 GtkCellAreaContext *context,
1853 const GdkRectangle *background_area,
1854 const GdkRectangle *cell_area,
1855 GtkCellRendererState flags,
1856 gboolean paint_focus)
1858 GtkCellAreaClass *class;
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);
1867 class = GTK_CELL_AREA_GET_CLASS (area);
1870 class->render (area, context, widget, cr, background_area, cell_area, flags, paint_focus);
1872 g_warning ("GtkCellAreaClass::render not implemented for `%s'",
1873 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1877 get_cell_allocation (GtkCellRenderer *renderer,
1878 const GdkRectangle *cell_area,
1879 const GdkRectangle *cell_background,
1880 RendererAllocationData *data)
1882 if (data->renderer == renderer)
1883 data->allocation = *cell_area;
1885 return (data->renderer == renderer);
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
1896 * @allocation: (out): where to store the allocation for @renderer
1898 * Derives the allocation of @renderer inside @area if @area
1899 * were to be renderered in @cell_area.
1904 gtk_cell_area_get_cell_allocation (GtkCellArea *area,
1905 GtkCellAreaContext *context,
1907 GtkCellRenderer *renderer,
1908 const GdkRectangle *cell_area,
1909 GdkRectangle *allocation)
1911 RendererAllocationData data = { renderer, { 0, } };
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);
1920 gtk_cell_area_foreach_alloc (area, context, widget, cell_area, cell_area,
1921 (GtkCellAllocCallback)get_cell_allocation, &data);
1923 *allocation = data.allocation;
1927 get_cell_by_position (GtkCellRenderer *renderer,
1928 const GdkRectangle *cell_area,
1929 const GdkRectangle *cell_background,
1930 CellByPositionData *data)
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)
1935 data->renderer = renderer;
1936 data->cell_area = *cell_area;
1939 return (data->renderer != NULL);
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
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.
1954 * Gets the #GtkCellRenderer at @x and @y coordinates inside @area and optionally
1955 * returns the full cell allocation for it inside @cell_area.
1957 * Return value: (transfer none): the #GtkCellRenderer at @x and @y.
1962 gtk_cell_area_get_cell_at_position (GtkCellArea *area,
1963 GtkCellAreaContext *context,
1965 const GdkRectangle *cell_area,
1968 GdkRectangle *alloc_area)
1970 CellByPositionData data = { x, y, NULL, { 0, } };
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);
1979 gtk_cell_area_foreach_alloc (area, context, widget, cell_area, cell_area,
1980 (GtkCellAllocCallback)get_cell_by_position, &data);
1983 *alloc_area = data.cell_area;
1985 return data.renderer;
1988 /*************************************************************
1990 *************************************************************/
1992 * gtk_cell_area_create_context:
1993 * @area: a #GtkCellArea
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).
2002 * Return value: (transfer full): a newly created #GtkCellAreaContext which can be used with @area.
2006 GtkCellAreaContext *
2007 gtk_cell_area_create_context (GtkCellArea *area)
2009 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2011 return GTK_CELL_AREA_GET_CLASS (area)->create_context (area);
2015 * gtk_cell_area_copy_context:
2016 * @area: a #GtkCellArea
2017 * @context: the #GtkCellAreaContext to copy
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.
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
2031 * Return value: (transfer full): a newly created #GtkCellAreaContext copy of @context.
2035 GtkCellAreaContext *
2036 gtk_cell_area_copy_context (GtkCellArea *area,
2037 GtkCellAreaContext *context)
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);
2042 return GTK_CELL_AREA_GET_CLASS (area)->copy_context (area, context);
2046 * gtk_cell_area_get_request_mode:
2047 * @area: a #GtkCellArea
2049 * Gets whether the area prefers a height-for-width layout
2050 * or a width-for-height layout.
2052 * Return value: The #GtkSizeRequestMode preferred by @area.
2057 gtk_cell_area_get_request_mode (GtkCellArea *area)
2059 g_return_val_if_fail (GTK_IS_CELL_AREA (area),
2060 GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH);
2062 return GTK_CELL_AREA_GET_CLASS (area)->get_request_mode (area);
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
2073 * Retrieves a cell area's initial minimum and natural width.
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
2084 gtk_cell_area_get_preferred_width (GtkCellArea *area,
2085 GtkCellAreaContext *context,
2087 gint *minimum_width,
2088 gint *natural_width)
2090 g_return_if_fail (GTK_IS_CELL_AREA (area));
2091 g_return_if_fail (GTK_IS_WIDGET (widget));
2093 GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, context, widget,
2094 minimum_width, natural_width);
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
2106 * Retrieves a cell area's minimum and natural height if it would be given
2107 * the specified @width.
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.
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().
2124 gtk_cell_area_get_preferred_height_for_width (GtkCellArea *area,
2125 GtkCellAreaContext *context,
2128 gint *minimum_height,
2129 gint *natural_height)
2131 GtkCellAreaClass *class;
2133 g_return_if_fail (GTK_IS_CELL_AREA (area));
2134 g_return_if_fail (GTK_IS_WIDGET (widget));
2136 class = GTK_CELL_AREA_GET_CLASS (area);
2137 class->get_preferred_height_for_width (area, context, widget, width, minimum_height, natural_height);
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
2149 * Retrieves a cell area's initial minimum and natural height.
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
2160 gtk_cell_area_get_preferred_height (GtkCellArea *area,
2161 GtkCellAreaContext *context,
2163 gint *minimum_height,
2164 gint *natural_height)
2166 g_return_if_fail (GTK_IS_CELL_AREA (area));
2167 g_return_if_fail (GTK_IS_WIDGET (widget));
2169 GTK_CELL_AREA_GET_CLASS (area)->get_preferred_height (area, context, widget,
2170 minimum_height, natural_height);
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
2182 * Retrieves a cell area's minimum and natural width if it would be given
2183 * the specified @height.
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.
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().
2200 gtk_cell_area_get_preferred_width_for_height (GtkCellArea *area,
2201 GtkCellAreaContext *context,
2204 gint *minimum_width,
2205 gint *natural_width)
2207 GtkCellAreaClass *class;
2209 g_return_if_fail (GTK_IS_CELL_AREA (area));
2210 g_return_if_fail (GTK_IS_WIDGET (widget));
2212 class = GTK_CELL_AREA_GET_CLASS (area);
2213 class->get_preferred_width_for_height (area, context, widget, height, minimum_width, natural_width);
2216 /*************************************************************
2218 *************************************************************/
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
2227 * Connects an @attribute to apply values from @column for the
2228 * #GtkTreeModel in use.
2233 gtk_cell_area_attribute_connect (GtkCellArea *area,
2234 GtkCellRenderer *renderer,
2235 const gchar *attribute,
2238 GtkCellAreaPrivate *priv;
2240 CellAttribute *cell_attribute;
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));
2248 info = g_hash_table_lookup (priv->cell_info, renderer);
2252 info = cell_info_new (NULL, NULL, NULL);
2254 g_hash_table_insert (priv->cell_info, renderer, info);
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)
2264 cell_attribute = node->data;
2266 g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
2267 "since `%s' is already attributed to column %d",
2269 G_OBJECT_TYPE_NAME (renderer),
2270 attribute, cell_attribute->column);
2275 cell_attribute = cell_attribute_new (renderer, attribute, column);
2277 if (!cell_attribute)
2279 g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
2280 "since attribute does not exist",
2282 G_OBJECT_TYPE_NAME (renderer));
2286 info->attributes = g_slist_prepend (info->attributes, cell_attribute);
2290 * gtk_cell_area_attribute_disconnect:
2291 * @area: a #GtkCellArea
2292 * @renderer: the #GtkCellRenderer to disconnect an attribute for
2293 * @attribute: the attribute name
2295 * Disconnects @attribute for the @renderer in @area so that
2296 * attribute will no longer be updated with values from the
2302 gtk_cell_area_attribute_disconnect (GtkCellArea *area,
2303 GtkCellRenderer *renderer,
2304 const gchar *attribute)
2306 GtkCellAreaPrivate *priv;
2308 CellAttribute *cell_attribute;
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));
2317 info = g_hash_table_lookup (priv->cell_info, renderer);
2321 node = g_slist_find_custom (info->attributes, attribute,
2322 (GCompareFunc)cell_attribute_find);
2325 cell_attribute = node->data;
2327 cell_attribute_free (cell_attribute);
2329 info->attributes = g_slist_delete_link (info->attributes, node);
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
2343 * Applies any connected attributes to the renderers in
2344 * @area by pulling the values from @tree_model.
2349 gtk_cell_area_apply_attributes (GtkCellArea *area,
2350 GtkTreeModel *tree_model,
2352 gboolean is_expander,
2353 gboolean is_expanded)
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);
2359 g_signal_emit (area, cell_area_signals[SIGNAL_APPLY_ATTRIBUTES], 0,
2360 tree_model, iter, is_expander, is_expanded);
2364 * gtk_cell_area_get_current_path_string:
2365 * @area: a #GtkCellArea
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
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.
2380 gtk_cell_area_get_current_path_string (GtkCellArea *area)
2382 GtkCellAreaPrivate *priv;
2384 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2388 return priv->current_path;
2392 /*************************************************************
2393 * API: Cell Properties *
2394 *************************************************************/
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
2401 * Installs a cell property on a cell area class.
2406 gtk_cell_area_class_install_cell_property (GtkCellAreaClass *aclass,
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);
2420 if (g_param_spec_pool_lookup (cell_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (aclass), TRUE))
2422 g_warning (G_STRLOC ": class `%s' already contains a cell property named `%s'",
2423 G_OBJECT_CLASS_NAME (aclass), pspec->name);
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));
2433 * gtk_cell_area_class_find_cell_property:
2434 * @aclass: a #GtkCellAreaClass
2435 * @property_name: the name of the child property to find
2437 * Finds a cell property of a cell area class by name.
2439 * Return value: (transfer none): the #GParamSpec of the child property
2440 * or %NULL if @aclass has no child property with that name.
2445 gtk_cell_area_class_find_cell_property (GtkCellAreaClass *aclass,
2446 const gchar *property_name)
2448 g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
2449 g_return_val_if_fail (property_name != NULL, NULL);
2451 return g_param_spec_pool_lookup (cell_property_pool,
2453 G_OBJECT_CLASS_TYPE (aclass),
2458 * gtk_cell_area_class_list_cell_properties:
2459 * @aclass: a #GtkCellAreaClass
2460 * @n_properties: location to return the number of cell properties found
2462 * Returns all cell properties of a cell area class.
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().
2471 gtk_cell_area_class_list_cell_properties (GtkCellAreaClass *aclass,
2472 guint *n_properties)
2474 GParamSpec **pspecs;
2477 g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
2479 pspecs = g_param_spec_pool_list (cell_property_pool,
2480 G_OBJECT_CLASS_TYPE (aclass),
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
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.
2502 gtk_cell_area_add_with_properties (GtkCellArea *area,
2503 GtkCellRenderer *renderer,
2504 const gchar *first_prop_name,
2507 GtkCellAreaClass *class;
2509 g_return_if_fail (GTK_IS_CELL_AREA (area));
2510 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2512 class = GTK_CELL_AREA_GET_CLASS (area);
2518 class->add (area, renderer);
2520 va_start (var_args, first_prop_name);
2521 gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
2525 g_warning ("GtkCellAreaClass::add not implemented for `%s'",
2526 g_type_name (G_TYPE_FROM_INSTANCE (area)));
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
2537 * Sets one or more cell properties for @cell in @area.
2542 gtk_cell_area_cell_set (GtkCellArea *area,
2543 GtkCellRenderer *renderer,
2544 const gchar *first_prop_name,
2549 g_return_if_fail (GTK_IS_CELL_AREA (area));
2550 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2552 va_start (var_args, first_prop_name);
2553 gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
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
2565 * Gets the values of one or more cell properties for @renderer in @area.
2570 gtk_cell_area_cell_get (GtkCellArea *area,
2571 GtkCellRenderer *renderer,
2572 const gchar *first_prop_name,
2577 g_return_if_fail (GTK_IS_CELL_AREA (area));
2578 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2580 va_start (var_args, first_prop_name);
2581 gtk_cell_area_cell_get_valist (area, renderer, first_prop_name, var_args);
2586 area_get_cell_property (GtkCellArea *area,
2587 GtkCellRenderer *renderer,
2591 GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
2593 class->get_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), value, pspec);
2597 area_set_cell_property (GtkCellArea *area,
2598 GtkCellRenderer *renderer,
2600 const GValue *value)
2602 GValue tmp_value = { 0, };
2603 GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
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'",
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))
2614 gchar *contents = g_strdup_value_contents (value);
2616 g_warning ("value \"%s\" of type `%s' is invalid for property `%s' of type `%s'",
2618 G_VALUE_TYPE_NAME (value),
2620 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
2625 class->set_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec);
2627 g_value_unset (&tmp_value);
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
2638 * Sets one or more cell properties for @renderer in @area.
2643 gtk_cell_area_cell_set_valist (GtkCellArea *area,
2644 GtkCellRenderer *renderer,
2645 const gchar *first_property_name,
2650 g_return_if_fail (GTK_IS_CELL_AREA (area));
2651 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2653 name = first_property_name;
2656 GValue value = { 0, };
2657 gchar *error = NULL;
2659 g_param_spec_pool_lookup (cell_property_pool, name,
2660 G_OBJECT_TYPE (area), TRUE);
2663 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
2664 G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
2667 if (!(pspec->flags & G_PARAM_WRITABLE))
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));
2674 G_VALUE_COLLECT_INIT (&value, G_PARAM_SPEC_VALUE_TYPE (pspec),
2675 var_args, 0, &error);
2678 g_warning ("%s: %s", G_STRLOC, error);
2681 /* we purposely leak the value here, it might not be
2682 * in a sane state if an error condition occoured
2686 area_set_cell_property (area, renderer, pspec, &value);
2687 g_value_unset (&value);
2688 name = va_arg (var_args, gchar*);
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
2700 * Gets the values of one or more cell properties for @renderer in @area.
2705 gtk_cell_area_cell_get_valist (GtkCellArea *area,
2706 GtkCellRenderer *renderer,
2707 const gchar *first_property_name,
2712 g_return_if_fail (GTK_IS_CELL_AREA (area));
2713 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2715 name = first_property_name;
2718 GValue value = { 0, };
2722 pspec = g_param_spec_pool_lookup (cell_property_pool, name,
2723 G_OBJECT_TYPE (area), TRUE);
2726 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
2727 G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
2730 if (!(pspec->flags & G_PARAM_READABLE))
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));
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);
2742 g_warning ("%s: %s", G_STRLOC, error);
2744 g_value_unset (&value);
2747 g_value_unset (&value);
2748 name = va_arg (var_args, gchar*);
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
2759 * Sets a cell property for @renderer in @area.
2764 gtk_cell_area_cell_set_property (GtkCellArea *area,
2765 GtkCellRenderer *renderer,
2766 const gchar *property_name,
2767 const GValue *value)
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));
2776 pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
2777 G_OBJECT_TYPE (area), TRUE);
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));
2786 area_set_cell_property (area, renderer, pspec, value);
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
2797 * Gets the value of a cell property for @renderer in @area.
2802 gtk_cell_area_cell_get_property (GtkCellArea *area,
2803 GtkCellRenderer *renderer,
2804 const gchar *property_name,
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));
2814 pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
2815 G_OBJECT_TYPE (area), TRUE);
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));
2824 GValue *prop_value, tmp_value = { 0, };
2826 /* auto-conversion of the callers value type
2828 if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
2830 g_value_reset (value);
2833 else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
2835 g_warning ("can't retrieve cell property `%s' of type `%s' as value of type `%s'",
2837 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
2838 G_VALUE_TYPE_NAME (value));
2843 g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
2844 prop_value = &tmp_value;
2847 area_get_cell_property (area, renderer, pspec, prop_value);
2849 if (prop_value != value)
2851 g_value_transform (prop_value, value);
2852 g_value_unset (&tmp_value);
2857 /*************************************************************
2859 *************************************************************/
2862 * gtk_cell_area_is_activatable:
2863 * @area: a #GtkCellArea
2865 * Returns whether the area can do anything when activated,
2866 * after applying new attributes to @area.
2868 * Return value: whether @area can do anything when activated.
2873 gtk_cell_area_is_activatable (GtkCellArea *area)
2875 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2877 return GTK_CELL_AREA_GET_CLASS (area)->is_activatable (area);
2881 * gtk_cell_area_focus:
2882 * @area: a #GtkCellArea
2883 * @direction: the #GtkDirectionType
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.
2889 * Implementing #GtkCellArea classes should implement this
2890 * method to receive and navigate focus in its own way particular
2891 * to how it lays out cells.
2893 * Return value: %TRUE if focus remains inside @area as a result of this call.
2898 gtk_cell_area_focus (GtkCellArea *area,
2899 GtkDirectionType direction)
2901 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2903 return GTK_CELL_AREA_GET_CLASS (area)->focus (area, direction);
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.
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.
2920 * Return value: Whether @area was successfully activated.
2925 gtk_cell_area_activate (GtkCellArea *area,
2926 GtkCellAreaContext *context,
2928 const GdkRectangle *cell_area,
2929 GtkCellRendererState flags,
2932 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2934 return GTK_CELL_AREA_GET_CLASS (area)->activate (area, context, widget, cell_area, flags, edit_only);
2939 * gtk_cell_area_set_focus_cell:
2940 * @area: a #GtkCellArea
2941 * @renderer: the #GtkCellRenderer to give focus to
2943 * Explicitly sets the currently focused cell to @renderer.
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().
2953 gtk_cell_area_set_focus_cell (GtkCellArea *area,
2954 GtkCellRenderer *renderer)
2956 GtkCellAreaPrivate *priv;
2958 g_return_if_fail (GTK_IS_CELL_AREA (area));
2959 g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer));
2963 if (priv->focus_cell != renderer)
2965 if (priv->focus_cell)
2966 g_object_unref (priv->focus_cell);
2968 priv->focus_cell = renderer;
2970 if (priv->focus_cell)
2971 g_object_ref (priv->focus_cell);
2973 g_object_notify (G_OBJECT (area), "focus-cell");
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);
2985 * gtk_cell_area_get_focus_cell:
2986 * @area: a #GtkCellArea
2988 * Retrieves the currently focused cell for @area
2990 * Return value: (transfer none): the currently focused cell in @area.
2995 gtk_cell_area_get_focus_cell (GtkCellArea *area)
2997 GtkCellAreaPrivate *priv;
2999 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
3003 return priv->focus_cell;
3007 /*************************************************************
3008 * API: Focus Siblings *
3009 *************************************************************/
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
3017 * Adds @sibling to @renderer's focusable area, focus will be drawn
3018 * around @renderer and all of its siblings if @renderer can
3019 * focus for a given row.
3021 * Events handled by focus siblings can also activate the given
3022 * focusable @renderer.
3027 gtk_cell_area_add_focus_sibling (GtkCellArea *area,
3028 GtkCellRenderer *renderer,
3029 GtkCellRenderer *sibling)
3031 GtkCellAreaPrivate *priv;
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));
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
3049 siblings = g_hash_table_lookup (priv->focus_siblings, renderer);
3052 siblings = g_list_append (siblings, sibling);
3055 siblings = g_list_append (siblings, sibling);
3056 g_hash_table_insert (priv->focus_siblings, renderer, siblings);
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
3066 * Removes @sibling from @renderer's focus sibling list
3067 * (see gtk_cell_area_add_focus_sibling()).
3072 gtk_cell_area_remove_focus_sibling (GtkCellArea *area,
3073 GtkCellRenderer *renderer,
3074 GtkCellRenderer *sibling)
3076 GtkCellAreaPrivate *priv;
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));
3086 siblings = g_hash_table_lookup (priv->focus_siblings, renderer);
3088 siblings = g_list_copy (siblings);
3089 siblings = g_list_remove (siblings, sibling);
3092 g_hash_table_remove (priv->focus_siblings, renderer);
3094 g_hash_table_insert (priv->focus_siblings, renderer, siblings);
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
3103 * Returns whether @sibling is one of @renderer's focus siblings
3104 * (see gtk_cell_area_add_focus_sibling()).
3106 * Return value: %TRUE if @sibling is a focus sibling of @renderer
3111 gtk_cell_area_is_focus_sibling (GtkCellArea *area,
3112 GtkCellRenderer *renderer,
3113 GtkCellRenderer *sibling)
3115 GtkCellAreaPrivate *priv;
3116 GList *siblings, *l;
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);
3124 siblings = g_hash_table_lookup (priv->focus_siblings, renderer);
3126 for (l = siblings; l; l = l->next)
3128 GtkCellRenderer *a_sibling = l->data;
3130 if (a_sibling == sibling)
3138 * gtk_cell_area_get_focus_siblings:
3139 * @area: a #GtkCellArea
3140 * @renderer: the #GtkCellRenderer expected to have focus
3142 * Gets the focus sibling cell renderers for @renderer.
3144 * Return value: (element-type GtkCellRenderer) (transfer none): A #GList of #GtkCellRenderers.
3145 * The returned list is internal and should not be freed.
3150 gtk_cell_area_get_focus_siblings (GtkCellArea *area,
3151 GtkCellRenderer *renderer)
3153 GtkCellAreaPrivate *priv;
3155 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
3156 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), NULL);
3160 return g_hash_table_lookup (priv->focus_siblings, renderer);
3164 * gtk_cell_area_get_focus_from_sibling:
3165 * @area: a #GtkCellArea
3166 * @renderer: the #GtkCellRenderer
3168 * Gets the #GtkCellRenderer which is expected to be focusable
3169 * for which @renderer is, or may be a sibling.
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.
3176 * Return value: (transfer none): the #GtkCellRenderer for which @renderer
3177 * is a sibling, or %NULL.
3182 gtk_cell_area_get_focus_from_sibling (GtkCellArea *area,
3183 GtkCellRenderer *renderer)
3185 GtkCellRenderer *ret_renderer = NULL;
3186 GList *renderers, *l;
3188 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
3189 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), NULL);
3191 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (area));
3193 for (l = renderers; l; l = l->next)
3195 GtkCellRenderer *a_renderer = l->data;
3198 for (list = gtk_cell_area_get_focus_siblings (area, a_renderer);
3199 list; list = list->next)
3201 GtkCellRenderer *sibling_renderer = list->data;
3203 if (sibling_renderer == renderer)
3205 ret_renderer = a_renderer;
3210 g_list_free (renderers);
3212 return ret_renderer;
3215 /*************************************************************
3216 * API: Cell Activation/Editing *
3217 *************************************************************/
3219 gtk_cell_area_add_editable (GtkCellArea *area,
3220 GtkCellRenderer *renderer,
3221 GtkCellEditable *editable,
3222 const GdkRectangle *cell_area)
3224 g_signal_emit (area, cell_area_signals[SIGNAL_ADD_EDITABLE], 0,
3225 renderer, editable, cell_area, area->priv->current_path);
3229 gtk_cell_area_remove_editable (GtkCellArea *area,
3230 GtkCellRenderer *renderer,
3231 GtkCellEditable *editable)
3233 g_signal_emit (area, cell_area_signals[SIGNAL_REMOVE_EDITABLE], 0, renderer, editable);
3237 cell_area_remove_widget_cb (GtkCellEditable *editable,
3240 GtkCellAreaPrivate *priv = area->priv;
3242 g_assert (priv->edit_widget == editable);
3243 g_assert (priv->edited_cell != NULL);
3245 gtk_cell_area_remove_editable (area, priv->edited_cell, priv->edit_widget);
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);
3254 gtk_cell_area_set_edited_cell (GtkCellArea *area,
3255 GtkCellRenderer *renderer)
3257 GtkCellAreaPrivate *priv;
3259 g_return_if_fail (GTK_IS_CELL_AREA (area));
3260 g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer));
3264 if (priv->edited_cell != renderer)
3266 if (priv->edited_cell)
3267 g_object_unref (priv->edited_cell);
3269 priv->edited_cell = renderer;
3271 if (priv->edited_cell)
3272 g_object_ref (priv->edited_cell);
3274 g_object_notify (G_OBJECT (area), "edited-cell");
3279 gtk_cell_area_set_edit_widget (GtkCellArea *area,
3280 GtkCellEditable *editable)
3282 GtkCellAreaPrivate *priv;
3284 g_return_if_fail (GTK_IS_CELL_AREA (area));
3285 g_return_if_fail (editable == NULL || GTK_IS_CELL_EDITABLE (editable));
3289 if (priv->edit_widget != editable)
3291 if (priv->edit_widget)
3293 g_signal_handler_disconnect (priv->edit_widget, priv->remove_widget_id);
3295 g_object_unref (priv->edit_widget);
3298 priv->edit_widget = editable;
3300 if (priv->edit_widget)
3302 priv->remove_widget_id =
3303 g_signal_connect (priv->edit_widget, "remove-widget",
3304 G_CALLBACK (cell_area_remove_widget_cb), area);
3306 g_object_ref (priv->edit_widget);
3309 g_object_notify (G_OBJECT (area), "edit-widget");
3314 * gtk_cell_area_get_edited_cell:
3315 * @area: a #GtkCellArea
3317 * Gets the #GtkCellRenderer in @area that is currently
3320 * Return value: (transfer none): The currently edited #GtkCellRenderer
3325 gtk_cell_area_get_edited_cell (GtkCellArea *area)
3327 GtkCellAreaPrivate *priv;
3329 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
3333 return priv->edited_cell;
3337 * gtk_cell_area_get_edit_widget:
3338 * @area: a #GtkCellArea
3340 * Gets the #GtkCellEditable widget currently used
3341 * to edit the currently edited cell.
3343 * Return value: (transfer none): The currently active #GtkCellEditable widget
3348 gtk_cell_area_get_edit_widget (GtkCellArea *area)
3350 GtkCellAreaPrivate *priv;
3352 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
3356 return priv->edit_widget;
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
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 its own GtkCellArea->activate()
3374 * Return value: whether cell activation was successful
3379 gtk_cell_area_activate_cell (GtkCellArea *area,
3381 GtkCellRenderer *renderer,
3383 const GdkRectangle *cell_area,
3384 GtkCellRendererState flags)
3386 GtkCellRendererMode mode;
3387 GtkCellAreaPrivate *priv;
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);
3396 if (!gtk_cell_renderer_get_sensitive (renderer))
3399 g_object_get (renderer, "mode", &mode, NULL);
3401 if (mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
3403 if (gtk_cell_renderer_activate (renderer,
3411 else if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
3413 GtkCellEditable *editable_widget;
3414 GdkRectangle inner_area;
3416 gtk_cell_area_inner_cell_area (area, widget, cell_area, &inner_area);
3419 gtk_cell_renderer_start_editing (renderer,
3426 if (editable_widget != NULL)
3428 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (editable_widget), FALSE);
3430 gtk_cell_area_set_edited_cell (area, renderer);
3431 gtk_cell_area_set_edit_widget (area, editable_widget);
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);
3437 /* If the signal was successfully handled start the editing */
3438 if (gtk_widget_get_parent (GTK_WIDGET (editable_widget)))
3440 gtk_cell_editable_start_editing (editable_widget, NULL);
3441 gtk_widget_grab_focus (GTK_WIDGET (editable_widget));
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);
3449 g_warning ("GtkCellArea::add-editable fired in the dark, no cell editing was started.");
3460 * gtk_cell_area_stop_editing:
3461 * @area: a #GtkCellArea
3462 * @canceled: whether editing was canceled.
3464 * Explicitly stops the editing of the currently
3465 * edited cell (see gtk_cell_area_get_edited_cell()).
3467 * If @canceled is %TRUE, the cell renderer will emit
3468 * the ::editing-canceled signal.
3473 gtk_cell_area_stop_editing (GtkCellArea *area,
3476 GtkCellAreaPrivate *priv;
3478 g_return_if_fail (GTK_IS_CELL_AREA (area));
3482 if (priv->edited_cell)
3484 GtkCellEditable *edit_widget = g_object_ref (priv->edit_widget);
3485 GtkCellRenderer *edit_cell = g_object_ref (priv->edited_cell);
3487 /* Stop editing of the cell renderer */
3488 gtk_cell_renderer_stop_editing (priv->edited_cell, canceled);
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);
3494 /* Send the remove-widget signal explicitly (this is done after setting
3495 * the edit cell/widget NULL to avoid feedback)
3497 gtk_cell_area_remove_editable (area, edit_cell, edit_widget);
3498 g_object_unref (edit_cell);
3499 g_object_unref (edit_widget);
3503 /*************************************************************
3504 * API: Convenience for area implementations *
3505 *************************************************************/
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
3513 * @inner_area: (out): the return location for the inner cell area
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().
3522 gtk_cell_area_inner_cell_area (GtkCellArea *area,
3524 const GdkRectangle *cell_area,
3525 GdkRectangle *inner_area)
3527 gint focus_line_width;
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);
3534 gtk_widget_style_get (widget, "focus-line-width", &focus_line_width, NULL);
3536 *inner_area = *cell_area;
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;
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
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.
3564 gtk_cell_area_request_renderer (GtkCellArea *area,
3565 GtkCellRenderer *renderer,
3566 GtkOrientation orientation,
3572 gint focus_line_width;
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);
3580 gtk_widget_style_get (widget, "focus-line-width", &focus_line_width, NULL);
3582 focus_line_width *= 2;
3584 if (orientation == GTK_ORIENTATION_HORIZONTAL)
3587 gtk_cell_renderer_get_preferred_width (renderer, widget, minimum_size, natural_size);
3590 for_size = MAX (0, for_size - focus_line_width);
3592 gtk_cell_renderer_get_preferred_width_for_height (renderer, widget, for_size,
3593 minimum_size, natural_size);
3596 else /* GTK_ORIENTATION_VERTICAL */
3599 gtk_cell_renderer_get_preferred_height (renderer, widget, minimum_size, natural_size);
3602 for_size = MAX (0, for_size - focus_line_width);
3604 gtk_cell_renderer_get_preferred_height_for_width (renderer, widget, for_size,
3605 minimum_size, natural_size);
3609 *minimum_size += focus_line_width;
3610 *natural_size += focus_line_width;
3614 _gtk_cell_area_set_cell_data_func_with_proxy (GtkCellArea *area,
3615 GtkCellRenderer *cell,
3618 GDestroyNotify destroy,
3621 GtkCellAreaPrivate *priv;
3624 g_return_if_fail (GTK_IS_CELL_AREA (area));
3625 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
3629 info = g_hash_table_lookup (priv->cell_info, cell);
3631 /* Note we do not take a reference to the proxy, the proxy is a GtkCellLayout
3632 * that is forwarding its implementation to a delegate GtkCellArea therefore
3633 * its life-cycle is longer than the area's life cycle.
3637 if (info->destroy && info->data)
3638 info->destroy (info->data);
3642 info->func = (GtkCellLayoutDataFunc)func;
3643 info->data = func_data;
3644 info->destroy = destroy;
3645 info->proxy = proxy;
3651 info->destroy = NULL;
3657 info = cell_info_new ((GtkCellLayoutDataFunc)func, func_data, destroy);
3658 info->proxy = proxy;
3660 g_hash_table_insert (priv->cell_info, cell, info);