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_get_preferred_height_for_width (GtkCellArea *area,
60 GtkCellAreaContext *context,
64 gint *natural_height);
65 static void gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area,
66 GtkCellAreaContext *context,
71 static gboolean gtk_cell_area_real_can_focus (GtkCellArea *area);
72 static gboolean gtk_cell_area_real_activate (GtkCellArea *area,
73 GtkCellAreaContext *context,
75 const GdkRectangle *cell_area,
76 GtkCellRendererState flags);
78 /* GtkCellLayoutIface */
79 static void gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface);
80 static void gtk_cell_area_pack_default (GtkCellLayout *cell_layout,
81 GtkCellRenderer *renderer,
83 static void gtk_cell_area_clear (GtkCellLayout *cell_layout);
84 static void gtk_cell_area_add_attribute (GtkCellLayout *cell_layout,
85 GtkCellRenderer *renderer,
86 const gchar *attribute,
88 static void gtk_cell_area_set_cell_data_func (GtkCellLayout *cell_layout,
89 GtkCellRenderer *cell,
90 GtkCellLayoutDataFunc func,
92 GDestroyNotify destroy);
93 static void gtk_cell_area_clear_attributes (GtkCellLayout *cell_layout,
94 GtkCellRenderer *renderer);
95 static void gtk_cell_area_reorder (GtkCellLayout *cell_layout,
96 GtkCellRenderer *cell,
98 static GList *gtk_cell_area_get_cells (GtkCellLayout *cell_layout);
101 /* Used in forall loop to check if a child renderer is present */
103 GtkCellRenderer *renderer;
104 gboolean has_renderer;
107 /* Attribute/Cell metadata */
109 const gchar *attribute;
116 GtkCellLayoutDataFunc func;
118 GDestroyNotify destroy;
121 static CellInfo *cell_info_new (GtkCellLayoutDataFunc func,
123 GDestroyNotify destroy);
124 static void cell_info_free (CellInfo *info);
125 static CellAttribute *cell_attribute_new (GtkCellRenderer *renderer,
126 const gchar *attribute,
128 static void cell_attribute_free (CellAttribute *attribute);
129 static gint cell_attribute_find (CellAttribute *cell_attribute,
130 const gchar *attribute);
132 /* Internal functions/signal emissions */
133 static void gtk_cell_area_add_editable (GtkCellArea *area,
134 GtkCellRenderer *renderer,
135 GtkCellEditable *editable,
136 GdkRectangle *cell_area);
137 static void gtk_cell_area_remove_editable (GtkCellArea *area,
138 GtkCellRenderer *renderer,
139 GtkCellEditable *editable);
140 static void gtk_cell_area_set_edit_widget (GtkCellArea *area,
141 GtkCellEditable *editable);
142 static void gtk_cell_area_set_edited_cell (GtkCellArea *area,
143 GtkCellRenderer *renderer);
146 /* Struct to pass data along while looping over
147 * cell renderers to apply attributes
153 gboolean is_expander;
154 gboolean is_expanded;
157 struct _GtkCellAreaPrivate
159 /* The GtkCellArea bookkeeps any connected
160 * attributes in this hash table.
162 GHashTable *cell_info;
164 /* The cell border decides how much space to reserve
165 * around each cell for the background_area
167 GtkBorder cell_border;
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 */
192 PROP_CELL_MARGIN_LEFT,
193 PROP_CELL_MARGIN_RIGHT,
194 PROP_CELL_MARGIN_TOP,
195 PROP_CELL_MARGIN_BOTTOM,
203 SIGNAL_REMOVE_EDITABLE,
204 SIGNAL_FOCUS_CHANGED,
208 /* Keep the paramspec pool internal, no need to deliver notifications
209 * on cells. at least no percieved need for now */
210 static GParamSpecPool *cell_property_pool = NULL;
211 static guint cell_area_signals[LAST_SIGNAL] = { 0 };
213 #define PARAM_SPEC_PARAM_ID(pspec) ((pspec)->param_id)
214 #define PARAM_SPEC_SET_PARAM_ID(pspec, id) ((pspec)->param_id = (id))
217 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkCellArea, gtk_cell_area, G_TYPE_INITIALLY_UNOWNED,
218 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
219 gtk_cell_area_cell_layout_init));
222 gtk_cell_area_init (GtkCellArea *area)
224 GtkCellAreaPrivate *priv;
226 area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area,
231 priv->cell_info = g_hash_table_new_full (g_direct_hash,
234 (GDestroyNotify)cell_info_free);
236 priv->focus_siblings = g_hash_table_new_full (g_direct_hash,
239 (GDestroyNotify)g_list_free);
241 priv->cell_border.left = 0;
242 priv->cell_border.right = 0;
243 priv->cell_border.top = 0;
244 priv->cell_border.bottom = 0;
246 priv->focus_cell = NULL;
247 priv->edited_cell = NULL;
248 priv->edit_widget = NULL;
250 priv->remove_widget_id = 0;
254 gtk_cell_area_class_init (GtkCellAreaClass *class)
256 GObjectClass *object_class = G_OBJECT_CLASS (class);
259 object_class->dispose = gtk_cell_area_dispose;
260 object_class->finalize = gtk_cell_area_finalize;
261 object_class->get_property = gtk_cell_area_get_property;
262 object_class->set_property = gtk_cell_area_set_property;
266 class->remove = NULL;
267 class->forall = NULL;
268 class->event = gtk_cell_area_real_event;
269 class->render = NULL;
272 class->create_context = NULL;
273 class->get_request_mode = NULL;
274 class->get_preferred_width = NULL;
275 class->get_preferred_height = NULL;
276 class->get_preferred_height_for_width = gtk_cell_area_real_get_preferred_height_for_width;
277 class->get_preferred_width_for_height = gtk_cell_area_real_get_preferred_width_for_height;
280 class->can_focus = gtk_cell_area_real_can_focus;
282 class->activate = gtk_cell_area_real_activate;
287 * GtkCellArea::add-editable:
288 * @area: the #GtkCellArea where editing started
289 * @renderer: the #GtkCellRenderer that started the edited
290 * @editable: the #GtkCellEditable widget to add
291 * @cell_area: the #GtkWidget relative #GdkRectangle coordinates
292 * where @editable should be added
293 * @path: the #GtkTreePath string this edit was initiated for
295 * Indicates that editing has started on @renderer and that @editable
296 * should be added to the owning cell layouting widget at @cell_area.
298 cell_area_signals[SIGNAL_ADD_EDITABLE] =
299 g_signal_new (I_("add-editable"),
300 G_OBJECT_CLASS_TYPE (object_class),
302 0, /* No class closure here */
304 _gtk_marshal_VOID__OBJECT_OBJECT_BOXED_STRING,
306 GTK_TYPE_CELL_RENDERER,
307 GTK_TYPE_CELL_EDITABLE,
313 * GtkCellArea::remove-editable:
314 * @area: the #GtkCellArea where editing finished
315 * @renderer: the #GtkCellRenderer that finished editeding
316 * @editable: the #GtkCellEditable widget to remove
318 * Indicates that editing finished on @renderer and that @editable
319 * should be removed from the owning cell layouting widget.
321 cell_area_signals[SIGNAL_REMOVE_EDITABLE] =
322 g_signal_new (I_("remove-editable"),
323 G_OBJECT_CLASS_TYPE (object_class),
325 0, /* No class closure here */
327 _gtk_marshal_VOID__OBJECT_OBJECT,
329 GTK_TYPE_CELL_RENDERER,
330 GTK_TYPE_CELL_EDITABLE);
333 * GtkCellArea::focus-changed:
334 * @area: the #GtkCellArea where focus changed
335 * @renderer: the #GtkCellRenderer that has focus
336 * @path: the current #GtkTreePath string set for @area
338 * Indicates that focus changed on this @area. This signal
339 * is emitted either as a result of focus handling or event
342 * It's possible that the signal is emitted even if the
343 * currently focused renderer did not change, this is
344 * because focus may change to the same renderer in the
345 * same cell area for a different row of data.
347 cell_area_signals[SIGNAL_FOCUS_CHANGED] =
348 g_signal_new (I_("focus-changed"),
349 G_OBJECT_CLASS_TYPE (object_class),
351 0, /* No class closure here */
353 _gtk_marshal_VOID__OBJECT_STRING,
355 GTK_TYPE_CELL_RENDERER,
359 g_object_class_install_property (object_class,
360 PROP_CELL_MARGIN_LEFT,
363 P_("Margin on Left"),
364 P_("Pixels of extra space on the left side of each cell"),
368 GTK_PARAM_READWRITE));
370 g_object_class_install_property (object_class,
371 PROP_CELL_MARGIN_RIGHT,
373 ("cell-margin-right",
374 P_("Margin on Right"),
375 P_("Pixels of extra space on the right side of each cell"),
379 GTK_PARAM_READWRITE));
381 g_object_class_install_property (object_class,
382 PROP_CELL_MARGIN_TOP,
386 P_("Pixels of extra space on the top side of each cell"),
390 GTK_PARAM_READWRITE));
392 g_object_class_install_property (object_class,
393 PROP_CELL_MARGIN_BOTTOM,
395 ("cell-margin-bottom",
396 P_("Margin on Bottom"),
397 P_("Pixels of extra space on the bottom side of each cell"),
401 GTK_PARAM_READWRITE));
403 g_object_class_install_property (object_class,
408 P_("The cell which currently has focus"),
409 GTK_TYPE_CELL_RENDERER,
410 GTK_PARAM_READWRITE));
412 g_object_class_install_property (object_class,
417 P_("The cell which is currently being edited"),
418 GTK_TYPE_CELL_RENDERER,
421 g_object_class_install_property (object_class,
426 P_("The widget currently editing the edited cell"),
427 GTK_TYPE_CELL_RENDERER,
430 /* Pool for Cell Properties */
431 if (!cell_property_pool)
432 cell_property_pool = g_param_spec_pool_new (FALSE);
434 g_type_class_add_private (object_class, sizeof (GtkCellAreaPrivate));
437 /*************************************************************
439 *************************************************************/
441 cell_info_new (GtkCellLayoutDataFunc func,
443 GDestroyNotify destroy)
445 CellInfo *info = g_slice_new (CellInfo);
447 info->attributes = NULL;
450 info->destroy = destroy;
456 cell_info_free (CellInfo *info)
459 info->destroy (info->data);
461 g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
462 g_slist_free (info->attributes);
464 g_slice_free (CellInfo, info);
467 static CellAttribute *
468 cell_attribute_new (GtkCellRenderer *renderer,
469 const gchar *attribute,
474 /* Check if the attribute really exists and point to
475 * the property string installed on the cell renderer
476 * class (dont dup the string)
478 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (renderer), attribute);
482 CellAttribute *cell_attribute = g_slice_new (CellAttribute);
484 cell_attribute->attribute = pspec->name;
485 cell_attribute->column = column;
487 return cell_attribute;
494 cell_attribute_free (CellAttribute *attribute)
496 g_slice_free (CellAttribute, attribute);
499 /* GCompareFunc for g_slist_find_custom() */
501 cell_attribute_find (CellAttribute *cell_attribute,
502 const gchar *attribute)
504 return g_strcmp0 (cell_attribute->attribute, attribute);
507 /*************************************************************
509 *************************************************************/
511 gtk_cell_area_finalize (GObject *object)
513 GtkCellArea *area = GTK_CELL_AREA (object);
514 GtkCellAreaPrivate *priv = area->priv;
516 /* All cell renderers should already be removed at this point,
517 * just kill our (empty) hash tables here.
519 g_hash_table_destroy (priv->cell_info);
520 g_hash_table_destroy (priv->focus_siblings);
522 g_free (priv->current_path);
524 G_OBJECT_CLASS (gtk_cell_area_parent_class)->finalize (object);
529 gtk_cell_area_dispose (GObject *object)
531 /* This removes every cell renderer that may be added to the GtkCellArea,
532 * subclasses should be breaking references to the GtkCellRenderers
535 gtk_cell_layout_clear (GTK_CELL_LAYOUT (object));
537 /* Remove any ref to a focused/edited cell */
538 gtk_cell_area_set_focus_cell (GTK_CELL_AREA (object), NULL);
539 gtk_cell_area_set_edited_cell (GTK_CELL_AREA (object), NULL);
540 gtk_cell_area_set_edit_widget (GTK_CELL_AREA (object), NULL);
542 G_OBJECT_CLASS (gtk_cell_area_parent_class)->dispose (object);
546 gtk_cell_area_set_property (GObject *object,
551 GtkCellArea *area = GTK_CELL_AREA (object);
555 case PROP_CELL_MARGIN_LEFT:
556 gtk_cell_area_set_cell_margin_left (area, g_value_get_int (value));
558 case PROP_CELL_MARGIN_RIGHT:
559 gtk_cell_area_set_cell_margin_right (area, g_value_get_int (value));
561 case PROP_CELL_MARGIN_TOP:
562 gtk_cell_area_set_cell_margin_top (area, g_value_get_int (value));
564 case PROP_CELL_MARGIN_BOTTOM:
565 gtk_cell_area_set_cell_margin_bottom (area, g_value_get_int (value));
567 case PROP_FOCUS_CELL:
568 gtk_cell_area_set_focus_cell (area, (GtkCellRenderer *)g_value_get_object (value));
571 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
577 gtk_cell_area_get_property (GObject *object,
582 GtkCellArea *area = GTK_CELL_AREA (object);
583 GtkCellAreaPrivate *priv = area->priv;
587 case PROP_CELL_MARGIN_LEFT:
588 g_value_set_int (value, priv->cell_border.left);
590 case PROP_CELL_MARGIN_RIGHT:
591 g_value_set_int (value, priv->cell_border.right);
593 case PROP_CELL_MARGIN_TOP:
594 g_value_set_int (value, priv->cell_border.top);
596 case PROP_CELL_MARGIN_BOTTOM:
597 g_value_set_int (value, priv->cell_border.bottom);
599 case PROP_FOCUS_CELL:
600 g_value_set_object (value, priv->focus_cell);
602 case PROP_EDITED_CELL:
603 g_value_set_object (value, priv->edited_cell);
605 case PROP_EDIT_WIDGET:
606 g_value_set_object (value, priv->edit_widget);
609 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
614 /*************************************************************
616 *************************************************************/
618 gtk_cell_area_real_event (GtkCellArea *area,
619 GtkCellAreaContext *context,
622 const GdkRectangle *cell_area,
623 GtkCellRendererState flags)
625 GtkCellAreaPrivate *priv = area->priv;
627 if (event->type == GDK_KEY_PRESS && (flags & GTK_CELL_RENDERER_FOCUSED) != 0)
629 GdkEventKey *key_event = (GdkEventKey *)event;
631 /* Cancel any edits in progress */
632 if (priv->edited_cell && (key_event->keyval == GDK_KEY_Escape))
634 gtk_cell_area_stop_editing (area, TRUE);
643 gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area,
644 GtkCellAreaContext *context,
647 gint *minimum_height,
648 gint *natural_height)
650 /* If the area doesnt do height-for-width, fallback on base preferred height */
651 GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, context, widget, minimum_height, natural_height);
655 gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area,
656 GtkCellAreaContext *context,
662 /* If the area doesnt do width-for-height, fallback on base preferred width */
663 GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, context, widget, minimum_width, natural_width);
667 get_can_focus (GtkCellRenderer *renderer,
671 if (gtk_cell_renderer_can_focus (renderer))
676 gtk_cell_area_real_can_focus (GtkCellArea *area)
678 gboolean can_focus = FALSE;
680 /* Checks if any renderer can focus for the currently applied
683 * Subclasses can override this in the case that they are also
684 * rendering widgets as well as renderers.
686 gtk_cell_area_forall (area, (GtkCellCallback)get_can_focus, &can_focus);
692 gtk_cell_area_real_activate (GtkCellArea *area,
693 GtkCellAreaContext *context,
695 const GdkRectangle *cell_area,
696 GtkCellRendererState flags)
698 GtkCellAreaPrivate *priv = area->priv;
699 GdkRectangle background_area;
701 if (priv->focus_cell)
703 /* Get the allocation of the focused cell.
705 gtk_cell_area_get_cell_allocation (area, context, widget, priv->focus_cell,
706 cell_area, &background_area);
708 /* Activate or Edit the currently focused cell
710 * Currently just not sending an event, renderers afaics dont use
711 * the event argument anyway, worst case is we can synthesize one.
713 if (gtk_cell_area_activate_cell (area, widget, priv->focus_cell, NULL,
714 &background_area, flags))
721 /*************************************************************
722 * GtkCellLayoutIface *
723 *************************************************************/
725 gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface)
727 iface->pack_start = gtk_cell_area_pack_default;
728 iface->pack_end = gtk_cell_area_pack_default;
729 iface->clear = gtk_cell_area_clear;
730 iface->add_attribute = gtk_cell_area_add_attribute;
731 iface->set_cell_data_func = gtk_cell_area_set_cell_data_func;
732 iface->clear_attributes = gtk_cell_area_clear_attributes;
733 iface->reorder = gtk_cell_area_reorder;
734 iface->get_cells = gtk_cell_area_get_cells;
738 gtk_cell_area_pack_default (GtkCellLayout *cell_layout,
739 GtkCellRenderer *renderer,
742 gtk_cell_area_add (GTK_CELL_AREA (cell_layout), renderer);
746 gtk_cell_area_clear (GtkCellLayout *cell_layout)
748 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
750 gtk_cell_layout_get_cells (cell_layout);
752 for (l = cells; l; l = l->next)
754 GtkCellRenderer *renderer = l->data;
755 gtk_cell_area_remove (area, renderer);
762 gtk_cell_area_add_attribute (GtkCellLayout *cell_layout,
763 GtkCellRenderer *renderer,
764 const gchar *attribute,
767 gtk_cell_area_attribute_connect (GTK_CELL_AREA (cell_layout),
768 renderer, attribute, column);
772 gtk_cell_area_set_cell_data_func (GtkCellLayout *cell_layout,
773 GtkCellRenderer *renderer,
774 GtkCellLayoutDataFunc func,
776 GDestroyNotify destroy)
778 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
779 GtkCellAreaPrivate *priv = area->priv;
782 info = g_hash_table_lookup (priv->cell_info, renderer);
786 if (info->destroy && info->data)
787 info->destroy (info->data);
792 info->data = func_data;
793 info->destroy = destroy;
799 info->destroy = NULL;
804 info = cell_info_new (func, func_data, destroy);
806 g_hash_table_insert (priv->cell_info, renderer, info);
811 gtk_cell_area_clear_attributes (GtkCellLayout *cell_layout,
812 GtkCellRenderer *renderer)
814 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
815 GtkCellAreaPrivate *priv = area->priv;
818 info = g_hash_table_lookup (priv->cell_info, renderer);
822 g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
823 g_slist_free (info->attributes);
825 info->attributes = NULL;
830 gtk_cell_area_reorder (GtkCellLayout *cell_layout,
831 GtkCellRenderer *cell,
834 g_warning ("GtkCellLayout::reorder not implemented for `%s'",
835 g_type_name (G_TYPE_FROM_INSTANCE (cell_layout)));
839 accum_cells (GtkCellRenderer *renderer,
842 *accum = g_list_prepend (*accum, renderer);
846 gtk_cell_area_get_cells (GtkCellLayout *cell_layout)
850 gtk_cell_area_forall (GTK_CELL_AREA (cell_layout),
851 (GtkCellCallback)accum_cells,
854 return g_list_reverse (cells);
858 /*************************************************************
860 *************************************************************/
864 * @area: a #GtkCellArea
865 * @renderer: the #GtkCellRenderer to add to @area
867 * Adds @renderer to @area with the default child cell properties.
870 gtk_cell_area_add (GtkCellArea *area,
871 GtkCellRenderer *renderer)
873 GtkCellAreaClass *class;
875 g_return_if_fail (GTK_IS_CELL_AREA (area));
876 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
878 class = GTK_CELL_AREA_GET_CLASS (area);
881 class->add (area, renderer);
883 g_warning ("GtkCellAreaClass::add not implemented for `%s'",
884 g_type_name (G_TYPE_FROM_INSTANCE (area)));
888 * gtk_cell_area_remove:
889 * @area: a #GtkCellArea
890 * @renderer: the #GtkCellRenderer to add to @area
892 * Removes @renderer from @area.
895 gtk_cell_area_remove (GtkCellArea *area,
896 GtkCellRenderer *renderer)
898 GtkCellAreaClass *class;
899 GtkCellAreaPrivate *priv;
900 GList *renderers, *l;
902 g_return_if_fail (GTK_IS_CELL_AREA (area));
903 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
905 class = GTK_CELL_AREA_GET_CLASS (area);
908 /* Remove any custom attributes and custom cell data func here first */
909 g_hash_table_remove (priv->cell_info, renderer);
911 /* Remove focus siblings of this renderer */
912 g_hash_table_remove (priv->focus_siblings, renderer);
914 /* Remove this renderer from any focus renderer's sibling list */
915 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (area));
917 for (l = renderers; l; l = l->next)
919 GtkCellRenderer *focus_renderer = l->data;
921 if (gtk_cell_area_is_focus_sibling (area, focus_renderer, renderer))
923 gtk_cell_area_remove_focus_sibling (area, focus_renderer, renderer);
928 g_list_free (renderers);
931 class->remove (area, renderer);
933 g_warning ("GtkCellAreaClass::remove not implemented for `%s'",
934 g_type_name (G_TYPE_FROM_INSTANCE (area)));
938 get_has_renderer (GtkCellRenderer *renderer,
939 HasRendererCheck *check)
941 if (renderer == check->renderer)
942 check->has_renderer = TRUE;
946 * gtk_cell_area_has_renderer:
947 * @area: a #GtkCellArea
948 * @renderer: the #GtkCellRenderer to check
950 * Checks if @area contains @renderer.
952 * Returns: %TRUE if @renderer is in the @area.
955 gtk_cell_area_has_renderer (GtkCellArea *area,
956 GtkCellRenderer *renderer)
958 HasRendererCheck check = { renderer, FALSE };
960 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
961 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
963 gtk_cell_area_forall (area, (GtkCellCallback)get_has_renderer, &check);
965 return check.has_renderer;
969 * gtk_cell_area_forall
970 * @area: a #GtkCellArea
971 * @callback: the #GtkCellCallback to call
972 * @callback_data: user provided data pointer
974 * Calls @callback for every #GtkCellRenderer in @area.
977 gtk_cell_area_forall (GtkCellArea *area,
978 GtkCellCallback callback,
979 gpointer callback_data)
981 GtkCellAreaClass *class;
983 g_return_if_fail (GTK_IS_CELL_AREA (area));
984 g_return_if_fail (callback != NULL);
986 class = GTK_CELL_AREA_GET_CLASS (area);
989 class->forall (area, callback, callback_data);
991 g_warning ("GtkCellAreaClass::forall not implemented for `%s'",
992 g_type_name (G_TYPE_FROM_INSTANCE (area)));
996 * gtk_cell_area_get_cell_allocation:
997 * @area: a #GtkCellArea
998 * @context: the #GtkCellAreaContext used to hold sizes for @area.
999 * @widget: the #GtkWidget that @area is rendering on
1000 * @renderer: the #GtkCellRenderer to get the allocation for
1001 * @cell_area: the whole allocated area for @area in @widget
1003 * @allocation: where to store the allocation for @renderer
1005 * Derives the allocation of @renderer inside @area if @area
1006 * were to be renderered in @cell_area.
1009 gtk_cell_area_get_cell_allocation (GtkCellArea *area,
1010 GtkCellAreaContext *context,
1012 GtkCellRenderer *renderer,
1013 const GdkRectangle *cell_area,
1014 GdkRectangle *allocation)
1016 GtkCellAreaClass *class;
1018 g_return_if_fail (GTK_IS_CELL_AREA (area));
1019 g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
1020 g_return_if_fail (GTK_IS_WIDGET (widget));
1021 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1022 g_return_if_fail (cell_area != NULL);
1023 g_return_if_fail (allocation != NULL);
1025 class = GTK_CELL_AREA_GET_CLASS (area);
1027 if (class->get_cell_allocation)
1028 class->get_cell_allocation (area, context, widget, renderer, cell_area, allocation);
1030 g_warning ("GtkCellAreaClass::get_cell_allocation not implemented for `%s'",
1031 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1035 * gtk_cell_area_event:
1036 * @area: a #GtkCellArea
1037 * @context: the #GtkCellAreaContext for this row of data.
1038 * @widget: the #GtkWidget that @area is rendering to
1039 * @event: the #GdkEvent to handle
1040 * @cell_area: the @widget relative coordinates for @area
1041 * @flags: the #GtkCellRendererState for @area in this row.
1043 * Delegates event handling to a #GtkCellArea.
1045 * Returns: %TRUE if the event was handled by @area.
1048 gtk_cell_area_event (GtkCellArea *area,
1049 GtkCellAreaContext *context,
1052 const GdkRectangle *cell_area,
1053 GtkCellRendererState flags)
1055 GtkCellAreaClass *class;
1057 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1058 g_return_val_if_fail (GTK_IS_CELL_AREA_CONTEXT (context), 0);
1059 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
1060 g_return_val_if_fail (event != NULL, 0);
1061 g_return_val_if_fail (cell_area != NULL, 0);
1063 class = GTK_CELL_AREA_GET_CLASS (area);
1066 return class->event (area, context, widget, event, cell_area, flags);
1068 g_warning ("GtkCellAreaClass::event not implemented for `%s'",
1069 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1074 * gtk_cell_area_render:
1075 * @area: a #GtkCellArea
1076 * @context: the #GtkCellAreaContext for this row of data.
1077 * @widget: the #GtkWidget that @area is rendering to
1078 * @cr: the #cairo_t to render with
1079 * @background_area: the @widget relative coordinates for @area's background
1080 * @cell_area: the @widget relative coordinates for @area
1081 * @flags: the #GtkCellRendererState for @area in this row.
1082 * @paint_focus: whether @area should paint focus on focused cells for focused rows or not.
1084 * Renders @area's cells according to @area's layout onto @widget at
1085 * the given coordinates.
1088 gtk_cell_area_render (GtkCellArea *area,
1089 GtkCellAreaContext *context,
1092 const GdkRectangle *background_area,
1093 const GdkRectangle *cell_area,
1094 GtkCellRendererState flags,
1095 gboolean paint_focus)
1097 GtkCellAreaClass *class;
1099 g_return_if_fail (GTK_IS_CELL_AREA (area));
1100 g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
1101 g_return_if_fail (GTK_IS_WIDGET (widget));
1102 g_return_if_fail (cr != NULL);
1103 g_return_if_fail (background_area != NULL);
1104 g_return_if_fail (cell_area != NULL);
1106 class = GTK_CELL_AREA_GET_CLASS (area);
1109 class->render (area, context, widget, cr, background_area, cell_area, flags, paint_focus);
1111 g_warning ("GtkCellAreaClass::render not implemented for `%s'",
1112 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1116 * gtk_cell_area_set_style_detail:
1117 * @area: a #GtkCellArea
1118 * @detail: the #GtkStyle detail string to set
1120 * Sets the detail string used in any gtk_paint_*() functions
1124 gtk_cell_area_set_style_detail (GtkCellArea *area,
1125 const gchar *detail)
1127 GtkCellAreaPrivate *priv;
1129 g_return_if_fail (GTK_IS_CELL_AREA (area));
1133 if (g_strcmp0 (priv->style_detail, detail) != 0)
1135 g_free (priv->style_detail);
1136 priv->style_detail = g_strdup (detail);
1141 * gtk_cell_area_get_style_detail:
1142 * @area: a #GtkCellArea
1144 * Gets the detail string used in any gtk_paint_*() functions
1147 * Returns: the detail string.
1149 G_CONST_RETURN gchar *
1150 gtk_cell_area_get_style_detail (GtkCellArea *area)
1152 GtkCellAreaPrivate *priv;
1154 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1158 return priv->style_detail;
1161 /*************************************************************
1163 *************************************************************/
1165 * gtk_cell_area_create_context:
1166 * @area: a #GtkCellArea
1168 * Creates a #GtkCellAreaContext to be used with @area for
1169 * all purposes. #GtkCellAreaContext stores geometry information
1170 * for rows for which it was operated on, it is important to use
1171 * the same context for the same row of data at all times (i.e.
1172 * one should render and handle events with the same #GtkCellAreaContext
1173 * which was used to request the size of those rows of data).
1175 * Returns: a newly created #GtkCellAreaContext which can be used with @area.
1177 GtkCellAreaContext *
1178 gtk_cell_area_create_context (GtkCellArea *area)
1180 GtkCellAreaClass *class;
1182 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1184 class = GTK_CELL_AREA_GET_CLASS (area);
1186 if (class->create_context)
1187 return class->create_context (area);
1189 g_warning ("GtkCellAreaClass::create_context not implemented for `%s'",
1190 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1197 * gtk_cell_area_get_request_mode:
1198 * @area: a #GtkCellArea
1200 * Gets whether the area prefers a height-for-width layout
1201 * or a width-for-height layout.
1203 * Returns: The #GtkSizeRequestMode preferred by @area.
1208 gtk_cell_area_get_request_mode (GtkCellArea *area)
1210 GtkCellAreaClass *class;
1212 g_return_val_if_fail (GTK_IS_CELL_AREA (area),
1213 GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH);
1215 class = GTK_CELL_AREA_GET_CLASS (area);
1217 if (class->get_request_mode)
1218 return class->get_request_mode (area);
1220 g_warning ("GtkCellAreaClass::get_request_mode not implemented for `%s'",
1221 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1223 return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
1227 * gtk_cell_area_get_preferred_width:
1228 * @area: a #GtkCellArea
1229 * @context: the #GtkCellAreaContext to perform this request with
1230 * @widget: the #GtkWidget where @area will be rendering
1231 * @minimum_width: (out) (allow-none): location to store the minimum width, or %NULL
1232 * @natural_width: (out) (allow-none): location to store the natural width, or %NULL
1234 * Retrieves a cell area's initial minimum and natural width.
1236 * @area will store some geometrical information in @context along the way,
1237 * when requesting sizes over an arbitrary number of rows, its not important
1238 * to check the @minimum_width and @natural_width of this call but rather to
1239 * call gtk_cell_area_context_sum_preferred_width() and then consult
1240 * gtk_cell_area_context_get_preferred_width().
1246 gtk_cell_area_get_preferred_width (GtkCellArea *area,
1247 GtkCellAreaContext *context,
1249 gint *minimum_width,
1250 gint *natural_width)
1252 GtkCellAreaClass *class;
1254 g_return_if_fail (GTK_IS_CELL_AREA (area));
1255 g_return_if_fail (GTK_IS_WIDGET (widget));
1257 class = GTK_CELL_AREA_GET_CLASS (area);
1259 if (class->get_preferred_width)
1260 class->get_preferred_width (area, context, widget, minimum_width, natural_width);
1262 g_warning ("GtkCellAreaClass::get_preferred_width not implemented for `%s'",
1263 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1267 * gtk_cell_area_get_preferred_height_for_width:
1268 * @area: a #GtkCellArea
1269 * @context: the #GtkCellAreaContext which has already been requested for widths.
1270 * @widget: the #GtkWidget where @area will be rendering
1271 * @width: the width for which to check the height of this area
1272 * @minimum_height: (out) (allow-none): location to store the minimum height, or %NULL
1273 * @natural_height: (out) (allow-none): location to store the natural height, or %NULL
1275 * Retrieves a cell area's minimum and natural height if it would be given
1276 * the specified @width.
1278 * @area stores some geometrical information in @context along the way
1279 * while calling gtk_cell_area_get_preferred_width(), it's important to
1280 * perform a series of gtk_cell_area_get_preferred_width() requests with
1281 * @context first and then call gtk_cell_area_get_preferred_height_for_width()
1282 * on each cell area individually to get the height for width of each
1283 * fully requested row.
1285 * If at some point, the width of a single row changes, it should be
1286 * requested with gtk_cell_area_get_preferred_width() again and then
1287 * the full with of the requested rows checked again after calling
1288 * gtk_cell_area_context_sum_preferred_width(), and then the height
1289 * for width of each row needs to be requested again.
1294 gtk_cell_area_get_preferred_height_for_width (GtkCellArea *area,
1295 GtkCellAreaContext *context,
1298 gint *minimum_height,
1299 gint *natural_height)
1301 GtkCellAreaClass *class;
1303 g_return_if_fail (GTK_IS_CELL_AREA (area));
1304 g_return_if_fail (GTK_IS_WIDGET (widget));
1306 class = GTK_CELL_AREA_GET_CLASS (area);
1307 class->get_preferred_height_for_width (area, context, widget, width, minimum_height, natural_height);
1312 * gtk_cell_area_get_preferred_height:
1313 * @area: a #GtkCellArea
1314 * @context: the #GtkCellAreaContext to perform this request with
1315 * @widget: the #GtkWidget where @area will be rendering
1316 * @minimum_height: (out) (allow-none): location to store the minimum height, or %NULL
1317 * @natural_height: (out) (allow-none): location to store the natural height, or %NULL
1319 * Retrieves a cell area's initial minimum and natural height.
1321 * @area will store some geometrical information in @context along the way,
1322 * when requesting sizes over an arbitrary number of rows, its not important
1323 * to check the @minimum_height and @natural_height of this call but rather to
1324 * call gtk_cell_area_context_sum_preferred_height() and then consult
1325 * gtk_cell_area_context_get_preferred_height().
1330 gtk_cell_area_get_preferred_height (GtkCellArea *area,
1331 GtkCellAreaContext *context,
1333 gint *minimum_height,
1334 gint *natural_height)
1336 GtkCellAreaClass *class;
1338 g_return_if_fail (GTK_IS_CELL_AREA (area));
1339 g_return_if_fail (GTK_IS_WIDGET (widget));
1341 class = GTK_CELL_AREA_GET_CLASS (area);
1343 if (class->get_preferred_height)
1344 class->get_preferred_height (area, context, widget, minimum_height, natural_height);
1346 g_warning ("GtkCellAreaClass::get_preferred_height not implemented for `%s'",
1347 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1351 * gtk_cell_area_get_preferred_width_for_height:
1352 * @area: a #GtkCellArea
1353 * @context: the #GtkCellAreaContext which has already been requested for widths.
1354 * @widget: the #GtkWidget where @area will be rendering
1355 * @height: the height for which to check the width of this area
1356 * @minimum_width: (out) (allow-none): location to store the minimum width, or %NULL
1357 * @natural_width: (out) (allow-none): location to store the natural width, or %NULL
1359 * Retrieves a cell area's minimum and natural width if it would be given
1360 * the specified @height.
1362 * @area stores some geometrical information in @context along the way
1363 * while calling gtk_cell_area_get_preferred_height(), it's important to
1364 * perform a series of gtk_cell_area_get_preferred_height() requests with
1365 * @context first and then call gtk_cell_area_get_preferred_width_for_height()
1366 * on each cell area individually to get the height for width of each
1367 * fully requested row.
1369 * If at some point, the width of a single row changes, it should be
1370 * requested with gtk_cell_area_get_preferred_width() again and then
1371 * the full with of the requested rows checked again after calling
1372 * gtk_cell_area_context_sum_preferred_width(), and then the height
1373 * for width of each row needs to be requested again.
1378 gtk_cell_area_get_preferred_width_for_height (GtkCellArea *area,
1379 GtkCellAreaContext *context,
1382 gint *minimum_width,
1383 gint *natural_width)
1385 GtkCellAreaClass *class;
1387 g_return_if_fail (GTK_IS_CELL_AREA (area));
1388 g_return_if_fail (GTK_IS_WIDGET (widget));
1390 class = GTK_CELL_AREA_GET_CLASS (area);
1391 class->get_preferred_width_for_height (area, context, widget, height, minimum_width, natural_width);
1394 /*************************************************************
1396 *************************************************************/
1399 * gtk_cell_area_attribute_connect:
1400 * @area: a #GtkCellArea
1401 * @renderer: the #GtkCellRenderer to connect an attribute for
1402 * @attribute: the attribute name
1403 * @column: the #GtkTreeModel column to fetch attribute values from
1405 * Connects an @attribute to apply values from @column for the
1406 * #GtkTreeModel in use.
1409 gtk_cell_area_attribute_connect (GtkCellArea *area,
1410 GtkCellRenderer *renderer,
1411 const gchar *attribute,
1414 GtkCellAreaPrivate *priv;
1416 CellAttribute *cell_attribute;
1418 g_return_if_fail (GTK_IS_CELL_AREA (area));
1419 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1420 g_return_if_fail (attribute != NULL);
1421 g_return_if_fail (gtk_cell_area_has_renderer (area, renderer));
1424 info = g_hash_table_lookup (priv->cell_info, renderer);
1428 info = cell_info_new (NULL, NULL, NULL);
1430 g_hash_table_insert (priv->cell_info, renderer, info);
1436 /* Check we are not adding the same attribute twice */
1437 if ((node = g_slist_find_custom (info->attributes, attribute,
1438 (GCompareFunc)cell_attribute_find)) != NULL)
1440 cell_attribute = node->data;
1442 g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
1443 "since `%s' is already attributed to column %d",
1445 g_type_name (G_TYPE_FROM_INSTANCE (area)),
1446 attribute, cell_attribute->column);
1451 cell_attribute = cell_attribute_new (renderer, attribute, column);
1453 if (!cell_attribute)
1455 g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
1456 "since attribute does not exist",
1458 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1462 info->attributes = g_slist_prepend (info->attributes, cell_attribute);
1466 * gtk_cell_area_attribute_disconnect:
1467 * @area: a #GtkCellArea
1468 * @renderer: the #GtkCellRenderer to disconnect an attribute for
1469 * @attribute: the attribute name
1471 * Disconnects @attribute for the @renderer in @area so that
1472 * attribute will no longer be updated with values from the
1476 gtk_cell_area_attribute_disconnect (GtkCellArea *area,
1477 GtkCellRenderer *renderer,
1478 const gchar *attribute)
1480 GtkCellAreaPrivate *priv;
1482 CellAttribute *cell_attribute;
1485 g_return_if_fail (GTK_IS_CELL_AREA (area));
1486 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1487 g_return_if_fail (attribute != NULL);
1488 g_return_if_fail (gtk_cell_area_has_renderer (area, renderer));
1491 info = g_hash_table_lookup (priv->cell_info, renderer);
1495 node = g_slist_find_custom (info->attributes, attribute,
1496 (GCompareFunc)cell_attribute_find);
1499 cell_attribute = node->data;
1501 cell_attribute_free (cell_attribute);
1503 info->attributes = g_slist_delete_link (info->attributes, node);
1509 apply_cell_attributes (GtkCellRenderer *renderer,
1511 AttributeData *data)
1513 CellAttribute *attribute;
1515 GValue value = { 0, };
1516 gboolean is_expander;
1517 gboolean is_expanded;
1519 g_object_freeze_notify (G_OBJECT (renderer));
1521 /* Whether a row expands or is presently expanded can only be
1522 * provided by the view (as these states can vary across views
1523 * accessing the same model).
1525 g_object_get (renderer, "is-expander", &is_expander, NULL);
1526 if (is_expander != data->is_expander)
1527 g_object_set (renderer, "is-expander", data->is_expander, NULL);
1529 g_object_get (renderer, "is-expanded", &is_expanded, NULL);
1530 if (is_expanded != data->is_expanded)
1531 g_object_set (renderer, "is-expanded", data->is_expanded, NULL);
1533 /* Apply the attributes directly to the renderer */
1534 for (list = info->attributes; list; list = list->next)
1536 attribute = list->data;
1538 gtk_tree_model_get_value (data->model, data->iter, attribute->column, &value);
1539 g_object_set_property (G_OBJECT (renderer), attribute->attribute, &value);
1540 g_value_unset (&value);
1543 /* Call any GtkCellLayoutDataFunc that may have been set by the user
1546 info->func (GTK_CELL_LAYOUT (data->area), renderer,
1547 data->model, data->iter, info->data);
1549 g_object_thaw_notify (G_OBJECT (renderer));
1553 * gtk_cell_area_apply_attributes
1554 * @area: a #GtkCellArea
1555 * @tree_model: a #GtkTreeModel to pull values from
1556 * @iter: the #GtkTreeIter in @tree_model to apply values for
1557 * @is_expander: whether @iter has children
1558 * @is_expanded: whether @iter is expanded in the view and
1559 * children are visible
1561 * Applies any connected attributes to the renderers in
1562 * @area by pulling the values from @tree_model.
1565 gtk_cell_area_apply_attributes (GtkCellArea *area,
1566 GtkTreeModel *tree_model,
1568 gboolean is_expander,
1569 gboolean is_expanded)
1571 GtkCellAreaPrivate *priv;
1575 g_return_if_fail (GTK_IS_CELL_AREA (area));
1576 g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
1577 g_return_if_fail (iter != NULL);
1581 /* Feed in data needed to apply to every renderer */
1583 data.model = tree_model;
1585 data.is_expander = is_expander;
1586 data.is_expanded = is_expanded;
1588 /* Go over any cells that have attributes or custom GtkCellLayoutDataFuncs and
1589 * apply the data from the treemodel */
1590 g_hash_table_foreach (priv->cell_info, (GHFunc)apply_cell_attributes, &data);
1592 /* Update the currently applied path */
1593 g_free (priv->current_path);
1594 path = gtk_tree_model_get_path (tree_model, iter);
1595 priv->current_path = gtk_tree_path_to_string (path);
1596 gtk_tree_path_free (path);
1600 * gtk_cell_area_get_current_path_string:
1601 * @area: a #GtkCellArea
1603 * Gets the current #GtkTreePath string for the currently
1604 * applied #GtkTreeIter, this is implicitly updated when
1605 * gtk_cell_area_apply_attributes() is called and can be
1606 * used to interact with renderers from #GtkCellArea
1610 gtk_cell_area_get_current_path_string (GtkCellArea *area)
1612 GtkCellAreaPrivate *priv;
1614 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1618 return priv->current_path;
1622 /*************************************************************
1623 * API: Cell Properties *
1624 *************************************************************/
1626 * gtk_cell_area_class_install_cell_property:
1627 * @aclass: a #GtkCellAreaClass
1628 * @property_id: the id for the property
1629 * @pspec: the #GParamSpec for the property
1631 * Installs a cell property on a cell area class.
1634 gtk_cell_area_class_install_cell_property (GtkCellAreaClass *aclass,
1638 g_return_if_fail (GTK_IS_CELL_AREA_CLASS (aclass));
1639 g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1640 if (pspec->flags & G_PARAM_WRITABLE)
1641 g_return_if_fail (aclass->set_cell_property != NULL);
1642 if (pspec->flags & G_PARAM_READABLE)
1643 g_return_if_fail (aclass->get_cell_property != NULL);
1644 g_return_if_fail (property_id > 0);
1645 g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0); /* paranoid */
1646 g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0);
1648 if (g_param_spec_pool_lookup (cell_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (aclass), TRUE))
1650 g_warning (G_STRLOC ": class `%s' already contains a cell property named `%s'",
1651 G_OBJECT_CLASS_NAME (aclass), pspec->name);
1654 g_param_spec_ref (pspec);
1655 g_param_spec_sink (pspec);
1656 PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
1657 g_param_spec_pool_insert (cell_property_pool, pspec, G_OBJECT_CLASS_TYPE (aclass));
1661 * gtk_cell_area_class_find_cell_property:
1662 * @aclass: a #GtkCellAreaClass
1663 * @property_name: the name of the child property to find
1664 * @returns: (allow-none): the #GParamSpec of the child property or %NULL if @aclass has no
1665 * child property with that name.
1667 * Finds a cell property of a cell area class by name.
1670 gtk_cell_area_class_find_cell_property (GtkCellAreaClass *aclass,
1671 const gchar *property_name)
1673 g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
1674 g_return_val_if_fail (property_name != NULL, NULL);
1676 return g_param_spec_pool_lookup (cell_property_pool,
1678 G_OBJECT_CLASS_TYPE (aclass),
1683 * gtk_cell_area_class_list_cell_properties:
1684 * @aclass: a #GtkCellAreaClass
1685 * @n_properties: location to return the number of cell properties found
1686 * @returns: a newly allocated %NULL-terminated array of #GParamSpec*.
1687 * The array must be freed with g_free().
1689 * Returns all cell properties of a cell area class.
1692 gtk_cell_area_class_list_cell_properties (GtkCellAreaClass *aclass,
1693 guint *n_properties)
1695 GParamSpec **pspecs;
1698 g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
1700 pspecs = g_param_spec_pool_list (cell_property_pool,
1701 G_OBJECT_CLASS_TYPE (aclass),
1710 * gtk_cell_area_add_with_properties:
1711 * @area: a #GtkCellArea
1712 * @renderer: a #GtkCellRenderer to be placed inside @area
1713 * @first_prop_name: the name of the first cell property to set
1714 * @Varargs: a %NULL-terminated list of property names and values, starting
1715 * with @first_prop_name
1717 * Adds @renderer to @area, setting cell properties at the same time.
1718 * See gtk_cell_area_add() and gtk_cell_area_child_set() for more details.
1721 gtk_cell_area_add_with_properties (GtkCellArea *area,
1722 GtkCellRenderer *renderer,
1723 const gchar *first_prop_name,
1726 GtkCellAreaClass *class;
1728 g_return_if_fail (GTK_IS_CELL_AREA (area));
1729 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1731 class = GTK_CELL_AREA_GET_CLASS (area);
1737 class->add (area, renderer);
1739 va_start (var_args, first_prop_name);
1740 gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1744 g_warning ("GtkCellAreaClass::add not implemented for `%s'",
1745 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1749 * gtk_cell_area_cell_set:
1750 * @area: a #GtkCellArea
1751 * @renderer: a #GtkCellRenderer which is a cell inside @area
1752 * @first_prop_name: the name of the first cell property to set
1753 * @Varargs: a %NULL-terminated list of property names and values, starting
1754 * with @first_prop_name
1756 * Sets one or more cell properties for @cell in @area.
1759 gtk_cell_area_cell_set (GtkCellArea *area,
1760 GtkCellRenderer *renderer,
1761 const gchar *first_prop_name,
1766 g_return_if_fail (GTK_IS_CELL_AREA (area));
1767 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1769 va_start (var_args, first_prop_name);
1770 gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1775 * gtk_cell_area_cell_get:
1776 * @area: a #GtkCellArea
1777 * @renderer: a #GtkCellRenderer which is inside @area
1778 * @first_prop_name: the name of the first cell property to get
1779 * @Varargs: return location for the first cell property, followed
1780 * optionally by more name/return location pairs, followed by %NULL
1782 * Gets the values of one or more cell properties for @renderer in @area.
1785 gtk_cell_area_cell_get (GtkCellArea *area,
1786 GtkCellRenderer *renderer,
1787 const gchar *first_prop_name,
1792 g_return_if_fail (GTK_IS_CELL_AREA (area));
1793 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1795 va_start (var_args, first_prop_name);
1796 gtk_cell_area_cell_get_valist (area, renderer, first_prop_name, var_args);
1801 area_get_cell_property (GtkCellArea *area,
1802 GtkCellRenderer *renderer,
1806 GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1808 class->get_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), value, pspec);
1812 area_set_cell_property (GtkCellArea *area,
1813 GtkCellRenderer *renderer,
1815 const GValue *value)
1817 GValue tmp_value = { 0, };
1818 GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1820 /* provide a copy to work from, convert (if necessary) and validate */
1821 g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1822 if (!g_value_transform (value, &tmp_value))
1823 g_warning ("unable to set cell property `%s' of type `%s' from value of type `%s'",
1825 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1826 G_VALUE_TYPE_NAME (value));
1827 else if (g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION))
1829 gchar *contents = g_strdup_value_contents (value);
1831 g_warning ("value \"%s\" of type `%s' is invalid for property `%s' of type `%s'",
1833 G_VALUE_TYPE_NAME (value),
1835 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
1840 class->set_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec);
1842 g_value_unset (&tmp_value);
1846 * gtk_cell_area_cell_set_valist:
1847 * @area: a #GtkCellArea
1848 * @renderer: a #GtkCellRenderer which inside @area
1849 * @first_property_name: the name of the first cell property to set
1850 * @var_args: a %NULL-terminated list of property names and values, starting
1851 * with @first_prop_name
1853 * Sets one or more cell properties for @renderer in @area.
1856 gtk_cell_area_cell_set_valist (GtkCellArea *area,
1857 GtkCellRenderer *renderer,
1858 const gchar *first_property_name,
1863 g_return_if_fail (GTK_IS_CELL_AREA (area));
1864 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1866 name = first_property_name;
1869 GValue value = { 0, };
1870 gchar *error = NULL;
1872 g_param_spec_pool_lookup (cell_property_pool, name,
1873 G_OBJECT_TYPE (area), TRUE);
1876 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1877 G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1880 if (!(pspec->flags & G_PARAM_WRITABLE))
1882 g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1883 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1887 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1888 G_VALUE_COLLECT (&value, var_args, 0, &error);
1891 g_warning ("%s: %s", G_STRLOC, error);
1894 /* we purposely leak the value here, it might not be
1895 * in a sane state if an error condition occoured
1899 area_set_cell_property (area, renderer, pspec, &value);
1900 g_value_unset (&value);
1901 name = va_arg (var_args, gchar*);
1906 * gtk_cell_area_cell_get_valist:
1907 * @area: a #GtkCellArea
1908 * @renderer: a #GtkCellRenderer inside @area
1909 * @first_property_name: the name of the first property to get
1910 * @var_args: return location for the first property, followed
1911 * optionally by more name/return location pairs, followed by %NULL
1913 * Gets the values of one or more cell properties for @renderer in @area.
1916 gtk_cell_area_cell_get_valist (GtkCellArea *area,
1917 GtkCellRenderer *renderer,
1918 const gchar *first_property_name,
1923 g_return_if_fail (GTK_IS_CELL_AREA (area));
1924 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1926 name = first_property_name;
1929 GValue value = { 0, };
1933 pspec = g_param_spec_pool_lookup (cell_property_pool, name,
1934 G_OBJECT_TYPE (area), TRUE);
1937 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1938 G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1941 if (!(pspec->flags & G_PARAM_READABLE))
1943 g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1944 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1948 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1949 area_get_cell_property (area, renderer, pspec, &value);
1950 G_VALUE_LCOPY (&value, var_args, 0, &error);
1953 g_warning ("%s: %s", G_STRLOC, error);
1955 g_value_unset (&value);
1958 g_value_unset (&value);
1959 name = va_arg (var_args, gchar*);
1964 * gtk_cell_area_cell_set_property:
1965 * @area: a #GtkCellArea
1966 * @renderer: a #GtkCellRenderer inside @area
1967 * @property_name: the name of the cell property to set
1968 * @value: the value to set the cell property to
1970 * Sets a cell property for @renderer in @area.
1973 gtk_cell_area_cell_set_property (GtkCellArea *area,
1974 GtkCellRenderer *renderer,
1975 const gchar *property_name,
1976 const GValue *value)
1980 g_return_if_fail (GTK_IS_CELL_AREA (area));
1981 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1982 g_return_if_fail (property_name != NULL);
1983 g_return_if_fail (G_IS_VALUE (value));
1985 pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1986 G_OBJECT_TYPE (area), TRUE);
1988 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1989 G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1990 else if (!(pspec->flags & G_PARAM_WRITABLE))
1991 g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1992 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1995 area_set_cell_property (area, renderer, pspec, value);
2000 * gtk_cell_area_cell_get_property:
2001 * @area: a #GtkCellArea
2002 * @renderer: a #GtkCellRenderer inside @area
2003 * @property_name: the name of the property to get
2004 * @value: a location to return the value
2006 * Gets the value of a cell property for @renderer in @area.
2009 gtk_cell_area_cell_get_property (GtkCellArea *area,
2010 GtkCellRenderer *renderer,
2011 const gchar *property_name,
2016 g_return_if_fail (GTK_IS_CELL_AREA (area));
2017 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2018 g_return_if_fail (property_name != NULL);
2019 g_return_if_fail (G_IS_VALUE (value));
2021 pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
2022 G_OBJECT_TYPE (area), TRUE);
2024 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
2025 G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
2026 else if (!(pspec->flags & G_PARAM_READABLE))
2027 g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
2028 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
2031 GValue *prop_value, tmp_value = { 0, };
2033 /* auto-conversion of the callers value type
2035 if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
2037 g_value_reset (value);
2040 else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
2042 g_warning ("can't retrieve cell property `%s' of type `%s' as value of type `%s'",
2044 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
2045 G_VALUE_TYPE_NAME (value));
2050 g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
2051 prop_value = &tmp_value;
2054 area_get_cell_property (area, renderer, pspec, prop_value);
2056 if (prop_value != value)
2058 g_value_transform (prop_value, value);
2059 g_value_unset (&tmp_value);
2064 /*************************************************************
2066 *************************************************************/
2069 * gtk_cell_area_can_focus:
2070 * @area: a #GtkCellArea
2072 * Returns whether the area can receive keyboard focus,
2073 * after applying new attributes to @area.
2075 * Returns: whether @area can receive focus.
2078 gtk_cell_area_can_focus (GtkCellArea *area)
2080 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2082 return GTK_CELL_AREA_GET_CLASS (area)->can_focus (area);
2086 * gtk_cell_area_focus:
2087 * @area: a #GtkCellArea
2088 * @direction: the #GtkDirectionType
2090 * This should be called by the @area's owning layout widget
2091 * when focus is to be passed to @area, or moved within @area
2092 * for a given @direction and row data.
2094 * Implementing #GtkCellArea classes should implement this
2095 * method to receive and navigate focus in it's own way particular
2096 * to how it lays out cells.
2098 * Returns: %TRUE if focus remains inside @area as a result of this call.
2101 gtk_cell_area_focus (GtkCellArea *area,
2102 GtkDirectionType direction)
2104 GtkCellAreaClass *class;
2106 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2108 class = GTK_CELL_AREA_GET_CLASS (area);
2111 return class->focus (area, direction);
2113 g_warning ("GtkCellAreaClass::focus not implemented for `%s'",
2114 g_type_name (G_TYPE_FROM_INSTANCE (area)));
2120 * gtk_cell_area_activate:
2121 * @area: a #GtkCellArea
2122 * @context: the #GtkCellAreaContext in context with the current row data
2123 * @widget: the #GtkWidget that @area is rendering on
2124 * @cell_area: the size and location of @area relative to @widget's allocation
2125 * @flags: the #GtkCellRendererState flags for @area for this row of data.
2127 * Activates @area, usually by activating the currently focused
2128 * cell, however some subclasses which embed widgets in the area
2129 * can also activate a widget if it currently has the focus.
2131 * Returns: Whether @area was successfully activated.
2134 gtk_cell_area_activate (GtkCellArea *area,
2135 GtkCellAreaContext *context,
2137 const GdkRectangle *cell_area,
2138 GtkCellRendererState flags)
2140 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2142 return GTK_CELL_AREA_GET_CLASS (area)->activate (area, context, widget, cell_area, flags);
2147 * gtk_cell_area_set_focus_cell:
2148 * @area: a #GtkCellArea
2149 * @focus_cell: the #GtkCellRenderer to give focus to
2151 * This is generally called from #GtkCellArea implementations
2152 * either gtk_cell_area_grab_focus() or gtk_cell_area_update_focus()
2153 * is called. It's also up to the #GtkCellArea implementation
2154 * to update the focused cell when receiving events from
2155 * gtk_cell_area_event() appropriately.
2158 gtk_cell_area_set_focus_cell (GtkCellArea *area,
2159 GtkCellRenderer *renderer)
2161 GtkCellAreaPrivate *priv;
2163 g_return_if_fail (GTK_IS_CELL_AREA (area));
2164 g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer));
2168 if (priv->focus_cell != renderer)
2170 if (priv->focus_cell)
2171 g_object_unref (priv->focus_cell);
2173 priv->focus_cell = renderer;
2175 if (priv->focus_cell)
2176 g_object_ref (priv->focus_cell);
2178 g_object_notify (G_OBJECT (area), "focus-cell");
2181 /* Signal that the current focus renderer for this path changed
2182 * (it may be that the focus cell did not change, but the row
2183 * may have changed so we need to signal it) */
2184 g_signal_emit (area, cell_area_signals[SIGNAL_FOCUS_CHANGED], 0,
2185 priv->focus_cell, priv->current_path);
2190 * gtk_cell_area_get_focus_cell:
2191 * @area: a #GtkCellArea
2193 * Retrieves the currently focused cell for @area
2195 * Returns: the currently focused cell in @area.
2198 gtk_cell_area_get_focus_cell (GtkCellArea *area)
2200 GtkCellAreaPrivate *priv;
2202 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2206 return priv->focus_cell;
2210 /*************************************************************
2211 * API: Focus Siblings *
2212 *************************************************************/
2215 * gtk_cell_area_add_focus_sibling:
2216 * @area: a #GtkCellArea
2217 * @renderer: the #GtkCellRenderer expected to have focus
2218 * @sibling: the #GtkCellRenderer to add to @renderer's focus area
2220 * Adds @sibling to @renderer's focusable area, focus will be drawn
2221 * around @renderer and all of it's siblings if @renderer can
2222 * focus for a given row.
2224 * Events handled by focus siblings can also activate the given
2225 * focusable @renderer.
2228 gtk_cell_area_add_focus_sibling (GtkCellArea *area,
2229 GtkCellRenderer *renderer,
2230 GtkCellRenderer *sibling)
2232 GtkCellAreaPrivate *priv;
2235 g_return_if_fail (GTK_IS_CELL_AREA (area));
2236 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2237 g_return_if_fail (GTK_IS_CELL_RENDERER (sibling));
2238 g_return_if_fail (renderer != sibling);
2239 g_return_if_fail (gtk_cell_area_has_renderer (area, renderer));
2240 g_return_if_fail (gtk_cell_area_has_renderer (area, sibling));
2241 g_return_if_fail (!gtk_cell_area_is_focus_sibling (area, renderer, sibling));
2243 /* XXX We should also check that sibling is not in any other renderer's sibling
2244 * list already, a renderer can be sibling of only one focusable renderer
2250 siblings = g_hash_table_lookup (priv->focus_siblings, renderer);
2253 siblings = g_list_append (siblings, sibling);
2256 siblings = g_list_append (siblings, sibling);
2257 g_hash_table_insert (priv->focus_siblings, renderer, siblings);
2262 * gtk_cell_area_remove_focus_sibling:
2263 * @area: a #GtkCellArea
2264 * @renderer: the #GtkCellRenderer expected to have focus
2265 * @sibling: the #GtkCellRenderer to remove from @renderer's focus area
2267 * Removes @sibling from @renderer's focus sibling list
2268 * (see gtk_cell_area_add_focus_sibling()).
2271 gtk_cell_area_remove_focus_sibling (GtkCellArea *area,
2272 GtkCellRenderer *renderer,
2273 GtkCellRenderer *sibling)
2275 GtkCellAreaPrivate *priv;
2278 g_return_if_fail (GTK_IS_CELL_AREA (area));
2279 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2280 g_return_if_fail (GTK_IS_CELL_RENDERER (sibling));
2281 g_return_if_fail (gtk_cell_area_is_focus_sibling (area, renderer, sibling));
2285 siblings = g_hash_table_lookup (priv->focus_siblings, renderer);
2287 siblings = g_list_copy (siblings);
2288 siblings = g_list_remove (siblings, sibling);
2291 g_hash_table_remove (priv->focus_siblings, renderer);
2293 g_hash_table_insert (priv->focus_siblings, renderer, siblings);
2297 * gtk_cell_area_is_focus_sibling:
2298 * @area: a #GtkCellArea
2299 * @renderer: the #GtkCellRenderer expected to have focus
2300 * @sibling: the #GtkCellRenderer to check against @renderer's sibling list
2302 * Returns %TRUE if @sibling is one of @renderer's focus siblings
2303 * (see gtk_cell_area_add_focus_sibling()).
2306 gtk_cell_area_is_focus_sibling (GtkCellArea *area,
2307 GtkCellRenderer *renderer,
2308 GtkCellRenderer *sibling)
2310 GtkCellAreaPrivate *priv;
2311 GList *siblings, *l;
2313 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2314 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
2315 g_return_val_if_fail (GTK_IS_CELL_RENDERER (sibling), FALSE);
2319 siblings = g_hash_table_lookup (priv->focus_siblings, renderer);
2321 for (l = siblings; l; l = l->next)
2323 GtkCellRenderer *a_sibling = l->data;
2325 if (a_sibling == sibling)
2333 * gtk_cell_area_get_focus_siblings:
2334 * @area: a #GtkCellArea
2335 * @renderer: the #GtkCellRenderer expected to have focus
2337 * Gets the focus sibling cell renderers for @renderer.
2339 * Returns: A #GList of #GtkCellRenderers. The returned list is internal and should not be freed.
2342 gtk_cell_area_get_focus_siblings (GtkCellArea *area,
2343 GtkCellRenderer *renderer)
2345 GtkCellAreaPrivate *priv;
2347 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2348 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), NULL);
2352 return g_hash_table_lookup (priv->focus_siblings, renderer);
2356 * gtk_cell_area_get_focus_from_sibling:
2357 * @area: a #GtkCellArea
2358 * @renderer: the #GtkCellRenderer
2360 * Gets the #GtkCellRenderer which is expected to be focusable
2361 * for which @renderer is, or may be a sibling.
2363 * This is handy for #GtkCellArea subclasses when handling events,
2364 * after determining the renderer at the event location it can
2365 * then chose to activate the focus cell for which the event
2366 * cell may have been a sibling.
2368 * Returns: the #GtkCellRenderer for which @renderer is a sibling, or %NULL.
2371 gtk_cell_area_get_focus_from_sibling (GtkCellArea *area,
2372 GtkCellRenderer *renderer)
2374 GtkCellRenderer *ret_renderer = NULL;
2375 GList *renderers, *l;
2377 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2378 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), NULL);
2380 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (area));
2382 for (l = renderers; l; l = l->next)
2384 GtkCellRenderer *a_renderer = l->data;
2387 for (list = gtk_cell_area_get_focus_siblings (area, a_renderer);
2388 list; list = list->next)
2390 GtkCellRenderer *sibling_renderer = list->data;
2392 if (sibling_renderer == renderer)
2394 ret_renderer = a_renderer;
2399 g_list_free (renderers);
2401 return ret_renderer;
2404 /*************************************************************
2405 * API: Cell Activation/Editing *
2406 *************************************************************/
2408 gtk_cell_area_add_editable (GtkCellArea *area,
2409 GtkCellRenderer *renderer,
2410 GtkCellEditable *editable,
2411 GdkRectangle *cell_area)
2413 g_signal_emit (area, cell_area_signals[SIGNAL_ADD_EDITABLE], 0,
2414 renderer, editable, cell_area, area->priv->current_path);
2418 gtk_cell_area_remove_editable (GtkCellArea *area,
2419 GtkCellRenderer *renderer,
2420 GtkCellEditable *editable)
2422 g_signal_emit (area, cell_area_signals[SIGNAL_REMOVE_EDITABLE], 0, renderer, editable);
2426 cell_area_remove_widget_cb (GtkCellEditable *editable,
2429 GtkCellAreaPrivate *priv = area->priv;
2431 g_assert (priv->edit_widget == editable);
2432 g_assert (priv->edited_cell != NULL);
2434 gtk_cell_area_remove_editable (area, priv->edited_cell, priv->edit_widget);
2436 /* Now that we're done with editing the widget and it can be removed,
2437 * remove our references to the widget and disconnect handlers */
2438 gtk_cell_area_set_edited_cell (area, NULL);
2439 gtk_cell_area_set_edit_widget (area, NULL);
2443 gtk_cell_area_set_edited_cell (GtkCellArea *area,
2444 GtkCellRenderer *renderer)
2446 GtkCellAreaPrivate *priv;
2448 g_return_if_fail (GTK_IS_CELL_AREA (area));
2449 g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer));
2453 if (priv->edited_cell != renderer)
2455 if (priv->edited_cell)
2456 g_object_unref (priv->edited_cell);
2458 priv->edited_cell = renderer;
2460 if (priv->edited_cell)
2461 g_object_ref (priv->edited_cell);
2463 g_object_notify (G_OBJECT (area), "edited-cell");
2468 gtk_cell_area_set_edit_widget (GtkCellArea *area,
2469 GtkCellEditable *editable)
2471 GtkCellAreaPrivate *priv;
2473 g_return_if_fail (GTK_IS_CELL_AREA (area));
2474 g_return_if_fail (editable == NULL || GTK_IS_CELL_EDITABLE (editable));
2478 if (priv->edit_widget != editable)
2480 if (priv->edit_widget)
2482 g_signal_handler_disconnect (priv->edit_widget, priv->remove_widget_id);
2484 g_object_unref (priv->edit_widget);
2487 priv->edit_widget = editable;
2489 if (priv->edit_widget)
2491 priv->remove_widget_id =
2492 g_signal_connect (priv->edit_widget, "remove-widget",
2493 G_CALLBACK (cell_area_remove_widget_cb), area);
2495 g_object_ref (priv->edit_widget);
2498 g_object_notify (G_OBJECT (area), "edit-widget");
2503 * gtk_cell_area_get_edited_cell:
2504 * @area: a #GtkCellArea
2506 * Gets the #GtkCellRenderer in @area that is currently
2509 * Returns: The currently edited #GtkCellRenderer
2512 gtk_cell_area_get_edited_cell (GtkCellArea *area)
2514 GtkCellAreaPrivate *priv;
2516 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2520 return priv->edited_cell;
2524 * gtk_cell_area_get_edit_widget:
2525 * @area: a #GtkCellArea
2527 * Gets the #GtkCellEditable widget currently used
2528 * to edit the currently edited cell.
2530 * Returns: The currently active #GtkCellEditable widget
2533 gtk_cell_area_get_edit_widget (GtkCellArea *area)
2535 GtkCellAreaPrivate *priv;
2537 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2541 return priv->edit_widget;
2545 * gtk_cell_area_activate_cell:
2546 * @area: a #GtkCellArea
2547 * @widget: the #GtkWidget that @area is rendering onto
2548 * @renderer: the #GtkCellRenderer in @area to activate
2549 * @event: the #GdkEvent for which cell activation should occur
2550 * @cell_area: the #GdkRectangle in @widget relative coordinates
2551 * of @renderer for the current row.
2552 * @flags: the #GtkCellRendererState for @renderer
2554 * This is used by #GtkCellArea subclasses when handling events
2555 * to activate cells, the base #GtkCellArea class activates cells
2556 * for keyboard events for free in it's own GtkCellArea->activate()
2559 * Returns: whether cell activation was successful
2562 gtk_cell_area_activate_cell (GtkCellArea *area,
2564 GtkCellRenderer *renderer,
2566 const GdkRectangle *cell_area,
2567 GtkCellRendererState flags)
2569 GtkCellRendererMode mode;
2570 GdkRectangle inner_area;
2571 GtkCellAreaPrivate *priv;
2573 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2574 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
2575 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
2576 g_return_val_if_fail (cell_area != NULL, FALSE);
2580 /* Remove margins from the background area to produce the cell area.
2582 * XXX Maybe have to do some rtl mode treatment here...
2584 gtk_cell_area_inner_cell_area (area, cell_area, &inner_area);
2586 g_object_get (renderer, "mode", &mode, NULL);
2588 if (mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
2590 if (gtk_cell_renderer_activate (renderer,
2598 else if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
2600 GtkCellEditable *editable_widget;
2603 gtk_cell_renderer_start_editing (renderer,
2610 if (editable_widget != NULL)
2612 GdkRectangle edit_area;
2614 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (editable_widget), FALSE);
2616 gtk_cell_area_set_edited_cell (area, renderer);
2617 gtk_cell_area_set_edit_widget (area, editable_widget);
2619 gtk_cell_area_aligned_cell_area (area, widget, renderer, &inner_area, &edit_area);
2621 /* Signal that editing started so that callers can get
2622 * a handle on the editable_widget */
2623 gtk_cell_area_add_editable (area, priv->focus_cell, editable_widget, &edit_area);
2625 /* If the signal was successfully handled start the editing */
2626 if (gtk_widget_get_parent (GTK_WIDGET (editable_widget)))
2628 gtk_cell_editable_start_editing (editable_widget, NULL);
2629 gtk_widget_grab_focus (GTK_WIDGET (editable_widget));
2633 /* Otherwise clear the editing state and fire a warning */
2634 gtk_cell_area_set_edited_cell (area, NULL);
2635 gtk_cell_area_set_edit_widget (area, NULL);
2637 g_warning ("GtkCellArea::add-editable fired in the dark, no cell editing was started.");
2648 * gtk_cell_area_stop_editing:
2649 * @area: a #GtkCellArea
2650 * @canceled: whether editing was canceled.
2652 * Explicitly stops the editing of the currently
2653 * edited cell (see gtk_cell_area_get_edited_cell()).
2655 * If @canceled is %TRUE, the cell renderer will emit
2656 * the ::editing-canceled signal.
2659 gtk_cell_area_stop_editing (GtkCellArea *area,
2662 GtkCellAreaPrivate *priv;
2664 g_return_if_fail (GTK_IS_CELL_AREA (area));
2668 if (priv->edited_cell)
2670 GtkCellEditable *edit_widget = g_object_ref (priv->edit_widget);
2671 GtkCellRenderer *edit_cell = g_object_ref (priv->edited_cell);
2673 /* Stop editing of the cell renderer */
2674 gtk_cell_renderer_stop_editing (priv->edited_cell, canceled);
2676 /* Remove any references to the editable widget */
2677 gtk_cell_area_set_edited_cell (area, NULL);
2678 gtk_cell_area_set_edit_widget (area, NULL);
2680 /* Send the remove-widget signal explicitly (this is done after setting
2681 * the edit cell/widget NULL to avoid feedback)
2683 gtk_cell_area_remove_editable (area, edit_cell, edit_widget);
2684 g_object_unref (edit_cell);
2685 g_object_unref (edit_widget);
2689 /*************************************************************
2691 *************************************************************/
2693 gtk_cell_area_get_cell_margin_left (GtkCellArea *area)
2695 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
2697 return area->priv->cell_border.left;
2701 gtk_cell_area_set_cell_margin_left (GtkCellArea *area,
2704 GtkCellAreaPrivate *priv;
2706 g_return_if_fail (GTK_IS_CELL_AREA (area));
2710 if (priv->cell_border.left != margin)
2712 priv->cell_border.left = margin;
2714 g_object_notify (G_OBJECT (area), "cell-margin-left");
2719 gtk_cell_area_get_cell_margin_right (GtkCellArea *area)
2721 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
2723 return area->priv->cell_border.right;
2727 gtk_cell_area_set_cell_margin_right (GtkCellArea *area,
2730 GtkCellAreaPrivate *priv;
2732 g_return_if_fail (GTK_IS_CELL_AREA (area));
2736 if (priv->cell_border.right != margin)
2738 priv->cell_border.right = margin;
2740 g_object_notify (G_OBJECT (area), "cell-margin-right");
2745 gtk_cell_area_get_cell_margin_top (GtkCellArea *area)
2747 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
2749 return area->priv->cell_border.top;
2753 gtk_cell_area_set_cell_margin_top (GtkCellArea *area,
2756 GtkCellAreaPrivate *priv;
2758 g_return_if_fail (GTK_IS_CELL_AREA (area));
2762 if (priv->cell_border.top != margin)
2764 priv->cell_border.top = margin;
2766 g_object_notify (G_OBJECT (area), "cell-margin-top");
2771 gtk_cell_area_get_cell_margin_bottom (GtkCellArea *area)
2773 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
2775 return area->priv->cell_border.bottom;
2779 gtk_cell_area_set_cell_margin_bottom (GtkCellArea *area,
2782 GtkCellAreaPrivate *priv;
2784 g_return_if_fail (GTK_IS_CELL_AREA (area));
2788 if (priv->cell_border.bottom != margin)
2790 priv->cell_border.bottom = margin;
2792 g_object_notify (G_OBJECT (area), "cell-margin-bottom");
2797 gtk_cell_area_inner_cell_area (GtkCellArea *area,
2798 const GdkRectangle *cell_area,
2799 GdkRectangle *inner_area)
2801 GtkCellAreaPrivate *priv;
2803 g_return_if_fail (GTK_IS_CELL_AREA (area));
2804 g_return_if_fail (cell_area != NULL);
2805 g_return_if_fail (inner_area != NULL);
2809 *inner_area = *cell_area;
2811 inner_area->x += priv->cell_border.left;
2812 inner_area->width -= (priv->cell_border.left + priv->cell_border.right);
2813 inner_area->y += priv->cell_border.top;
2814 inner_area->height -= (priv->cell_border.top + priv->cell_border.bottom);
2818 gtk_cell_area_aligned_cell_area (GtkCellArea *area,
2820 GtkCellRenderer *renderer,
2821 const GdkRectangle *cell_area,
2822 GdkRectangle *aligned_area)
2824 GtkCellAreaPrivate *priv;
2825 gint opposite_size, x_offset, y_offset;
2827 g_return_if_fail (GTK_IS_CELL_AREA (area));
2828 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2829 g_return_if_fail (GTK_IS_WIDGET (widget));
2830 g_return_if_fail (cell_area != NULL);
2831 g_return_if_fail (aligned_area != NULL);
2835 *aligned_area = *cell_area;
2837 /* Trim up the aligned size */
2838 if (gtk_cell_renderer_get_request_mode (renderer) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
2840 gtk_cell_renderer_get_preferred_height_for_width (renderer, widget,
2841 aligned_area->width,
2842 NULL, &opposite_size);
2844 aligned_area->height = MIN (opposite_size, aligned_area->height);
2848 gtk_cell_renderer_get_preferred_width_for_height (renderer, widget,
2849 aligned_area->height,
2850 NULL, &opposite_size);
2852 aligned_area->width = MIN (opposite_size, aligned_area->width);
2855 /* offset the cell position */
2856 _gtk_cell_renderer_calc_offset (renderer, cell_area,
2857 gtk_widget_get_direction (widget),
2858 aligned_area->width,
2859 aligned_area->height,
2860 &x_offset, &y_offset);
2862 aligned_area->x += x_offset;
2863 aligned_area->y += y_offset;
2867 gtk_cell_area_request_renderer (GtkCellArea *area,
2868 GtkCellRenderer *renderer,
2869 GtkOrientation orientation,
2875 GtkCellAreaPrivate *priv;
2877 g_return_if_fail (GTK_IS_CELL_AREA (area));
2878 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2879 g_return_if_fail (GTK_IS_WIDGET (widget));
2880 g_return_if_fail (minimum_size != NULL);
2881 g_return_if_fail (natural_size != NULL);
2885 if (orientation == GTK_ORIENTATION_HORIZONTAL)
2888 gtk_cell_renderer_get_preferred_width (renderer, widget, minimum_size, natural_size);
2891 for_size = MAX (0, for_size - (priv->cell_border.top + priv->cell_border.bottom));
2893 gtk_cell_renderer_get_preferred_width_for_height (renderer, widget, for_size,
2894 minimum_size, natural_size);
2897 *minimum_size += (priv->cell_border.left + priv->cell_border.right);
2898 *natural_size += (priv->cell_border.left + priv->cell_border.right);
2900 else /* GTK_ORIENTATION_VERTICAL */
2903 gtk_cell_renderer_get_preferred_height (renderer, widget, minimum_size, natural_size);
2906 for_size = MAX (0, for_size - (priv->cell_border.left + priv->cell_border.right));
2908 gtk_cell_renderer_get_preferred_height_for_width (renderer, widget, for_size,
2909 minimum_size, natural_size);
2912 *minimum_size += (priv->cell_border.top + priv->cell_border.bottom);
2913 *natural_size += (priv->cell_border.top + priv->cell_border.bottom);