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.
31 #include "gtkcelllayout.h"
32 #include "gtkcellarea.h"
33 #include "gtkcellareacontext.h"
34 #include "gtkmarshalers.h"
35 #include "gtkprivate.h"
37 #include <gobject/gvaluecollector.h>
41 static void gtk_cell_area_dispose (GObject *object);
42 static void gtk_cell_area_finalize (GObject *object);
43 static void gtk_cell_area_set_property (GObject *object,
47 static void gtk_cell_area_get_property (GObject *object,
52 /* GtkCellAreaClass */
53 static gint gtk_cell_area_real_event (GtkCellArea *area,
54 GtkCellAreaContext *context,
57 const GdkRectangle *cell_area,
58 GtkCellRendererState flags);
59 static void gtk_cell_area_real_apply_attributes (GtkCellArea *area,
60 GtkTreeModel *tree_model,
63 gboolean is_expanded);
64 static void gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area,
65 GtkCellAreaContext *context,
69 gint *natural_height);
70 static void gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area,
71 GtkCellAreaContext *context,
76 static gboolean gtk_cell_area_real_can_focus (GtkCellArea *area);
77 static gboolean gtk_cell_area_real_activate (GtkCellArea *area,
78 GtkCellAreaContext *context,
80 const GdkRectangle *cell_area,
81 GtkCellRendererState flags);
83 /* GtkCellLayoutIface */
84 static void gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface);
85 static void gtk_cell_area_pack_default (GtkCellLayout *cell_layout,
86 GtkCellRenderer *renderer,
88 static void gtk_cell_area_clear (GtkCellLayout *cell_layout);
89 static void gtk_cell_area_add_attribute (GtkCellLayout *cell_layout,
90 GtkCellRenderer *renderer,
91 const gchar *attribute,
93 static void gtk_cell_area_set_cell_data_func (GtkCellLayout *cell_layout,
94 GtkCellRenderer *cell,
95 GtkCellLayoutDataFunc func,
97 GDestroyNotify destroy);
98 static void gtk_cell_area_clear_attributes (GtkCellLayout *cell_layout,
99 GtkCellRenderer *renderer);
100 static void gtk_cell_area_reorder (GtkCellLayout *cell_layout,
101 GtkCellRenderer *cell,
103 static GList *gtk_cell_area_get_cells (GtkCellLayout *cell_layout);
106 /* Used in forall loop to check if a child renderer is present */
108 GtkCellRenderer *renderer;
109 gboolean has_renderer;
112 /* Attribute/Cell metadata */
114 const gchar *attribute;
121 GtkCellLayoutDataFunc func;
123 GDestroyNotify destroy;
126 static CellInfo *cell_info_new (GtkCellLayoutDataFunc func,
128 GDestroyNotify destroy);
129 static void cell_info_free (CellInfo *info);
130 static CellAttribute *cell_attribute_new (GtkCellRenderer *renderer,
131 const gchar *attribute,
133 static void cell_attribute_free (CellAttribute *attribute);
134 static gint cell_attribute_find (CellAttribute *cell_attribute,
135 const gchar *attribute);
137 /* Internal functions/signal emissions */
138 static void gtk_cell_area_add_editable (GtkCellArea *area,
139 GtkCellRenderer *renderer,
140 GtkCellEditable *editable,
141 GdkRectangle *cell_area);
142 static void gtk_cell_area_remove_editable (GtkCellArea *area,
143 GtkCellRenderer *renderer,
144 GtkCellEditable *editable);
145 static void gtk_cell_area_set_edit_widget (GtkCellArea *area,
146 GtkCellEditable *editable);
147 static void gtk_cell_area_set_edited_cell (GtkCellArea *area,
148 GtkCellRenderer *renderer);
151 /* Struct to pass data along while looping over
152 * cell renderers to apply attributes
158 gboolean is_expander;
159 gboolean is_expanded;
162 struct _GtkCellAreaPrivate
164 /* The GtkCellArea bookkeeps any connected
165 * attributes in this hash table.
167 GHashTable *cell_info;
169 /* Current path is saved as a side-effect
170 * of gtk_cell_area_apply_attributes() */
173 /* Current cell being edited and editable widget used */
174 GtkCellEditable *edit_widget;
175 GtkCellRenderer *edited_cell;
177 /* Signal connections to the editable widget */
178 gulong remove_widget_id;
180 /* Currently focused cell */
181 GtkCellRenderer *focus_cell;
183 /* Tracking which cells are focus siblings of focusable cells */
184 GHashTable *focus_siblings;
186 /* Detail string to pass to gtk_paint_*() functions */
198 SIGNAL_APPLY_ATTRIBUTES,
200 SIGNAL_REMOVE_EDITABLE,
201 SIGNAL_FOCUS_CHANGED,
205 /* Keep the paramspec pool internal, no need to deliver notifications
206 * on cells. at least no percieved need for now */
207 static GParamSpecPool *cell_property_pool = NULL;
208 static guint cell_area_signals[LAST_SIGNAL] = { 0 };
210 #define PARAM_SPEC_PARAM_ID(pspec) ((pspec)->param_id)
211 #define PARAM_SPEC_SET_PARAM_ID(pspec, id) ((pspec)->param_id = (id))
214 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkCellArea, gtk_cell_area, G_TYPE_INITIALLY_UNOWNED,
215 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
216 gtk_cell_area_cell_layout_init));
219 gtk_cell_area_init (GtkCellArea *area)
221 GtkCellAreaPrivate *priv;
223 area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area,
228 priv->cell_info = g_hash_table_new_full (g_direct_hash,
231 (GDestroyNotify)cell_info_free);
233 priv->focus_siblings = g_hash_table_new_full (g_direct_hash,
236 (GDestroyNotify)g_list_free);
238 priv->focus_cell = NULL;
239 priv->edited_cell = NULL;
240 priv->edit_widget = NULL;
242 priv->remove_widget_id = 0;
246 gtk_cell_area_class_init (GtkCellAreaClass *class)
248 GObjectClass *object_class = G_OBJECT_CLASS (class);
251 object_class->dispose = gtk_cell_area_dispose;
252 object_class->finalize = gtk_cell_area_finalize;
253 object_class->get_property = gtk_cell_area_get_property;
254 object_class->set_property = gtk_cell_area_set_property;
258 class->remove = NULL;
259 class->forall = NULL;
260 class->event = gtk_cell_area_real_event;
261 class->render = NULL;
262 class->apply_attributes = gtk_cell_area_real_apply_attributes;
265 class->create_context = NULL;
266 class->get_request_mode = NULL;
267 class->get_preferred_width = NULL;
268 class->get_preferred_height = NULL;
269 class->get_preferred_height_for_width = gtk_cell_area_real_get_preferred_height_for_width;
270 class->get_preferred_width_for_height = gtk_cell_area_real_get_preferred_width_for_height;
273 class->can_focus = gtk_cell_area_real_can_focus;
275 class->activate = gtk_cell_area_real_activate;
280 * GtkCellArea::apply-attributes:
281 * @area: the #GtkCellArea to apply the attributes to
282 * @model: the #GtkTreeModel to apply the attributes from
283 * @iter: the #GtkTreeIter indicating which row to apply the attributes of
284 * @is_expander: whether the view shows children for this row
285 * @is_expanded: whether the view is currently showing the children of this row
287 * This signal is emitted whenever applying attributes to @area from @model
289 cell_area_signals[SIGNAL_APPLY_ATTRIBUTES] =
290 g_signal_new (I_("apply-attributes"),
291 G_OBJECT_CLASS_TYPE (object_class),
293 G_STRUCT_OFFSET (GtkCellAreaClass, apply_attributes),
295 _gtk_marshal_VOID__OBJECT_BOXED_BOOLEAN_BOOLEAN,
303 * GtkCellArea::add-editable:
304 * @area: the #GtkCellArea where editing started
305 * @renderer: the #GtkCellRenderer that started the edited
306 * @editable: the #GtkCellEditable widget to add
307 * @cell_area: the #GtkWidget relative #GdkRectangle coordinates
308 * where @editable should be added
309 * @path: the #GtkTreePath string this edit was initiated for
311 * Indicates that editing has started on @renderer and that @editable
312 * should be added to the owning cell layouting widget at @cell_area.
314 cell_area_signals[SIGNAL_ADD_EDITABLE] =
315 g_signal_new (I_("add-editable"),
316 G_OBJECT_CLASS_TYPE (object_class),
318 0, /* No class closure here */
320 _gtk_marshal_VOID__OBJECT_OBJECT_BOXED_STRING,
322 GTK_TYPE_CELL_RENDERER,
323 GTK_TYPE_CELL_EDITABLE,
329 * GtkCellArea::remove-editable:
330 * @area: the #GtkCellArea where editing finished
331 * @renderer: the #GtkCellRenderer that finished editeding
332 * @editable: the #GtkCellEditable widget to remove
334 * Indicates that editing finished on @renderer and that @editable
335 * should be removed from the owning cell layouting widget.
337 cell_area_signals[SIGNAL_REMOVE_EDITABLE] =
338 g_signal_new (I_("remove-editable"),
339 G_OBJECT_CLASS_TYPE (object_class),
341 0, /* No class closure here */
343 _gtk_marshal_VOID__OBJECT_OBJECT,
345 GTK_TYPE_CELL_RENDERER,
346 GTK_TYPE_CELL_EDITABLE);
349 * GtkCellArea::focus-changed:
350 * @area: the #GtkCellArea where focus changed
351 * @renderer: the #GtkCellRenderer that has focus
352 * @path: the current #GtkTreePath string set for @area
354 * Indicates that focus changed on this @area. This signal
355 * is emitted either as a result of focus handling or event
358 * It's possible that the signal is emitted even if the
359 * currently focused renderer did not change, this is
360 * because focus may change to the same renderer in the
361 * same cell area for a different row of data.
363 cell_area_signals[SIGNAL_FOCUS_CHANGED] =
364 g_signal_new (I_("focus-changed"),
365 G_OBJECT_CLASS_TYPE (object_class),
367 0, /* No class closure here */
369 _gtk_marshal_VOID__OBJECT_STRING,
371 GTK_TYPE_CELL_RENDERER,
375 g_object_class_install_property (object_class,
380 P_("The cell which currently has focus"),
381 GTK_TYPE_CELL_RENDERER,
382 GTK_PARAM_READWRITE));
384 g_object_class_install_property (object_class,
389 P_("The cell which is currently being edited"),
390 GTK_TYPE_CELL_RENDERER,
393 g_object_class_install_property (object_class,
398 P_("The widget currently editing the edited cell"),
399 GTK_TYPE_CELL_RENDERER,
402 /* Pool for Cell Properties */
403 if (!cell_property_pool)
404 cell_property_pool = g_param_spec_pool_new (FALSE);
406 g_type_class_add_private (object_class, sizeof (GtkCellAreaPrivate));
409 /*************************************************************
411 *************************************************************/
413 cell_info_new (GtkCellLayoutDataFunc func,
415 GDestroyNotify destroy)
417 CellInfo *info = g_slice_new0 (CellInfo);
421 info->destroy = destroy;
427 cell_info_free (CellInfo *info)
430 info->destroy (info->data);
432 g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
433 g_slist_free (info->attributes);
435 g_slice_free (CellInfo, info);
438 static CellAttribute *
439 cell_attribute_new (GtkCellRenderer *renderer,
440 const gchar *attribute,
445 /* Check if the attribute really exists and point to
446 * the property string installed on the cell renderer
447 * class (dont dup the string)
449 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (renderer), attribute);
453 CellAttribute *cell_attribute = g_slice_new (CellAttribute);
455 cell_attribute->attribute = pspec->name;
456 cell_attribute->column = column;
458 return cell_attribute;
465 cell_attribute_free (CellAttribute *attribute)
467 g_slice_free (CellAttribute, attribute);
470 /* GCompareFunc for g_slist_find_custom() */
472 cell_attribute_find (CellAttribute *cell_attribute,
473 const gchar *attribute)
475 return g_strcmp0 (cell_attribute->attribute, attribute);
478 /*************************************************************
480 *************************************************************/
482 gtk_cell_area_finalize (GObject *object)
484 GtkCellArea *area = GTK_CELL_AREA (object);
485 GtkCellAreaPrivate *priv = area->priv;
487 /* All cell renderers should already be removed at this point,
488 * just kill our (empty) hash tables here.
490 g_hash_table_destroy (priv->cell_info);
491 g_hash_table_destroy (priv->focus_siblings);
493 g_free (priv->current_path);
495 G_OBJECT_CLASS (gtk_cell_area_parent_class)->finalize (object);
500 gtk_cell_area_dispose (GObject *object)
502 /* This removes every cell renderer that may be added to the GtkCellArea,
503 * subclasses should be breaking references to the GtkCellRenderers
506 gtk_cell_layout_clear (GTK_CELL_LAYOUT (object));
508 /* Remove any ref to a focused/edited cell */
509 gtk_cell_area_set_focus_cell (GTK_CELL_AREA (object), NULL);
510 gtk_cell_area_set_edited_cell (GTK_CELL_AREA (object), NULL);
511 gtk_cell_area_set_edit_widget (GTK_CELL_AREA (object), NULL);
513 G_OBJECT_CLASS (gtk_cell_area_parent_class)->dispose (object);
517 gtk_cell_area_set_property (GObject *object,
522 GtkCellArea *area = GTK_CELL_AREA (object);
526 case PROP_FOCUS_CELL:
527 gtk_cell_area_set_focus_cell (area, (GtkCellRenderer *)g_value_get_object (value));
530 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
536 gtk_cell_area_get_property (GObject *object,
541 GtkCellArea *area = GTK_CELL_AREA (object);
542 GtkCellAreaPrivate *priv = area->priv;
546 case PROP_FOCUS_CELL:
547 g_value_set_object (value, priv->focus_cell);
549 case PROP_EDITED_CELL:
550 g_value_set_object (value, priv->edited_cell);
552 case PROP_EDIT_WIDGET:
553 g_value_set_object (value, priv->edit_widget);
556 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
561 /*************************************************************
563 *************************************************************/
565 gtk_cell_area_real_event (GtkCellArea *area,
566 GtkCellAreaContext *context,
569 const GdkRectangle *cell_area,
570 GtkCellRendererState flags)
572 GtkCellAreaPrivate *priv = area->priv;
574 if (event->type == GDK_KEY_PRESS && (flags & GTK_CELL_RENDERER_FOCUSED) != 0)
576 GdkEventKey *key_event = (GdkEventKey *)event;
578 /* Cancel any edits in progress */
579 if (priv->edited_cell && (key_event->keyval == GDK_KEY_Escape))
581 gtk_cell_area_stop_editing (area, TRUE);
590 apply_cell_attributes (GtkCellRenderer *renderer,
594 CellAttribute *attribute;
596 GValue value = { 0, };
597 gboolean is_expander;
598 gboolean is_expanded;
600 g_object_freeze_notify (G_OBJECT (renderer));
602 /* Whether a row expands or is presently expanded can only be
603 * provided by the view (as these states can vary across views
604 * accessing the same model).
606 g_object_get (renderer, "is-expander", &is_expander, NULL);
607 if (is_expander != data->is_expander)
608 g_object_set (renderer, "is-expander", data->is_expander, NULL);
610 g_object_get (renderer, "is-expanded", &is_expanded, NULL);
611 if (is_expanded != data->is_expanded)
612 g_object_set (renderer, "is-expanded", data->is_expanded, NULL);
614 /* Apply the attributes directly to the renderer */
615 for (list = info->attributes; list; list = list->next)
617 attribute = list->data;
619 gtk_tree_model_get_value (data->model, data->iter, attribute->column, &value);
620 g_object_set_property (G_OBJECT (renderer), attribute->attribute, &value);
621 g_value_unset (&value);
624 /* Call any GtkCellLayoutDataFunc that may have been set by the user
627 info->func (GTK_CELL_LAYOUT (data->area), renderer,
628 data->model, data->iter, info->data);
630 g_object_thaw_notify (G_OBJECT (renderer));
634 gtk_cell_area_real_apply_attributes (GtkCellArea *area,
635 GtkTreeModel *tree_model,
637 gboolean is_expander,
638 gboolean is_expanded)
641 GtkCellAreaPrivate *priv;
647 /* Feed in data needed to apply to every renderer */
649 data.model = tree_model;
651 data.is_expander = is_expander;
652 data.is_expanded = is_expanded;
654 /* Go over any cells that have attributes or custom GtkCellLayoutDataFuncs and
655 * apply the data from the treemodel */
656 g_hash_table_foreach (priv->cell_info, (GHFunc)apply_cell_attributes, &data);
658 /* Update the currently applied path */
659 g_free (priv->current_path);
660 path = gtk_tree_model_get_path (tree_model, iter);
661 priv->current_path = gtk_tree_path_to_string (path);
662 gtk_tree_path_free (path);
666 gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area,
667 GtkCellAreaContext *context,
670 gint *minimum_height,
671 gint *natural_height)
673 /* If the area doesnt do height-for-width, fallback on base preferred height */
674 GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, context, widget, minimum_height, natural_height);
678 gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area,
679 GtkCellAreaContext *context,
685 /* If the area doesnt do width-for-height, fallback on base preferred width */
686 GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, context, widget, minimum_width, natural_width);
690 get_can_focus (GtkCellRenderer *renderer,
694 if (gtk_cell_renderer_can_focus (renderer))
699 gtk_cell_area_real_can_focus (GtkCellArea *area)
701 gboolean can_focus = FALSE;
703 /* Checks if any renderer can focus for the currently applied
706 * Subclasses can override this in the case that they are also
707 * rendering widgets as well as renderers.
709 gtk_cell_area_forall (area, (GtkCellCallback)get_can_focus, &can_focus);
715 gtk_cell_area_real_activate (GtkCellArea *area,
716 GtkCellAreaContext *context,
718 const GdkRectangle *cell_area,
719 GtkCellRendererState flags)
721 GtkCellAreaPrivate *priv = area->priv;
722 GdkRectangle background_area;
724 if (priv->focus_cell)
726 /* Get the allocation of the focused cell.
728 gtk_cell_area_get_cell_allocation (area, context, widget, priv->focus_cell,
729 cell_area, &background_area);
731 /* Activate or Edit the currently focused cell
733 * Currently just not sending an event, renderers afaics dont use
734 * the event argument anyway, worst case is we can synthesize one.
736 if (gtk_cell_area_activate_cell (area, widget, priv->focus_cell, NULL,
737 &background_area, flags))
744 /*************************************************************
745 * GtkCellLayoutIface *
746 *************************************************************/
748 gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface)
750 iface->pack_start = gtk_cell_area_pack_default;
751 iface->pack_end = gtk_cell_area_pack_default;
752 iface->clear = gtk_cell_area_clear;
753 iface->add_attribute = gtk_cell_area_add_attribute;
754 iface->set_cell_data_func = gtk_cell_area_set_cell_data_func;
755 iface->clear_attributes = gtk_cell_area_clear_attributes;
756 iface->reorder = gtk_cell_area_reorder;
757 iface->get_cells = gtk_cell_area_get_cells;
761 gtk_cell_area_pack_default (GtkCellLayout *cell_layout,
762 GtkCellRenderer *renderer,
765 gtk_cell_area_add (GTK_CELL_AREA (cell_layout), renderer);
769 gtk_cell_area_clear (GtkCellLayout *cell_layout)
771 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
773 gtk_cell_layout_get_cells (cell_layout);
775 for (l = cells; l; l = l->next)
777 GtkCellRenderer *renderer = l->data;
778 gtk_cell_area_remove (area, renderer);
785 gtk_cell_area_add_attribute (GtkCellLayout *cell_layout,
786 GtkCellRenderer *renderer,
787 const gchar *attribute,
790 gtk_cell_area_attribute_connect (GTK_CELL_AREA (cell_layout),
791 renderer, attribute, column);
795 gtk_cell_area_set_cell_data_func (GtkCellLayout *cell_layout,
796 GtkCellRenderer *renderer,
797 GtkCellLayoutDataFunc func,
799 GDestroyNotify destroy)
801 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
802 GtkCellAreaPrivate *priv = area->priv;
805 info = g_hash_table_lookup (priv->cell_info, renderer);
809 if (info->destroy && info->data)
810 info->destroy (info->data);
815 info->data = func_data;
816 info->destroy = destroy;
822 info->destroy = NULL;
827 info = cell_info_new (func, func_data, destroy);
829 g_hash_table_insert (priv->cell_info, renderer, info);
834 gtk_cell_area_clear_attributes (GtkCellLayout *cell_layout,
835 GtkCellRenderer *renderer)
837 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
838 GtkCellAreaPrivate *priv = area->priv;
841 info = g_hash_table_lookup (priv->cell_info, renderer);
845 g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
846 g_slist_free (info->attributes);
848 info->attributes = NULL;
853 gtk_cell_area_reorder (GtkCellLayout *cell_layout,
854 GtkCellRenderer *cell,
857 g_warning ("GtkCellLayout::reorder not implemented for `%s'",
858 g_type_name (G_TYPE_FROM_INSTANCE (cell_layout)));
862 accum_cells (GtkCellRenderer *renderer,
865 *accum = g_list_prepend (*accum, renderer);
869 gtk_cell_area_get_cells (GtkCellLayout *cell_layout)
873 gtk_cell_area_forall (GTK_CELL_AREA (cell_layout),
874 (GtkCellCallback)accum_cells,
877 return g_list_reverse (cells);
881 /*************************************************************
883 *************************************************************/
887 * @area: a #GtkCellArea
888 * @renderer: the #GtkCellRenderer to add to @area
890 * Adds @renderer to @area with the default child cell properties.
893 gtk_cell_area_add (GtkCellArea *area,
894 GtkCellRenderer *renderer)
896 GtkCellAreaClass *class;
898 g_return_if_fail (GTK_IS_CELL_AREA (area));
899 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
901 class = GTK_CELL_AREA_GET_CLASS (area);
904 class->add (area, renderer);
906 g_warning ("GtkCellAreaClass::add not implemented for `%s'",
907 g_type_name (G_TYPE_FROM_INSTANCE (area)));
911 * gtk_cell_area_remove:
912 * @area: a #GtkCellArea
913 * @renderer: the #GtkCellRenderer to add to @area
915 * Removes @renderer from @area.
918 gtk_cell_area_remove (GtkCellArea *area,
919 GtkCellRenderer *renderer)
921 GtkCellAreaClass *class;
922 GtkCellAreaPrivate *priv;
923 GList *renderers, *l;
925 g_return_if_fail (GTK_IS_CELL_AREA (area));
926 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
928 class = GTK_CELL_AREA_GET_CLASS (area);
931 /* Remove any custom attributes and custom cell data func here first */
932 g_hash_table_remove (priv->cell_info, renderer);
934 /* Remove focus siblings of this renderer */
935 g_hash_table_remove (priv->focus_siblings, renderer);
937 /* Remove this renderer from any focus renderer's sibling list */
938 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (area));
940 for (l = renderers; l; l = l->next)
942 GtkCellRenderer *focus_renderer = l->data;
944 if (gtk_cell_area_is_focus_sibling (area, focus_renderer, renderer))
946 gtk_cell_area_remove_focus_sibling (area, focus_renderer, renderer);
951 g_list_free (renderers);
954 class->remove (area, renderer);
956 g_warning ("GtkCellAreaClass::remove not implemented for `%s'",
957 g_type_name (G_TYPE_FROM_INSTANCE (area)));
961 get_has_renderer (GtkCellRenderer *renderer,
962 HasRendererCheck *check)
964 if (renderer == check->renderer)
965 check->has_renderer = TRUE;
969 * gtk_cell_area_has_renderer:
970 * @area: a #GtkCellArea
971 * @renderer: the #GtkCellRenderer to check
973 * Checks if @area contains @renderer.
975 * Returns: %TRUE if @renderer is in the @area.
978 gtk_cell_area_has_renderer (GtkCellArea *area,
979 GtkCellRenderer *renderer)
981 HasRendererCheck check = { renderer, FALSE };
983 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
984 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
986 gtk_cell_area_forall (area, (GtkCellCallback)get_has_renderer, &check);
988 return check.has_renderer;
992 * gtk_cell_area_forall
993 * @area: a #GtkCellArea
994 * @callback: the #GtkCellCallback to call
995 * @callback_data: user provided data pointer
997 * Calls @callback for every #GtkCellRenderer in @area.
1000 gtk_cell_area_forall (GtkCellArea *area,
1001 GtkCellCallback callback,
1002 gpointer callback_data)
1004 GtkCellAreaClass *class;
1006 g_return_if_fail (GTK_IS_CELL_AREA (area));
1007 g_return_if_fail (callback != NULL);
1009 class = GTK_CELL_AREA_GET_CLASS (area);
1012 class->forall (area, callback, callback_data);
1014 g_warning ("GtkCellAreaClass::forall not implemented for `%s'",
1015 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1019 * gtk_cell_area_get_cell_allocation:
1020 * @area: a #GtkCellArea
1021 * @context: the #GtkCellAreaContext used to hold sizes for @area.
1022 * @widget: the #GtkWidget that @area is rendering on
1023 * @renderer: the #GtkCellRenderer to get the allocation for
1024 * @cell_area: the whole allocated area for @area in @widget
1026 * @allocation: where to store the allocation for @renderer
1028 * Derives the allocation of @renderer inside @area if @area
1029 * were to be renderered in @cell_area.
1032 gtk_cell_area_get_cell_allocation (GtkCellArea *area,
1033 GtkCellAreaContext *context,
1035 GtkCellRenderer *renderer,
1036 const GdkRectangle *cell_area,
1037 GdkRectangle *allocation)
1039 GtkCellAreaClass *class;
1041 g_return_if_fail (GTK_IS_CELL_AREA (area));
1042 g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
1043 g_return_if_fail (GTK_IS_WIDGET (widget));
1044 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1045 g_return_if_fail (cell_area != NULL);
1046 g_return_if_fail (allocation != NULL);
1048 class = GTK_CELL_AREA_GET_CLASS (area);
1050 if (class->get_cell_allocation)
1051 class->get_cell_allocation (area, context, widget, renderer, cell_area, allocation);
1053 g_warning ("GtkCellAreaClass::get_cell_allocation not implemented for `%s'",
1054 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1058 * gtk_cell_area_event:
1059 * @area: a #GtkCellArea
1060 * @context: the #GtkCellAreaContext for this row of data.
1061 * @widget: the #GtkWidget that @area is rendering to
1062 * @event: the #GdkEvent to handle
1063 * @cell_area: the @widget relative coordinates for @area
1064 * @flags: the #GtkCellRendererState for @area in this row.
1066 * Delegates event handling to a #GtkCellArea.
1068 * Returns: %TRUE if the event was handled by @area.
1071 gtk_cell_area_event (GtkCellArea *area,
1072 GtkCellAreaContext *context,
1075 const GdkRectangle *cell_area,
1076 GtkCellRendererState flags)
1078 GtkCellAreaClass *class;
1080 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1081 g_return_val_if_fail (GTK_IS_CELL_AREA_CONTEXT (context), 0);
1082 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
1083 g_return_val_if_fail (event != NULL, 0);
1084 g_return_val_if_fail (cell_area != NULL, 0);
1086 class = GTK_CELL_AREA_GET_CLASS (area);
1089 return class->event (area, context, widget, event, cell_area, flags);
1091 g_warning ("GtkCellAreaClass::event not implemented for `%s'",
1092 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1097 * gtk_cell_area_render:
1098 * @area: a #GtkCellArea
1099 * @context: the #GtkCellAreaContext for this row of data.
1100 * @widget: the #GtkWidget that @area is rendering to
1101 * @cr: the #cairo_t to render with
1102 * @background_area: the @widget relative coordinates for @area's background
1103 * @cell_area: the @widget relative coordinates for @area
1104 * @flags: the #GtkCellRendererState for @area in this row.
1105 * @paint_focus: whether @area should paint focus on focused cells for focused rows or not.
1107 * Renders @area's cells according to @area's layout onto @widget at
1108 * the given coordinates.
1111 gtk_cell_area_render (GtkCellArea *area,
1112 GtkCellAreaContext *context,
1115 const GdkRectangle *background_area,
1116 const GdkRectangle *cell_area,
1117 GtkCellRendererState flags,
1118 gboolean paint_focus)
1120 GtkCellAreaClass *class;
1122 g_return_if_fail (GTK_IS_CELL_AREA (area));
1123 g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
1124 g_return_if_fail (GTK_IS_WIDGET (widget));
1125 g_return_if_fail (cr != NULL);
1126 g_return_if_fail (background_area != NULL);
1127 g_return_if_fail (cell_area != NULL);
1129 class = GTK_CELL_AREA_GET_CLASS (area);
1132 class->render (area, context, widget, cr, background_area, cell_area, flags, paint_focus);
1134 g_warning ("GtkCellAreaClass::render not implemented for `%s'",
1135 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1139 * gtk_cell_area_set_style_detail:
1140 * @area: a #GtkCellArea
1141 * @detail: the #GtkStyle detail string to set
1143 * Sets the detail string used in any gtk_paint_*() functions
1147 gtk_cell_area_set_style_detail (GtkCellArea *area,
1148 const gchar *detail)
1150 GtkCellAreaPrivate *priv;
1152 g_return_if_fail (GTK_IS_CELL_AREA (area));
1156 if (g_strcmp0 (priv->style_detail, detail) != 0)
1158 g_free (priv->style_detail);
1159 priv->style_detail = g_strdup (detail);
1164 * gtk_cell_area_get_style_detail:
1165 * @area: a #GtkCellArea
1167 * Gets the detail string used in any gtk_paint_*() functions
1170 * Returns: the detail string.
1172 G_CONST_RETURN gchar *
1173 gtk_cell_area_get_style_detail (GtkCellArea *area)
1175 GtkCellAreaPrivate *priv;
1177 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1181 return priv->style_detail;
1184 /*************************************************************
1186 *************************************************************/
1188 * gtk_cell_area_create_context:
1189 * @area: a #GtkCellArea
1191 * Creates a #GtkCellAreaContext to be used with @area for
1192 * all purposes. #GtkCellAreaContext stores geometry information
1193 * for rows for which it was operated on, it is important to use
1194 * the same context for the same row of data at all times (i.e.
1195 * one should render and handle events with the same #GtkCellAreaContext
1196 * which was used to request the size of those rows of data).
1198 * Returns: a newly created #GtkCellAreaContext which can be used with @area.
1200 GtkCellAreaContext *
1201 gtk_cell_area_create_context (GtkCellArea *area)
1203 GtkCellAreaClass *class;
1205 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1207 class = GTK_CELL_AREA_GET_CLASS (area);
1209 if (class->create_context)
1210 return class->create_context (area);
1212 g_warning ("GtkCellAreaClass::create_context not implemented for `%s'",
1213 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1220 * gtk_cell_area_get_request_mode:
1221 * @area: a #GtkCellArea
1223 * Gets whether the area prefers a height-for-width layout
1224 * or a width-for-height layout.
1226 * Returns: The #GtkSizeRequestMode preferred by @area.
1231 gtk_cell_area_get_request_mode (GtkCellArea *area)
1233 GtkCellAreaClass *class;
1235 g_return_val_if_fail (GTK_IS_CELL_AREA (area),
1236 GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH);
1238 class = GTK_CELL_AREA_GET_CLASS (area);
1240 if (class->get_request_mode)
1241 return class->get_request_mode (area);
1243 g_warning ("GtkCellAreaClass::get_request_mode not implemented for `%s'",
1244 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1246 return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
1250 * gtk_cell_area_get_preferred_width:
1251 * @area: a #GtkCellArea
1252 * @context: the #GtkCellAreaContext to perform this request with
1253 * @widget: the #GtkWidget where @area will be rendering
1254 * @minimum_width: (out) (allow-none): location to store the minimum width, or %NULL
1255 * @natural_width: (out) (allow-none): location to store the natural width, or %NULL
1257 * Retrieves a cell area's initial minimum and natural width.
1259 * @area will store some geometrical information in @context along the way,
1260 * when requesting sizes over an arbitrary number of rows, its not important
1261 * to check the @minimum_width and @natural_width of this call but rather to
1262 * call gtk_cell_area_context_sum_preferred_width() and then consult
1263 * gtk_cell_area_context_get_preferred_width().
1269 gtk_cell_area_get_preferred_width (GtkCellArea *area,
1270 GtkCellAreaContext *context,
1272 gint *minimum_width,
1273 gint *natural_width)
1275 GtkCellAreaClass *class;
1277 g_return_if_fail (GTK_IS_CELL_AREA (area));
1278 g_return_if_fail (GTK_IS_WIDGET (widget));
1280 class = GTK_CELL_AREA_GET_CLASS (area);
1282 if (class->get_preferred_width)
1283 class->get_preferred_width (area, context, widget, minimum_width, natural_width);
1285 g_warning ("GtkCellAreaClass::get_preferred_width not implemented for `%s'",
1286 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1290 * gtk_cell_area_get_preferred_height_for_width:
1291 * @area: a #GtkCellArea
1292 * @context: the #GtkCellAreaContext which has already been requested for widths.
1293 * @widget: the #GtkWidget where @area will be rendering
1294 * @width: the width for which to check the height of this area
1295 * @minimum_height: (out) (allow-none): location to store the minimum height, or %NULL
1296 * @natural_height: (out) (allow-none): location to store the natural height, or %NULL
1298 * Retrieves a cell area's minimum and natural height if it would be given
1299 * the specified @width.
1301 * @area stores some geometrical information in @context along the way
1302 * while calling gtk_cell_area_get_preferred_width(), it's important to
1303 * perform a series of gtk_cell_area_get_preferred_width() requests with
1304 * @context first and then call gtk_cell_area_get_preferred_height_for_width()
1305 * on each cell area individually to get the height for width of each
1306 * fully requested row.
1308 * If at some point, the width of a single row changes, it should be
1309 * requested with gtk_cell_area_get_preferred_width() again and then
1310 * the full with of the requested rows checked again after calling
1311 * gtk_cell_area_context_sum_preferred_width(), and then the height
1312 * for width of each row needs to be requested again.
1317 gtk_cell_area_get_preferred_height_for_width (GtkCellArea *area,
1318 GtkCellAreaContext *context,
1321 gint *minimum_height,
1322 gint *natural_height)
1324 GtkCellAreaClass *class;
1326 g_return_if_fail (GTK_IS_CELL_AREA (area));
1327 g_return_if_fail (GTK_IS_WIDGET (widget));
1329 class = GTK_CELL_AREA_GET_CLASS (area);
1330 class->get_preferred_height_for_width (area, context, widget, width, minimum_height, natural_height);
1335 * gtk_cell_area_get_preferred_height:
1336 * @area: a #GtkCellArea
1337 * @context: the #GtkCellAreaContext to perform this request with
1338 * @widget: the #GtkWidget where @area will be rendering
1339 * @minimum_height: (out) (allow-none): location to store the minimum height, or %NULL
1340 * @natural_height: (out) (allow-none): location to store the natural height, or %NULL
1342 * Retrieves a cell area's initial minimum and natural height.
1344 * @area will store some geometrical information in @context along the way,
1345 * when requesting sizes over an arbitrary number of rows, its not important
1346 * to check the @minimum_height and @natural_height of this call but rather to
1347 * call gtk_cell_area_context_sum_preferred_height() and then consult
1348 * gtk_cell_area_context_get_preferred_height().
1353 gtk_cell_area_get_preferred_height (GtkCellArea *area,
1354 GtkCellAreaContext *context,
1356 gint *minimum_height,
1357 gint *natural_height)
1359 GtkCellAreaClass *class;
1361 g_return_if_fail (GTK_IS_CELL_AREA (area));
1362 g_return_if_fail (GTK_IS_WIDGET (widget));
1364 class = GTK_CELL_AREA_GET_CLASS (area);
1366 if (class->get_preferred_height)
1367 class->get_preferred_height (area, context, widget, minimum_height, natural_height);
1369 g_warning ("GtkCellAreaClass::get_preferred_height not implemented for `%s'",
1370 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1374 * gtk_cell_area_get_preferred_width_for_height:
1375 * @area: a #GtkCellArea
1376 * @context: the #GtkCellAreaContext which has already been requested for widths.
1377 * @widget: the #GtkWidget where @area will be rendering
1378 * @height: the height for which to check the width of this area
1379 * @minimum_width: (out) (allow-none): location to store the minimum width, or %NULL
1380 * @natural_width: (out) (allow-none): location to store the natural width, or %NULL
1382 * Retrieves a cell area's minimum and natural width if it would be given
1383 * the specified @height.
1385 * @area stores some geometrical information in @context along the way
1386 * while calling gtk_cell_area_get_preferred_height(), it's important to
1387 * perform a series of gtk_cell_area_get_preferred_height() requests with
1388 * @context first and then call gtk_cell_area_get_preferred_width_for_height()
1389 * on each cell area individually to get the height for width of each
1390 * fully requested row.
1392 * If at some point, the width of a single row changes, it should be
1393 * requested with gtk_cell_area_get_preferred_width() again and then
1394 * the full with of the requested rows checked again after calling
1395 * gtk_cell_area_context_sum_preferred_width(), and then the height
1396 * for width of each row needs to be requested again.
1401 gtk_cell_area_get_preferred_width_for_height (GtkCellArea *area,
1402 GtkCellAreaContext *context,
1405 gint *minimum_width,
1406 gint *natural_width)
1408 GtkCellAreaClass *class;
1410 g_return_if_fail (GTK_IS_CELL_AREA (area));
1411 g_return_if_fail (GTK_IS_WIDGET (widget));
1413 class = GTK_CELL_AREA_GET_CLASS (area);
1414 class->get_preferred_width_for_height (area, context, widget, height, minimum_width, natural_width);
1417 /*************************************************************
1419 *************************************************************/
1422 * gtk_cell_area_attribute_connect:
1423 * @area: a #GtkCellArea
1424 * @renderer: the #GtkCellRenderer to connect an attribute for
1425 * @attribute: the attribute name
1426 * @column: the #GtkTreeModel column to fetch attribute values from
1428 * Connects an @attribute to apply values from @column for the
1429 * #GtkTreeModel in use.
1432 gtk_cell_area_attribute_connect (GtkCellArea *area,
1433 GtkCellRenderer *renderer,
1434 const gchar *attribute,
1437 GtkCellAreaPrivate *priv;
1439 CellAttribute *cell_attribute;
1441 g_return_if_fail (GTK_IS_CELL_AREA (area));
1442 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1443 g_return_if_fail (attribute != NULL);
1444 g_return_if_fail (gtk_cell_area_has_renderer (area, renderer));
1447 info = g_hash_table_lookup (priv->cell_info, renderer);
1451 info = cell_info_new (NULL, NULL, NULL);
1453 g_hash_table_insert (priv->cell_info, renderer, info);
1459 /* Check we are not adding the same attribute twice */
1460 if ((node = g_slist_find_custom (info->attributes, attribute,
1461 (GCompareFunc)cell_attribute_find)) != NULL)
1463 cell_attribute = node->data;
1465 g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
1466 "since `%s' is already attributed to column %d",
1468 g_type_name (G_TYPE_FROM_INSTANCE (area)),
1469 attribute, cell_attribute->column);
1474 cell_attribute = cell_attribute_new (renderer, attribute, column);
1476 if (!cell_attribute)
1478 g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
1479 "since attribute does not exist",
1481 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1485 info->attributes = g_slist_prepend (info->attributes, cell_attribute);
1489 * gtk_cell_area_attribute_disconnect:
1490 * @area: a #GtkCellArea
1491 * @renderer: the #GtkCellRenderer to disconnect an attribute for
1492 * @attribute: the attribute name
1494 * Disconnects @attribute for the @renderer in @area so that
1495 * attribute will no longer be updated with values from the
1499 gtk_cell_area_attribute_disconnect (GtkCellArea *area,
1500 GtkCellRenderer *renderer,
1501 const gchar *attribute)
1503 GtkCellAreaPrivate *priv;
1505 CellAttribute *cell_attribute;
1508 g_return_if_fail (GTK_IS_CELL_AREA (area));
1509 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1510 g_return_if_fail (attribute != NULL);
1511 g_return_if_fail (gtk_cell_area_has_renderer (area, renderer));
1514 info = g_hash_table_lookup (priv->cell_info, renderer);
1518 node = g_slist_find_custom (info->attributes, attribute,
1519 (GCompareFunc)cell_attribute_find);
1522 cell_attribute = node->data;
1524 cell_attribute_free (cell_attribute);
1526 info->attributes = g_slist_delete_link (info->attributes, node);
1532 * gtk_cell_area_apply_attributes
1533 * @area: a #GtkCellArea
1534 * @tree_model: a #GtkTreeModel to pull values from
1535 * @iter: the #GtkTreeIter in @tree_model to apply values for
1536 * @is_expander: whether @iter has children
1537 * @is_expanded: whether @iter is expanded in the view and
1538 * children are visible
1540 * Applies any connected attributes to the renderers in
1541 * @area by pulling the values from @tree_model.
1544 gtk_cell_area_apply_attributes (GtkCellArea *area,
1545 GtkTreeModel *tree_model,
1547 gboolean is_expander,
1548 gboolean is_expanded)
1550 g_return_if_fail (GTK_IS_CELL_AREA (area));
1551 g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
1552 g_return_if_fail (iter != NULL);
1554 g_signal_emit (area, cell_area_signals[SIGNAL_APPLY_ATTRIBUTES], 0,
1555 tree_model, iter, is_expander, is_expanded);
1559 * gtk_cell_area_get_current_path_string:
1560 * @area: a #GtkCellArea
1562 * Gets the current #GtkTreePath string for the currently
1563 * applied #GtkTreeIter, this is implicitly updated when
1564 * gtk_cell_area_apply_attributes() is called and can be
1565 * used to interact with renderers from #GtkCellArea
1569 gtk_cell_area_get_current_path_string (GtkCellArea *area)
1571 GtkCellAreaPrivate *priv;
1573 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1577 return priv->current_path;
1581 /*************************************************************
1582 * API: Cell Properties *
1583 *************************************************************/
1585 * gtk_cell_area_class_install_cell_property:
1586 * @aclass: a #GtkCellAreaClass
1587 * @property_id: the id for the property
1588 * @pspec: the #GParamSpec for the property
1590 * Installs a cell property on a cell area class.
1593 gtk_cell_area_class_install_cell_property (GtkCellAreaClass *aclass,
1597 g_return_if_fail (GTK_IS_CELL_AREA_CLASS (aclass));
1598 g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1599 if (pspec->flags & G_PARAM_WRITABLE)
1600 g_return_if_fail (aclass->set_cell_property != NULL);
1601 if (pspec->flags & G_PARAM_READABLE)
1602 g_return_if_fail (aclass->get_cell_property != NULL);
1603 g_return_if_fail (property_id > 0);
1604 g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0); /* paranoid */
1605 g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0);
1607 if (g_param_spec_pool_lookup (cell_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (aclass), TRUE))
1609 g_warning (G_STRLOC ": class `%s' already contains a cell property named `%s'",
1610 G_OBJECT_CLASS_NAME (aclass), pspec->name);
1613 g_param_spec_ref (pspec);
1614 g_param_spec_sink (pspec);
1615 PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
1616 g_param_spec_pool_insert (cell_property_pool, pspec, G_OBJECT_CLASS_TYPE (aclass));
1620 * gtk_cell_area_class_find_cell_property:
1621 * @aclass: a #GtkCellAreaClass
1622 * @property_name: the name of the child property to find
1623 * @returns: (allow-none): the #GParamSpec of the child property or %NULL if @aclass has no
1624 * child property with that name.
1626 * Finds a cell property of a cell area class by name.
1629 gtk_cell_area_class_find_cell_property (GtkCellAreaClass *aclass,
1630 const gchar *property_name)
1632 g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
1633 g_return_val_if_fail (property_name != NULL, NULL);
1635 return g_param_spec_pool_lookup (cell_property_pool,
1637 G_OBJECT_CLASS_TYPE (aclass),
1642 * gtk_cell_area_class_list_cell_properties:
1643 * @aclass: a #GtkCellAreaClass
1644 * @n_properties: location to return the number of cell properties found
1645 * @returns: a newly allocated %NULL-terminated array of #GParamSpec*.
1646 * The array must be freed with g_free().
1648 * Returns all cell properties of a cell area class.
1651 gtk_cell_area_class_list_cell_properties (GtkCellAreaClass *aclass,
1652 guint *n_properties)
1654 GParamSpec **pspecs;
1657 g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
1659 pspecs = g_param_spec_pool_list (cell_property_pool,
1660 G_OBJECT_CLASS_TYPE (aclass),
1669 * gtk_cell_area_add_with_properties:
1670 * @area: a #GtkCellArea
1671 * @renderer: a #GtkCellRenderer to be placed inside @area
1672 * @first_prop_name: the name of the first cell property to set
1673 * @Varargs: a %NULL-terminated list of property names and values, starting
1674 * with @first_prop_name
1676 * Adds @renderer to @area, setting cell properties at the same time.
1677 * See gtk_cell_area_add() and gtk_cell_area_child_set() for more details.
1680 gtk_cell_area_add_with_properties (GtkCellArea *area,
1681 GtkCellRenderer *renderer,
1682 const gchar *first_prop_name,
1685 GtkCellAreaClass *class;
1687 g_return_if_fail (GTK_IS_CELL_AREA (area));
1688 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1690 class = GTK_CELL_AREA_GET_CLASS (area);
1696 class->add (area, renderer);
1698 va_start (var_args, first_prop_name);
1699 gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1703 g_warning ("GtkCellAreaClass::add not implemented for `%s'",
1704 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1708 * gtk_cell_area_cell_set:
1709 * @area: a #GtkCellArea
1710 * @renderer: a #GtkCellRenderer which is a cell inside @area
1711 * @first_prop_name: the name of the first cell property to set
1712 * @Varargs: a %NULL-terminated list of property names and values, starting
1713 * with @first_prop_name
1715 * Sets one or more cell properties for @cell in @area.
1718 gtk_cell_area_cell_set (GtkCellArea *area,
1719 GtkCellRenderer *renderer,
1720 const gchar *first_prop_name,
1725 g_return_if_fail (GTK_IS_CELL_AREA (area));
1726 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1728 va_start (var_args, first_prop_name);
1729 gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1734 * gtk_cell_area_cell_get:
1735 * @area: a #GtkCellArea
1736 * @renderer: a #GtkCellRenderer which is inside @area
1737 * @first_prop_name: the name of the first cell property to get
1738 * @Varargs: return location for the first cell property, followed
1739 * optionally by more name/return location pairs, followed by %NULL
1741 * Gets the values of one or more cell properties for @renderer in @area.
1744 gtk_cell_area_cell_get (GtkCellArea *area,
1745 GtkCellRenderer *renderer,
1746 const gchar *first_prop_name,
1751 g_return_if_fail (GTK_IS_CELL_AREA (area));
1752 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1754 va_start (var_args, first_prop_name);
1755 gtk_cell_area_cell_get_valist (area, renderer, first_prop_name, var_args);
1760 area_get_cell_property (GtkCellArea *area,
1761 GtkCellRenderer *renderer,
1765 GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1767 class->get_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), value, pspec);
1771 area_set_cell_property (GtkCellArea *area,
1772 GtkCellRenderer *renderer,
1774 const GValue *value)
1776 GValue tmp_value = { 0, };
1777 GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1779 /* provide a copy to work from, convert (if necessary) and validate */
1780 g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1781 if (!g_value_transform (value, &tmp_value))
1782 g_warning ("unable to set cell property `%s' of type `%s' from value of type `%s'",
1784 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1785 G_VALUE_TYPE_NAME (value));
1786 else if (g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION))
1788 gchar *contents = g_strdup_value_contents (value);
1790 g_warning ("value \"%s\" of type `%s' is invalid for property `%s' of type `%s'",
1792 G_VALUE_TYPE_NAME (value),
1794 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
1799 class->set_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec);
1801 g_value_unset (&tmp_value);
1805 * gtk_cell_area_cell_set_valist:
1806 * @area: a #GtkCellArea
1807 * @renderer: a #GtkCellRenderer which inside @area
1808 * @first_property_name: the name of the first cell property to set
1809 * @var_args: a %NULL-terminated list of property names and values, starting
1810 * with @first_prop_name
1812 * Sets one or more cell properties for @renderer in @area.
1815 gtk_cell_area_cell_set_valist (GtkCellArea *area,
1816 GtkCellRenderer *renderer,
1817 const gchar *first_property_name,
1822 g_return_if_fail (GTK_IS_CELL_AREA (area));
1823 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1825 name = first_property_name;
1828 GValue value = { 0, };
1829 gchar *error = NULL;
1831 g_param_spec_pool_lookup (cell_property_pool, name,
1832 G_OBJECT_TYPE (area), TRUE);
1835 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1836 G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1839 if (!(pspec->flags & G_PARAM_WRITABLE))
1841 g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1842 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1846 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1847 G_VALUE_COLLECT (&value, var_args, 0, &error);
1850 g_warning ("%s: %s", G_STRLOC, error);
1853 /* we purposely leak the value here, it might not be
1854 * in a sane state if an error condition occoured
1858 area_set_cell_property (area, renderer, pspec, &value);
1859 g_value_unset (&value);
1860 name = va_arg (var_args, gchar*);
1865 * gtk_cell_area_cell_get_valist:
1866 * @area: a #GtkCellArea
1867 * @renderer: a #GtkCellRenderer inside @area
1868 * @first_property_name: the name of the first property to get
1869 * @var_args: return location for the first property, followed
1870 * optionally by more name/return location pairs, followed by %NULL
1872 * Gets the values of one or more cell properties for @renderer in @area.
1875 gtk_cell_area_cell_get_valist (GtkCellArea *area,
1876 GtkCellRenderer *renderer,
1877 const gchar *first_property_name,
1882 g_return_if_fail (GTK_IS_CELL_AREA (area));
1883 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1885 name = first_property_name;
1888 GValue value = { 0, };
1892 pspec = g_param_spec_pool_lookup (cell_property_pool, name,
1893 G_OBJECT_TYPE (area), TRUE);
1896 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1897 G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1900 if (!(pspec->flags & G_PARAM_READABLE))
1902 g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1903 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1907 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1908 area_get_cell_property (area, renderer, pspec, &value);
1909 G_VALUE_LCOPY (&value, var_args, 0, &error);
1912 g_warning ("%s: %s", G_STRLOC, error);
1914 g_value_unset (&value);
1917 g_value_unset (&value);
1918 name = va_arg (var_args, gchar*);
1923 * gtk_cell_area_cell_set_property:
1924 * @area: a #GtkCellArea
1925 * @renderer: a #GtkCellRenderer inside @area
1926 * @property_name: the name of the cell property to set
1927 * @value: the value to set the cell property to
1929 * Sets a cell property for @renderer in @area.
1932 gtk_cell_area_cell_set_property (GtkCellArea *area,
1933 GtkCellRenderer *renderer,
1934 const gchar *property_name,
1935 const GValue *value)
1939 g_return_if_fail (GTK_IS_CELL_AREA (area));
1940 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1941 g_return_if_fail (property_name != NULL);
1942 g_return_if_fail (G_IS_VALUE (value));
1944 pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1945 G_OBJECT_TYPE (area), TRUE);
1947 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1948 G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1949 else if (!(pspec->flags & G_PARAM_WRITABLE))
1950 g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1951 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1954 area_set_cell_property (area, renderer, pspec, value);
1959 * gtk_cell_area_cell_get_property:
1960 * @area: a #GtkCellArea
1961 * @renderer: a #GtkCellRenderer inside @area
1962 * @property_name: the name of the property to get
1963 * @value: a location to return the value
1965 * Gets the value of a cell property for @renderer in @area.
1968 gtk_cell_area_cell_get_property (GtkCellArea *area,
1969 GtkCellRenderer *renderer,
1970 const gchar *property_name,
1975 g_return_if_fail (GTK_IS_CELL_AREA (area));
1976 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1977 g_return_if_fail (property_name != NULL);
1978 g_return_if_fail (G_IS_VALUE (value));
1980 pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1981 G_OBJECT_TYPE (area), TRUE);
1983 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1984 G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1985 else if (!(pspec->flags & G_PARAM_READABLE))
1986 g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1987 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1990 GValue *prop_value, tmp_value = { 0, };
1992 /* auto-conversion of the callers value type
1994 if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
1996 g_value_reset (value);
1999 else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
2001 g_warning ("can't retrieve cell property `%s' of type `%s' as value of type `%s'",
2003 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
2004 G_VALUE_TYPE_NAME (value));
2009 g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
2010 prop_value = &tmp_value;
2013 area_get_cell_property (area, renderer, pspec, prop_value);
2015 if (prop_value != value)
2017 g_value_transform (prop_value, value);
2018 g_value_unset (&tmp_value);
2023 /*************************************************************
2025 *************************************************************/
2028 * gtk_cell_area_can_focus:
2029 * @area: a #GtkCellArea
2031 * Returns whether the area can receive keyboard focus,
2032 * after applying new attributes to @area.
2034 * Returns: whether @area can receive focus.
2037 gtk_cell_area_can_focus (GtkCellArea *area)
2039 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2041 return GTK_CELL_AREA_GET_CLASS (area)->can_focus (area);
2045 * gtk_cell_area_focus:
2046 * @area: a #GtkCellArea
2047 * @direction: the #GtkDirectionType
2049 * This should be called by the @area's owning layout widget
2050 * when focus is to be passed to @area, or moved within @area
2051 * for a given @direction and row data.
2053 * Implementing #GtkCellArea classes should implement this
2054 * method to receive and navigate focus in it's own way particular
2055 * to how it lays out cells.
2057 * Returns: %TRUE if focus remains inside @area as a result of this call.
2060 gtk_cell_area_focus (GtkCellArea *area,
2061 GtkDirectionType direction)
2063 GtkCellAreaClass *class;
2065 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2067 class = GTK_CELL_AREA_GET_CLASS (area);
2070 return class->focus (area, direction);
2072 g_warning ("GtkCellAreaClass::focus not implemented for `%s'",
2073 g_type_name (G_TYPE_FROM_INSTANCE (area)));
2079 * gtk_cell_area_activate:
2080 * @area: a #GtkCellArea
2081 * @context: the #GtkCellAreaContext in context with the current row data
2082 * @widget: the #GtkWidget that @area is rendering on
2083 * @cell_area: the size and location of @area relative to @widget's allocation
2084 * @flags: the #GtkCellRendererState flags for @area for this row of data.
2086 * Activates @area, usually by activating the currently focused
2087 * cell, however some subclasses which embed widgets in the area
2088 * can also activate a widget if it currently has the focus.
2090 * Returns: Whether @area was successfully activated.
2093 gtk_cell_area_activate (GtkCellArea *area,
2094 GtkCellAreaContext *context,
2096 const GdkRectangle *cell_area,
2097 GtkCellRendererState flags)
2099 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2101 return GTK_CELL_AREA_GET_CLASS (area)->activate (area, context, widget, cell_area, flags);
2106 * gtk_cell_area_set_focus_cell:
2107 * @area: a #GtkCellArea
2108 * @focus_cell: the #GtkCellRenderer to give focus to
2110 * This is generally called from #GtkCellArea implementations
2111 * either gtk_cell_area_grab_focus() or gtk_cell_area_update_focus()
2112 * is called. It's also up to the #GtkCellArea implementation
2113 * to update the focused cell when receiving events from
2114 * gtk_cell_area_event() appropriately.
2117 gtk_cell_area_set_focus_cell (GtkCellArea *area,
2118 GtkCellRenderer *renderer)
2120 GtkCellAreaPrivate *priv;
2122 g_return_if_fail (GTK_IS_CELL_AREA (area));
2123 g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer));
2127 if (priv->focus_cell != renderer)
2129 if (priv->focus_cell)
2130 g_object_unref (priv->focus_cell);
2132 priv->focus_cell = renderer;
2134 if (priv->focus_cell)
2135 g_object_ref (priv->focus_cell);
2137 g_object_notify (G_OBJECT (area), "focus-cell");
2140 /* Signal that the current focus renderer for this path changed
2141 * (it may be that the focus cell did not change, but the row
2142 * may have changed so we need to signal it) */
2143 g_signal_emit (area, cell_area_signals[SIGNAL_FOCUS_CHANGED], 0,
2144 priv->focus_cell, priv->current_path);
2149 * gtk_cell_area_get_focus_cell:
2150 * @area: a #GtkCellArea
2152 * Retrieves the currently focused cell for @area
2154 * Returns: the currently focused cell in @area.
2157 gtk_cell_area_get_focus_cell (GtkCellArea *area)
2159 GtkCellAreaPrivate *priv;
2161 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2165 return priv->focus_cell;
2169 /*************************************************************
2170 * API: Focus Siblings *
2171 *************************************************************/
2174 * gtk_cell_area_add_focus_sibling:
2175 * @area: a #GtkCellArea
2176 * @renderer: the #GtkCellRenderer expected to have focus
2177 * @sibling: the #GtkCellRenderer to add to @renderer's focus area
2179 * Adds @sibling to @renderer's focusable area, focus will be drawn
2180 * around @renderer and all of it's siblings if @renderer can
2181 * focus for a given row.
2183 * Events handled by focus siblings can also activate the given
2184 * focusable @renderer.
2187 gtk_cell_area_add_focus_sibling (GtkCellArea *area,
2188 GtkCellRenderer *renderer,
2189 GtkCellRenderer *sibling)
2191 GtkCellAreaPrivate *priv;
2194 g_return_if_fail (GTK_IS_CELL_AREA (area));
2195 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2196 g_return_if_fail (GTK_IS_CELL_RENDERER (sibling));
2197 g_return_if_fail (renderer != sibling);
2198 g_return_if_fail (gtk_cell_area_has_renderer (area, renderer));
2199 g_return_if_fail (gtk_cell_area_has_renderer (area, sibling));
2200 g_return_if_fail (!gtk_cell_area_is_focus_sibling (area, renderer, sibling));
2202 /* XXX We should also check that sibling is not in any other renderer's sibling
2203 * list already, a renderer can be sibling of only one focusable renderer
2209 siblings = g_hash_table_lookup (priv->focus_siblings, renderer);
2212 siblings = g_list_append (siblings, sibling);
2215 siblings = g_list_append (siblings, sibling);
2216 g_hash_table_insert (priv->focus_siblings, renderer, siblings);
2221 * gtk_cell_area_remove_focus_sibling:
2222 * @area: a #GtkCellArea
2223 * @renderer: the #GtkCellRenderer expected to have focus
2224 * @sibling: the #GtkCellRenderer to remove from @renderer's focus area
2226 * Removes @sibling from @renderer's focus sibling list
2227 * (see gtk_cell_area_add_focus_sibling()).
2230 gtk_cell_area_remove_focus_sibling (GtkCellArea *area,
2231 GtkCellRenderer *renderer,
2232 GtkCellRenderer *sibling)
2234 GtkCellAreaPrivate *priv;
2237 g_return_if_fail (GTK_IS_CELL_AREA (area));
2238 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2239 g_return_if_fail (GTK_IS_CELL_RENDERER (sibling));
2240 g_return_if_fail (gtk_cell_area_is_focus_sibling (area, renderer, sibling));
2244 siblings = g_hash_table_lookup (priv->focus_siblings, renderer);
2246 siblings = g_list_copy (siblings);
2247 siblings = g_list_remove (siblings, sibling);
2250 g_hash_table_remove (priv->focus_siblings, renderer);
2252 g_hash_table_insert (priv->focus_siblings, renderer, siblings);
2256 * gtk_cell_area_is_focus_sibling:
2257 * @area: a #GtkCellArea
2258 * @renderer: the #GtkCellRenderer expected to have focus
2259 * @sibling: the #GtkCellRenderer to check against @renderer's sibling list
2261 * Returns %TRUE if @sibling is one of @renderer's focus siblings
2262 * (see gtk_cell_area_add_focus_sibling()).
2265 gtk_cell_area_is_focus_sibling (GtkCellArea *area,
2266 GtkCellRenderer *renderer,
2267 GtkCellRenderer *sibling)
2269 GtkCellAreaPrivate *priv;
2270 GList *siblings, *l;
2272 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2273 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
2274 g_return_val_if_fail (GTK_IS_CELL_RENDERER (sibling), FALSE);
2278 siblings = g_hash_table_lookup (priv->focus_siblings, renderer);
2280 for (l = siblings; l; l = l->next)
2282 GtkCellRenderer *a_sibling = l->data;
2284 if (a_sibling == sibling)
2292 * gtk_cell_area_get_focus_siblings:
2293 * @area: a #GtkCellArea
2294 * @renderer: the #GtkCellRenderer expected to have focus
2296 * Gets the focus sibling cell renderers for @renderer.
2298 * Returns: A #GList of #GtkCellRenderers. The returned list is internal and should not be freed.
2301 gtk_cell_area_get_focus_siblings (GtkCellArea *area,
2302 GtkCellRenderer *renderer)
2304 GtkCellAreaPrivate *priv;
2306 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2307 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), NULL);
2311 return g_hash_table_lookup (priv->focus_siblings, renderer);
2315 * gtk_cell_area_get_focus_from_sibling:
2316 * @area: a #GtkCellArea
2317 * @renderer: the #GtkCellRenderer
2319 * Gets the #GtkCellRenderer which is expected to be focusable
2320 * for which @renderer is, or may be a sibling.
2322 * This is handy for #GtkCellArea subclasses when handling events,
2323 * after determining the renderer at the event location it can
2324 * then chose to activate the focus cell for which the event
2325 * cell may have been a sibling.
2327 * Returns: the #GtkCellRenderer for which @renderer is a sibling, or %NULL.
2330 gtk_cell_area_get_focus_from_sibling (GtkCellArea *area,
2331 GtkCellRenderer *renderer)
2333 GtkCellRenderer *ret_renderer = NULL;
2334 GList *renderers, *l;
2336 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2337 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), NULL);
2339 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (area));
2341 for (l = renderers; l; l = l->next)
2343 GtkCellRenderer *a_renderer = l->data;
2346 for (list = gtk_cell_area_get_focus_siblings (area, a_renderer);
2347 list; list = list->next)
2349 GtkCellRenderer *sibling_renderer = list->data;
2351 if (sibling_renderer == renderer)
2353 ret_renderer = a_renderer;
2358 g_list_free (renderers);
2360 return ret_renderer;
2363 /*************************************************************
2364 * API: Cell Activation/Editing *
2365 *************************************************************/
2367 gtk_cell_area_add_editable (GtkCellArea *area,
2368 GtkCellRenderer *renderer,
2369 GtkCellEditable *editable,
2370 GdkRectangle *cell_area)
2372 g_signal_emit (area, cell_area_signals[SIGNAL_ADD_EDITABLE], 0,
2373 renderer, editable, cell_area, area->priv->current_path);
2377 gtk_cell_area_remove_editable (GtkCellArea *area,
2378 GtkCellRenderer *renderer,
2379 GtkCellEditable *editable)
2381 g_signal_emit (area, cell_area_signals[SIGNAL_REMOVE_EDITABLE], 0, renderer, editable);
2385 cell_area_remove_widget_cb (GtkCellEditable *editable,
2388 GtkCellAreaPrivate *priv = area->priv;
2390 g_assert (priv->edit_widget == editable);
2391 g_assert (priv->edited_cell != NULL);
2393 gtk_cell_area_remove_editable (area, priv->edited_cell, priv->edit_widget);
2395 /* Now that we're done with editing the widget and it can be removed,
2396 * remove our references to the widget and disconnect handlers */
2397 gtk_cell_area_set_edited_cell (area, NULL);
2398 gtk_cell_area_set_edit_widget (area, NULL);
2402 gtk_cell_area_set_edited_cell (GtkCellArea *area,
2403 GtkCellRenderer *renderer)
2405 GtkCellAreaPrivate *priv;
2407 g_return_if_fail (GTK_IS_CELL_AREA (area));
2408 g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer));
2412 if (priv->edited_cell != renderer)
2414 if (priv->edited_cell)
2415 g_object_unref (priv->edited_cell);
2417 priv->edited_cell = renderer;
2419 if (priv->edited_cell)
2420 g_object_ref (priv->edited_cell);
2422 g_object_notify (G_OBJECT (area), "edited-cell");
2427 gtk_cell_area_set_edit_widget (GtkCellArea *area,
2428 GtkCellEditable *editable)
2430 GtkCellAreaPrivate *priv;
2432 g_return_if_fail (GTK_IS_CELL_AREA (area));
2433 g_return_if_fail (editable == NULL || GTK_IS_CELL_EDITABLE (editable));
2437 if (priv->edit_widget != editable)
2439 if (priv->edit_widget)
2441 g_signal_handler_disconnect (priv->edit_widget, priv->remove_widget_id);
2443 g_object_unref (priv->edit_widget);
2446 priv->edit_widget = editable;
2448 if (priv->edit_widget)
2450 priv->remove_widget_id =
2451 g_signal_connect (priv->edit_widget, "remove-widget",
2452 G_CALLBACK (cell_area_remove_widget_cb), area);
2454 g_object_ref (priv->edit_widget);
2457 g_object_notify (G_OBJECT (area), "edit-widget");
2462 * gtk_cell_area_get_edited_cell:
2463 * @area: a #GtkCellArea
2465 * Gets the #GtkCellRenderer in @area that is currently
2468 * Returns: The currently edited #GtkCellRenderer
2471 gtk_cell_area_get_edited_cell (GtkCellArea *area)
2473 GtkCellAreaPrivate *priv;
2475 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2479 return priv->edited_cell;
2483 * gtk_cell_area_get_edit_widget:
2484 * @area: a #GtkCellArea
2486 * Gets the #GtkCellEditable widget currently used
2487 * to edit the currently edited cell.
2489 * Returns: The currently active #GtkCellEditable widget
2492 gtk_cell_area_get_edit_widget (GtkCellArea *area)
2494 GtkCellAreaPrivate *priv;
2496 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2500 return priv->edit_widget;
2504 * gtk_cell_area_activate_cell:
2505 * @area: a #GtkCellArea
2506 * @widget: the #GtkWidget that @area is rendering onto
2507 * @renderer: the #GtkCellRenderer in @area to activate
2508 * @event: the #GdkEvent for which cell activation should occur
2509 * @cell_area: the #GdkRectangle in @widget relative coordinates
2510 * of @renderer for the current row.
2511 * @flags: the #GtkCellRendererState for @renderer
2513 * This is used by #GtkCellArea subclasses when handling events
2514 * to activate cells, the base #GtkCellArea class activates cells
2515 * for keyboard events for free in it's own GtkCellArea->activate()
2518 * Returns: whether cell activation was successful
2521 gtk_cell_area_activate_cell (GtkCellArea *area,
2523 GtkCellRenderer *renderer,
2525 const GdkRectangle *cell_area,
2526 GtkCellRendererState flags)
2528 GtkCellRendererMode mode;
2529 GdkRectangle inner_area;
2530 GtkCellAreaPrivate *priv;
2532 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2533 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
2534 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
2535 g_return_val_if_fail (cell_area != NULL, FALSE);
2539 /* Remove margins from the background area to produce the cell area.
2541 * XXX Maybe have to do some rtl mode treatment here...
2543 gtk_cell_area_inner_cell_area (area, widget, cell_area, &inner_area);
2545 g_object_get (renderer, "mode", &mode, NULL);
2547 if (mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
2549 if (gtk_cell_renderer_activate (renderer,
2557 else if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
2559 GtkCellEditable *editable_widget;
2562 gtk_cell_renderer_start_editing (renderer,
2569 if (editable_widget != NULL)
2571 GdkRectangle edit_area;
2573 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (editable_widget), FALSE);
2575 gtk_cell_area_set_edited_cell (area, renderer);
2576 gtk_cell_area_set_edit_widget (area, editable_widget);
2578 gtk_cell_renderer_get_aligned_area (renderer, widget, flags, &inner_area, &edit_area);
2580 /* Signal that editing started so that callers can get
2581 * a handle on the editable_widget */
2582 gtk_cell_area_add_editable (area, priv->focus_cell, editable_widget, &edit_area);
2584 /* If the signal was successfully handled start the editing */
2585 if (gtk_widget_get_parent (GTK_WIDGET (editable_widget)))
2587 gtk_cell_editable_start_editing (editable_widget, NULL);
2588 gtk_widget_grab_focus (GTK_WIDGET (editable_widget));
2592 /* Otherwise clear the editing state and fire a warning */
2593 gtk_cell_area_set_edited_cell (area, NULL);
2594 gtk_cell_area_set_edit_widget (area, NULL);
2596 g_warning ("GtkCellArea::add-editable fired in the dark, no cell editing was started.");
2607 * gtk_cell_area_stop_editing:
2608 * @area: a #GtkCellArea
2609 * @canceled: whether editing was canceled.
2611 * Explicitly stops the editing of the currently
2612 * edited cell (see gtk_cell_area_get_edited_cell()).
2614 * If @canceled is %TRUE, the cell renderer will emit
2615 * the ::editing-canceled signal.
2618 gtk_cell_area_stop_editing (GtkCellArea *area,
2621 GtkCellAreaPrivate *priv;
2623 g_return_if_fail (GTK_IS_CELL_AREA (area));
2627 if (priv->edited_cell)
2629 GtkCellEditable *edit_widget = g_object_ref (priv->edit_widget);
2630 GtkCellRenderer *edit_cell = g_object_ref (priv->edited_cell);
2632 /* Stop editing of the cell renderer */
2633 gtk_cell_renderer_stop_editing (priv->edited_cell, canceled);
2635 /* Remove any references to the editable widget */
2636 gtk_cell_area_set_edited_cell (area, NULL);
2637 gtk_cell_area_set_edit_widget (area, NULL);
2639 /* Send the remove-widget signal explicitly (this is done after setting
2640 * the edit cell/widget NULL to avoid feedback)
2642 gtk_cell_area_remove_editable (area, edit_cell, edit_widget);
2643 g_object_unref (edit_cell);
2644 g_object_unref (edit_widget);
2648 /*************************************************************
2649 * API: Convenience for area implementations *
2650 *************************************************************/
2653 gtk_cell_area_inner_cell_area (GtkCellArea *area,
2655 const GdkRectangle *cell_area,
2656 GdkRectangle *inner_area)
2658 gint focus_line_width;
2660 g_return_if_fail (GTK_IS_CELL_AREA (area));
2661 g_return_if_fail (GTK_IS_WIDGET (widget));
2662 g_return_if_fail (cell_area != NULL);
2663 g_return_if_fail (inner_area != NULL);
2665 gtk_widget_style_get (widget, "focus-line-width", &focus_line_width, NULL);
2667 *inner_area = *cell_area;
2669 inner_area->x += focus_line_width;
2670 inner_area->width -= focus_line_width * 2;
2671 inner_area->y += focus_line_width;
2672 inner_area->height -= focus_line_width * 2;
2676 gtk_cell_area_request_renderer (GtkCellArea *area,
2677 GtkCellRenderer *renderer,
2678 GtkOrientation orientation,
2684 GtkCellAreaPrivate *priv;
2685 gint focus_line_width;
2687 g_return_if_fail (GTK_IS_CELL_AREA (area));
2688 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2689 g_return_if_fail (GTK_IS_WIDGET (widget));
2690 g_return_if_fail (minimum_size != NULL);
2691 g_return_if_fail (natural_size != NULL);
2695 gtk_widget_style_get (widget, "focus-line-width", &focus_line_width, NULL);
2697 focus_line_width *= 2;
2699 if (orientation == GTK_ORIENTATION_HORIZONTAL)
2702 gtk_cell_renderer_get_preferred_width (renderer, widget, minimum_size, natural_size);
2705 for_size = MAX (0, for_size - focus_line_width);
2707 gtk_cell_renderer_get_preferred_width_for_height (renderer, widget, for_size,
2708 minimum_size, natural_size);
2711 else /* GTK_ORIENTATION_VERTICAL */
2714 gtk_cell_renderer_get_preferred_height (renderer, widget, minimum_size, natural_size);
2717 for_size = MAX (0, for_size - focus_line_width);
2719 gtk_cell_renderer_get_preferred_height_for_width (renderer, widget, for_size,
2720 minimum_size, natural_size);
2724 *minimum_size += focus_line_width;
2725 *natural_size += focus_line_width;