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 /* Current path is saved as a side-effect
165 * of gtk_cell_area_apply_attributes() */
168 /* Current cell being edited and editable widget used */
169 GtkCellEditable *edit_widget;
170 GtkCellRenderer *edited_cell;
172 /* Signal connections to the editable widget */
173 gulong remove_widget_id;
175 /* Currently focused cell */
176 GtkCellRenderer *focus_cell;
178 /* Tracking which cells are focus siblings of focusable cells */
179 GHashTable *focus_siblings;
181 /* Detail string to pass to gtk_paint_*() functions */
194 SIGNAL_REMOVE_EDITABLE,
195 SIGNAL_FOCUS_CHANGED,
199 /* Keep the paramspec pool internal, no need to deliver notifications
200 * on cells. at least no percieved need for now */
201 static GParamSpecPool *cell_property_pool = NULL;
202 static guint cell_area_signals[LAST_SIGNAL] = { 0 };
204 #define PARAM_SPEC_PARAM_ID(pspec) ((pspec)->param_id)
205 #define PARAM_SPEC_SET_PARAM_ID(pspec, id) ((pspec)->param_id = (id))
208 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkCellArea, gtk_cell_area, G_TYPE_INITIALLY_UNOWNED,
209 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
210 gtk_cell_area_cell_layout_init));
213 gtk_cell_area_init (GtkCellArea *area)
215 GtkCellAreaPrivate *priv;
217 area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area,
222 priv->cell_info = g_hash_table_new_full (g_direct_hash,
225 (GDestroyNotify)cell_info_free);
227 priv->focus_siblings = g_hash_table_new_full (g_direct_hash,
230 (GDestroyNotify)g_list_free);
232 priv->focus_cell = NULL;
233 priv->edited_cell = NULL;
234 priv->edit_widget = NULL;
236 priv->remove_widget_id = 0;
240 gtk_cell_area_class_init (GtkCellAreaClass *class)
242 GObjectClass *object_class = G_OBJECT_CLASS (class);
245 object_class->dispose = gtk_cell_area_dispose;
246 object_class->finalize = gtk_cell_area_finalize;
247 object_class->get_property = gtk_cell_area_get_property;
248 object_class->set_property = gtk_cell_area_set_property;
252 class->remove = NULL;
253 class->forall = NULL;
254 class->event = gtk_cell_area_real_event;
255 class->render = NULL;
258 class->create_context = NULL;
259 class->get_request_mode = NULL;
260 class->get_preferred_width = NULL;
261 class->get_preferred_height = NULL;
262 class->get_preferred_height_for_width = gtk_cell_area_real_get_preferred_height_for_width;
263 class->get_preferred_width_for_height = gtk_cell_area_real_get_preferred_width_for_height;
266 class->can_focus = gtk_cell_area_real_can_focus;
268 class->activate = gtk_cell_area_real_activate;
273 * GtkCellArea::add-editable:
274 * @area: the #GtkCellArea where editing started
275 * @renderer: the #GtkCellRenderer that started the edited
276 * @editable: the #GtkCellEditable widget to add
277 * @cell_area: the #GtkWidget relative #GdkRectangle coordinates
278 * where @editable should be added
279 * @path: the #GtkTreePath string this edit was initiated for
281 * Indicates that editing has started on @renderer and that @editable
282 * should be added to the owning cell layouting widget at @cell_area.
284 cell_area_signals[SIGNAL_ADD_EDITABLE] =
285 g_signal_new (I_("add-editable"),
286 G_OBJECT_CLASS_TYPE (object_class),
288 0, /* No class closure here */
290 _gtk_marshal_VOID__OBJECT_OBJECT_BOXED_STRING,
292 GTK_TYPE_CELL_RENDERER,
293 GTK_TYPE_CELL_EDITABLE,
299 * GtkCellArea::remove-editable:
300 * @area: the #GtkCellArea where editing finished
301 * @renderer: the #GtkCellRenderer that finished editeding
302 * @editable: the #GtkCellEditable widget to remove
304 * Indicates that editing finished on @renderer and that @editable
305 * should be removed from the owning cell layouting widget.
307 cell_area_signals[SIGNAL_REMOVE_EDITABLE] =
308 g_signal_new (I_("remove-editable"),
309 G_OBJECT_CLASS_TYPE (object_class),
311 0, /* No class closure here */
313 _gtk_marshal_VOID__OBJECT_OBJECT,
315 GTK_TYPE_CELL_RENDERER,
316 GTK_TYPE_CELL_EDITABLE);
319 * GtkCellArea::focus-changed:
320 * @area: the #GtkCellArea where focus changed
321 * @renderer: the #GtkCellRenderer that has focus
322 * @path: the current #GtkTreePath string set for @area
324 * Indicates that focus changed on this @area. This signal
325 * is emitted either as a result of focus handling or event
328 * It's possible that the signal is emitted even if the
329 * currently focused renderer did not change, this is
330 * because focus may change to the same renderer in the
331 * same cell area for a different row of data.
333 cell_area_signals[SIGNAL_FOCUS_CHANGED] =
334 g_signal_new (I_("focus-changed"),
335 G_OBJECT_CLASS_TYPE (object_class),
337 0, /* No class closure here */
339 _gtk_marshal_VOID__OBJECT_STRING,
341 GTK_TYPE_CELL_RENDERER,
345 g_object_class_install_property (object_class,
350 P_("The cell which currently has focus"),
351 GTK_TYPE_CELL_RENDERER,
352 GTK_PARAM_READWRITE));
354 g_object_class_install_property (object_class,
359 P_("The cell which is currently being edited"),
360 GTK_TYPE_CELL_RENDERER,
363 g_object_class_install_property (object_class,
368 P_("The widget currently editing the edited cell"),
369 GTK_TYPE_CELL_RENDERER,
372 /* Pool for Cell Properties */
373 if (!cell_property_pool)
374 cell_property_pool = g_param_spec_pool_new (FALSE);
376 g_type_class_add_private (object_class, sizeof (GtkCellAreaPrivate));
379 /*************************************************************
381 *************************************************************/
383 cell_info_new (GtkCellLayoutDataFunc func,
385 GDestroyNotify destroy)
387 CellInfo *info = g_slice_new0 (CellInfo);
391 info->destroy = destroy;
397 cell_info_free (CellInfo *info)
400 info->destroy (info->data);
402 g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
403 g_slist_free (info->attributes);
405 g_slice_free (CellInfo, info);
408 static CellAttribute *
409 cell_attribute_new (GtkCellRenderer *renderer,
410 const gchar *attribute,
415 /* Check if the attribute really exists and point to
416 * the property string installed on the cell renderer
417 * class (dont dup the string)
419 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (renderer), attribute);
423 CellAttribute *cell_attribute = g_slice_new (CellAttribute);
425 cell_attribute->attribute = pspec->name;
426 cell_attribute->column = column;
428 return cell_attribute;
435 cell_attribute_free (CellAttribute *attribute)
437 g_slice_free (CellAttribute, attribute);
440 /* GCompareFunc for g_slist_find_custom() */
442 cell_attribute_find (CellAttribute *cell_attribute,
443 const gchar *attribute)
445 return g_strcmp0 (cell_attribute->attribute, attribute);
448 /*************************************************************
450 *************************************************************/
452 gtk_cell_area_finalize (GObject *object)
454 GtkCellArea *area = GTK_CELL_AREA (object);
455 GtkCellAreaPrivate *priv = area->priv;
457 /* All cell renderers should already be removed at this point,
458 * just kill our (empty) hash tables here.
460 g_hash_table_destroy (priv->cell_info);
461 g_hash_table_destroy (priv->focus_siblings);
463 g_free (priv->current_path);
465 G_OBJECT_CLASS (gtk_cell_area_parent_class)->finalize (object);
470 gtk_cell_area_dispose (GObject *object)
472 /* This removes every cell renderer that may be added to the GtkCellArea,
473 * subclasses should be breaking references to the GtkCellRenderers
476 gtk_cell_layout_clear (GTK_CELL_LAYOUT (object));
478 /* Remove any ref to a focused/edited cell */
479 gtk_cell_area_set_focus_cell (GTK_CELL_AREA (object), NULL);
480 gtk_cell_area_set_edited_cell (GTK_CELL_AREA (object), NULL);
481 gtk_cell_area_set_edit_widget (GTK_CELL_AREA (object), NULL);
483 G_OBJECT_CLASS (gtk_cell_area_parent_class)->dispose (object);
487 gtk_cell_area_set_property (GObject *object,
492 GtkCellArea *area = GTK_CELL_AREA (object);
496 case PROP_FOCUS_CELL:
497 gtk_cell_area_set_focus_cell (area, (GtkCellRenderer *)g_value_get_object (value));
500 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
506 gtk_cell_area_get_property (GObject *object,
511 GtkCellArea *area = GTK_CELL_AREA (object);
512 GtkCellAreaPrivate *priv = area->priv;
516 case PROP_FOCUS_CELL:
517 g_value_set_object (value, priv->focus_cell);
519 case PROP_EDITED_CELL:
520 g_value_set_object (value, priv->edited_cell);
522 case PROP_EDIT_WIDGET:
523 g_value_set_object (value, priv->edit_widget);
526 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
531 /*************************************************************
533 *************************************************************/
535 gtk_cell_area_real_event (GtkCellArea *area,
536 GtkCellAreaContext *context,
539 const GdkRectangle *cell_area,
540 GtkCellRendererState flags)
542 GtkCellAreaPrivate *priv = area->priv;
544 if (event->type == GDK_KEY_PRESS && (flags & GTK_CELL_RENDERER_FOCUSED) != 0)
546 GdkEventKey *key_event = (GdkEventKey *)event;
548 /* Cancel any edits in progress */
549 if (priv->edited_cell && (key_event->keyval == GDK_KEY_Escape))
551 gtk_cell_area_stop_editing (area, TRUE);
560 gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area,
561 GtkCellAreaContext *context,
564 gint *minimum_height,
565 gint *natural_height)
567 /* If the area doesnt do height-for-width, fallback on base preferred height */
568 GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, context, widget, minimum_height, natural_height);
572 gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area,
573 GtkCellAreaContext *context,
579 /* If the area doesnt do width-for-height, fallback on base preferred width */
580 GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, context, widget, minimum_width, natural_width);
584 get_can_focus (GtkCellRenderer *renderer,
588 if (gtk_cell_renderer_can_focus (renderer))
593 gtk_cell_area_real_can_focus (GtkCellArea *area)
595 gboolean can_focus = FALSE;
597 /* Checks if any renderer can focus for the currently applied
600 * Subclasses can override this in the case that they are also
601 * rendering widgets as well as renderers.
603 gtk_cell_area_forall (area, (GtkCellCallback)get_can_focus, &can_focus);
609 gtk_cell_area_real_activate (GtkCellArea *area,
610 GtkCellAreaContext *context,
612 const GdkRectangle *cell_area,
613 GtkCellRendererState flags)
615 GtkCellAreaPrivate *priv = area->priv;
616 GdkRectangle background_area;
618 if (priv->focus_cell)
620 /* Get the allocation of the focused cell.
622 gtk_cell_area_get_cell_allocation (area, context, widget, priv->focus_cell,
623 cell_area, &background_area);
625 /* Activate or Edit the currently focused cell
627 * Currently just not sending an event, renderers afaics dont use
628 * the event argument anyway, worst case is we can synthesize one.
630 if (gtk_cell_area_activate_cell (area, widget, priv->focus_cell, NULL,
631 &background_area, flags))
638 /*************************************************************
639 * GtkCellLayoutIface *
640 *************************************************************/
642 gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface)
644 iface->pack_start = gtk_cell_area_pack_default;
645 iface->pack_end = gtk_cell_area_pack_default;
646 iface->clear = gtk_cell_area_clear;
647 iface->add_attribute = gtk_cell_area_add_attribute;
648 iface->set_cell_data_func = gtk_cell_area_set_cell_data_func;
649 iface->clear_attributes = gtk_cell_area_clear_attributes;
650 iface->reorder = gtk_cell_area_reorder;
651 iface->get_cells = gtk_cell_area_get_cells;
655 gtk_cell_area_pack_default (GtkCellLayout *cell_layout,
656 GtkCellRenderer *renderer,
659 gtk_cell_area_add (GTK_CELL_AREA (cell_layout), renderer);
663 gtk_cell_area_clear (GtkCellLayout *cell_layout)
665 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
667 gtk_cell_layout_get_cells (cell_layout);
669 for (l = cells; l; l = l->next)
671 GtkCellRenderer *renderer = l->data;
672 gtk_cell_area_remove (area, renderer);
679 gtk_cell_area_add_attribute (GtkCellLayout *cell_layout,
680 GtkCellRenderer *renderer,
681 const gchar *attribute,
684 gtk_cell_area_attribute_connect (GTK_CELL_AREA (cell_layout),
685 renderer, attribute, column);
689 gtk_cell_area_set_cell_data_func (GtkCellLayout *cell_layout,
690 GtkCellRenderer *renderer,
691 GtkCellLayoutDataFunc func,
693 GDestroyNotify destroy)
695 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
696 GtkCellAreaPrivate *priv = area->priv;
699 info = g_hash_table_lookup (priv->cell_info, renderer);
703 if (info->destroy && info->data)
704 info->destroy (info->data);
709 info->data = func_data;
710 info->destroy = destroy;
716 info->destroy = NULL;
721 info = cell_info_new (func, func_data, destroy);
723 g_hash_table_insert (priv->cell_info, renderer, info);
728 gtk_cell_area_clear_attributes (GtkCellLayout *cell_layout,
729 GtkCellRenderer *renderer)
731 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
732 GtkCellAreaPrivate *priv = area->priv;
735 info = g_hash_table_lookup (priv->cell_info, renderer);
739 g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
740 g_slist_free (info->attributes);
742 info->attributes = NULL;
747 gtk_cell_area_reorder (GtkCellLayout *cell_layout,
748 GtkCellRenderer *cell,
751 g_warning ("GtkCellLayout::reorder not implemented for `%s'",
752 g_type_name (G_TYPE_FROM_INSTANCE (cell_layout)));
756 accum_cells (GtkCellRenderer *renderer,
759 *accum = g_list_prepend (*accum, renderer);
763 gtk_cell_area_get_cells (GtkCellLayout *cell_layout)
767 gtk_cell_area_forall (GTK_CELL_AREA (cell_layout),
768 (GtkCellCallback)accum_cells,
771 return g_list_reverse (cells);
775 /*************************************************************
777 *************************************************************/
781 * @area: a #GtkCellArea
782 * @renderer: the #GtkCellRenderer to add to @area
784 * Adds @renderer to @area with the default child cell properties.
787 gtk_cell_area_add (GtkCellArea *area,
788 GtkCellRenderer *renderer)
790 GtkCellAreaClass *class;
792 g_return_if_fail (GTK_IS_CELL_AREA (area));
793 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
795 class = GTK_CELL_AREA_GET_CLASS (area);
798 class->add (area, renderer);
800 g_warning ("GtkCellAreaClass::add not implemented for `%s'",
801 g_type_name (G_TYPE_FROM_INSTANCE (area)));
805 * gtk_cell_area_remove:
806 * @area: a #GtkCellArea
807 * @renderer: the #GtkCellRenderer to add to @area
809 * Removes @renderer from @area.
812 gtk_cell_area_remove (GtkCellArea *area,
813 GtkCellRenderer *renderer)
815 GtkCellAreaClass *class;
816 GtkCellAreaPrivate *priv;
817 GList *renderers, *l;
819 g_return_if_fail (GTK_IS_CELL_AREA (area));
820 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
822 class = GTK_CELL_AREA_GET_CLASS (area);
825 /* Remove any custom attributes and custom cell data func here first */
826 g_hash_table_remove (priv->cell_info, renderer);
828 /* Remove focus siblings of this renderer */
829 g_hash_table_remove (priv->focus_siblings, renderer);
831 /* Remove this renderer from any focus renderer's sibling list */
832 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (area));
834 for (l = renderers; l; l = l->next)
836 GtkCellRenderer *focus_renderer = l->data;
838 if (gtk_cell_area_is_focus_sibling (area, focus_renderer, renderer))
840 gtk_cell_area_remove_focus_sibling (area, focus_renderer, renderer);
845 g_list_free (renderers);
848 class->remove (area, renderer);
850 g_warning ("GtkCellAreaClass::remove not implemented for `%s'",
851 g_type_name (G_TYPE_FROM_INSTANCE (area)));
855 get_has_renderer (GtkCellRenderer *renderer,
856 HasRendererCheck *check)
858 if (renderer == check->renderer)
859 check->has_renderer = TRUE;
863 * gtk_cell_area_has_renderer:
864 * @area: a #GtkCellArea
865 * @renderer: the #GtkCellRenderer to check
867 * Checks if @area contains @renderer.
869 * Returns: %TRUE if @renderer is in the @area.
872 gtk_cell_area_has_renderer (GtkCellArea *area,
873 GtkCellRenderer *renderer)
875 HasRendererCheck check = { renderer, FALSE };
877 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
878 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
880 gtk_cell_area_forall (area, (GtkCellCallback)get_has_renderer, &check);
882 return check.has_renderer;
886 * gtk_cell_area_forall
887 * @area: a #GtkCellArea
888 * @callback: the #GtkCellCallback to call
889 * @callback_data: user provided data pointer
891 * Calls @callback for every #GtkCellRenderer in @area.
894 gtk_cell_area_forall (GtkCellArea *area,
895 GtkCellCallback callback,
896 gpointer callback_data)
898 GtkCellAreaClass *class;
900 g_return_if_fail (GTK_IS_CELL_AREA (area));
901 g_return_if_fail (callback != NULL);
903 class = GTK_CELL_AREA_GET_CLASS (area);
906 class->forall (area, callback, callback_data);
908 g_warning ("GtkCellAreaClass::forall not implemented for `%s'",
909 g_type_name (G_TYPE_FROM_INSTANCE (area)));
913 * gtk_cell_area_get_cell_allocation:
914 * @area: a #GtkCellArea
915 * @context: the #GtkCellAreaContext used to hold sizes for @area.
916 * @widget: the #GtkWidget that @area is rendering on
917 * @renderer: the #GtkCellRenderer to get the allocation for
918 * @cell_area: the whole allocated area for @area in @widget
920 * @allocation: where to store the allocation for @renderer
922 * Derives the allocation of @renderer inside @area if @area
923 * were to be renderered in @cell_area.
926 gtk_cell_area_get_cell_allocation (GtkCellArea *area,
927 GtkCellAreaContext *context,
929 GtkCellRenderer *renderer,
930 const GdkRectangle *cell_area,
931 GdkRectangle *allocation)
933 GtkCellAreaClass *class;
935 g_return_if_fail (GTK_IS_CELL_AREA (area));
936 g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
937 g_return_if_fail (GTK_IS_WIDGET (widget));
938 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
939 g_return_if_fail (cell_area != NULL);
940 g_return_if_fail (allocation != NULL);
942 class = GTK_CELL_AREA_GET_CLASS (area);
944 if (class->get_cell_allocation)
945 class->get_cell_allocation (area, context, widget, renderer, cell_area, allocation);
947 g_warning ("GtkCellAreaClass::get_cell_allocation not implemented for `%s'",
948 g_type_name (G_TYPE_FROM_INSTANCE (area)));
952 * gtk_cell_area_event:
953 * @area: a #GtkCellArea
954 * @context: the #GtkCellAreaContext for this row of data.
955 * @widget: the #GtkWidget that @area is rendering to
956 * @event: the #GdkEvent to handle
957 * @cell_area: the @widget relative coordinates for @area
958 * @flags: the #GtkCellRendererState for @area in this row.
960 * Delegates event handling to a #GtkCellArea.
962 * Returns: %TRUE if the event was handled by @area.
965 gtk_cell_area_event (GtkCellArea *area,
966 GtkCellAreaContext *context,
969 const GdkRectangle *cell_area,
970 GtkCellRendererState flags)
972 GtkCellAreaClass *class;
974 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
975 g_return_val_if_fail (GTK_IS_CELL_AREA_CONTEXT (context), 0);
976 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
977 g_return_val_if_fail (event != NULL, 0);
978 g_return_val_if_fail (cell_area != NULL, 0);
980 class = GTK_CELL_AREA_GET_CLASS (area);
983 return class->event (area, context, widget, event, cell_area, flags);
985 g_warning ("GtkCellAreaClass::event not implemented for `%s'",
986 g_type_name (G_TYPE_FROM_INSTANCE (area)));
991 * gtk_cell_area_render:
992 * @area: a #GtkCellArea
993 * @context: the #GtkCellAreaContext for this row of data.
994 * @widget: the #GtkWidget that @area is rendering to
995 * @cr: the #cairo_t to render with
996 * @background_area: the @widget relative coordinates for @area's background
997 * @cell_area: the @widget relative coordinates for @area
998 * @flags: the #GtkCellRendererState for @area in this row.
999 * @paint_focus: whether @area should paint focus on focused cells for focused rows or not.
1001 * Renders @area's cells according to @area's layout onto @widget at
1002 * the given coordinates.
1005 gtk_cell_area_render (GtkCellArea *area,
1006 GtkCellAreaContext *context,
1009 const GdkRectangle *background_area,
1010 const GdkRectangle *cell_area,
1011 GtkCellRendererState flags,
1012 gboolean paint_focus)
1014 GtkCellAreaClass *class;
1016 g_return_if_fail (GTK_IS_CELL_AREA (area));
1017 g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
1018 g_return_if_fail (GTK_IS_WIDGET (widget));
1019 g_return_if_fail (cr != NULL);
1020 g_return_if_fail (background_area != NULL);
1021 g_return_if_fail (cell_area != NULL);
1023 class = GTK_CELL_AREA_GET_CLASS (area);
1026 class->render (area, context, widget, cr, background_area, cell_area, flags, paint_focus);
1028 g_warning ("GtkCellAreaClass::render not implemented for `%s'",
1029 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1033 * gtk_cell_area_set_style_detail:
1034 * @area: a #GtkCellArea
1035 * @detail: the #GtkStyle detail string to set
1037 * Sets the detail string used in any gtk_paint_*() functions
1041 gtk_cell_area_set_style_detail (GtkCellArea *area,
1042 const gchar *detail)
1044 GtkCellAreaPrivate *priv;
1046 g_return_if_fail (GTK_IS_CELL_AREA (area));
1050 if (g_strcmp0 (priv->style_detail, detail) != 0)
1052 g_free (priv->style_detail);
1053 priv->style_detail = g_strdup (detail);
1058 * gtk_cell_area_get_style_detail:
1059 * @area: a #GtkCellArea
1061 * Gets the detail string used in any gtk_paint_*() functions
1064 * Returns: the detail string.
1066 G_CONST_RETURN gchar *
1067 gtk_cell_area_get_style_detail (GtkCellArea *area)
1069 GtkCellAreaPrivate *priv;
1071 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1075 return priv->style_detail;
1078 /*************************************************************
1080 *************************************************************/
1082 * gtk_cell_area_create_context:
1083 * @area: a #GtkCellArea
1085 * Creates a #GtkCellAreaContext to be used with @area for
1086 * all purposes. #GtkCellAreaContext stores geometry information
1087 * for rows for which it was operated on, it is important to use
1088 * the same context for the same row of data at all times (i.e.
1089 * one should render and handle events with the same #GtkCellAreaContext
1090 * which was used to request the size of those rows of data).
1092 * Returns: a newly created #GtkCellAreaContext which can be used with @area.
1094 GtkCellAreaContext *
1095 gtk_cell_area_create_context (GtkCellArea *area)
1097 GtkCellAreaClass *class;
1099 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1101 class = GTK_CELL_AREA_GET_CLASS (area);
1103 if (class->create_context)
1104 return class->create_context (area);
1106 g_warning ("GtkCellAreaClass::create_context not implemented for `%s'",
1107 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1114 * gtk_cell_area_get_request_mode:
1115 * @area: a #GtkCellArea
1117 * Gets whether the area prefers a height-for-width layout
1118 * or a width-for-height layout.
1120 * Returns: The #GtkSizeRequestMode preferred by @area.
1125 gtk_cell_area_get_request_mode (GtkCellArea *area)
1127 GtkCellAreaClass *class;
1129 g_return_val_if_fail (GTK_IS_CELL_AREA (area),
1130 GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH);
1132 class = GTK_CELL_AREA_GET_CLASS (area);
1134 if (class->get_request_mode)
1135 return class->get_request_mode (area);
1137 g_warning ("GtkCellAreaClass::get_request_mode not implemented for `%s'",
1138 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1140 return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
1144 * gtk_cell_area_get_preferred_width:
1145 * @area: a #GtkCellArea
1146 * @context: the #GtkCellAreaContext to perform this request with
1147 * @widget: the #GtkWidget where @area will be rendering
1148 * @minimum_width: (out) (allow-none): location to store the minimum width, or %NULL
1149 * @natural_width: (out) (allow-none): location to store the natural width, or %NULL
1151 * Retrieves a cell area's initial minimum and natural width.
1153 * @area will store some geometrical information in @context along the way,
1154 * when requesting sizes over an arbitrary number of rows, its not important
1155 * to check the @minimum_width and @natural_width of this call but rather to
1156 * call gtk_cell_area_context_sum_preferred_width() and then consult
1157 * gtk_cell_area_context_get_preferred_width().
1163 gtk_cell_area_get_preferred_width (GtkCellArea *area,
1164 GtkCellAreaContext *context,
1166 gint *minimum_width,
1167 gint *natural_width)
1169 GtkCellAreaClass *class;
1171 g_return_if_fail (GTK_IS_CELL_AREA (area));
1172 g_return_if_fail (GTK_IS_WIDGET (widget));
1174 class = GTK_CELL_AREA_GET_CLASS (area);
1176 if (class->get_preferred_width)
1177 class->get_preferred_width (area, context, widget, minimum_width, natural_width);
1179 g_warning ("GtkCellAreaClass::get_preferred_width not implemented for `%s'",
1180 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1184 * gtk_cell_area_get_preferred_height_for_width:
1185 * @area: a #GtkCellArea
1186 * @context: the #GtkCellAreaContext which has already been requested for widths.
1187 * @widget: the #GtkWidget where @area will be rendering
1188 * @width: the width for which to check the height of this area
1189 * @minimum_height: (out) (allow-none): location to store the minimum height, or %NULL
1190 * @natural_height: (out) (allow-none): location to store the natural height, or %NULL
1192 * Retrieves a cell area's minimum and natural height if it would be given
1193 * the specified @width.
1195 * @area stores some geometrical information in @context along the way
1196 * while calling gtk_cell_area_get_preferred_width(), it's important to
1197 * perform a series of gtk_cell_area_get_preferred_width() requests with
1198 * @context first and then call gtk_cell_area_get_preferred_height_for_width()
1199 * on each cell area individually to get the height for width of each
1200 * fully requested row.
1202 * If at some point, the width of a single row changes, it should be
1203 * requested with gtk_cell_area_get_preferred_width() again and then
1204 * the full with of the requested rows checked again after calling
1205 * gtk_cell_area_context_sum_preferred_width(), and then the height
1206 * for width of each row needs to be requested again.
1211 gtk_cell_area_get_preferred_height_for_width (GtkCellArea *area,
1212 GtkCellAreaContext *context,
1215 gint *minimum_height,
1216 gint *natural_height)
1218 GtkCellAreaClass *class;
1220 g_return_if_fail (GTK_IS_CELL_AREA (area));
1221 g_return_if_fail (GTK_IS_WIDGET (widget));
1223 class = GTK_CELL_AREA_GET_CLASS (area);
1224 class->get_preferred_height_for_width (area, context, widget, width, minimum_height, natural_height);
1229 * gtk_cell_area_get_preferred_height:
1230 * @area: a #GtkCellArea
1231 * @context: the #GtkCellAreaContext to perform this request with
1232 * @widget: the #GtkWidget where @area will be rendering
1233 * @minimum_height: (out) (allow-none): location to store the minimum height, or %NULL
1234 * @natural_height: (out) (allow-none): location to store the natural height, or %NULL
1236 * Retrieves a cell area's initial minimum and natural height.
1238 * @area will store some geometrical information in @context along the way,
1239 * when requesting sizes over an arbitrary number of rows, its not important
1240 * to check the @minimum_height and @natural_height of this call but rather to
1241 * call gtk_cell_area_context_sum_preferred_height() and then consult
1242 * gtk_cell_area_context_get_preferred_height().
1247 gtk_cell_area_get_preferred_height (GtkCellArea *area,
1248 GtkCellAreaContext *context,
1250 gint *minimum_height,
1251 gint *natural_height)
1253 GtkCellAreaClass *class;
1255 g_return_if_fail (GTK_IS_CELL_AREA (area));
1256 g_return_if_fail (GTK_IS_WIDGET (widget));
1258 class = GTK_CELL_AREA_GET_CLASS (area);
1260 if (class->get_preferred_height)
1261 class->get_preferred_height (area, context, widget, minimum_height, natural_height);
1263 g_warning ("GtkCellAreaClass::get_preferred_height not implemented for `%s'",
1264 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1268 * gtk_cell_area_get_preferred_width_for_height:
1269 * @area: a #GtkCellArea
1270 * @context: the #GtkCellAreaContext which has already been requested for widths.
1271 * @widget: the #GtkWidget where @area will be rendering
1272 * @height: the height for which to check the width of this area
1273 * @minimum_width: (out) (allow-none): location to store the minimum width, or %NULL
1274 * @natural_width: (out) (allow-none): location to store the natural width, or %NULL
1276 * Retrieves a cell area's minimum and natural width if it would be given
1277 * the specified @height.
1279 * @area stores some geometrical information in @context along the way
1280 * while calling gtk_cell_area_get_preferred_height(), it's important to
1281 * perform a series of gtk_cell_area_get_preferred_height() requests with
1282 * @context first and then call gtk_cell_area_get_preferred_width_for_height()
1283 * on each cell area individually to get the height for width of each
1284 * fully requested row.
1286 * If at some point, the width of a single row changes, it should be
1287 * requested with gtk_cell_area_get_preferred_width() again and then
1288 * the full with of the requested rows checked again after calling
1289 * gtk_cell_area_context_sum_preferred_width(), and then the height
1290 * for width of each row needs to be requested again.
1295 gtk_cell_area_get_preferred_width_for_height (GtkCellArea *area,
1296 GtkCellAreaContext *context,
1299 gint *minimum_width,
1300 gint *natural_width)
1302 GtkCellAreaClass *class;
1304 g_return_if_fail (GTK_IS_CELL_AREA (area));
1305 g_return_if_fail (GTK_IS_WIDGET (widget));
1307 class = GTK_CELL_AREA_GET_CLASS (area);
1308 class->get_preferred_width_for_height (area, context, widget, height, minimum_width, natural_width);
1311 /*************************************************************
1313 *************************************************************/
1316 * gtk_cell_area_attribute_connect:
1317 * @area: a #GtkCellArea
1318 * @renderer: the #GtkCellRenderer to connect an attribute for
1319 * @attribute: the attribute name
1320 * @column: the #GtkTreeModel column to fetch attribute values from
1322 * Connects an @attribute to apply values from @column for the
1323 * #GtkTreeModel in use.
1326 gtk_cell_area_attribute_connect (GtkCellArea *area,
1327 GtkCellRenderer *renderer,
1328 const gchar *attribute,
1331 GtkCellAreaPrivate *priv;
1333 CellAttribute *cell_attribute;
1335 g_return_if_fail (GTK_IS_CELL_AREA (area));
1336 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1337 g_return_if_fail (attribute != NULL);
1338 g_return_if_fail (gtk_cell_area_has_renderer (area, renderer));
1341 info = g_hash_table_lookup (priv->cell_info, renderer);
1345 info = cell_info_new (NULL, NULL, NULL);
1347 g_hash_table_insert (priv->cell_info, renderer, info);
1353 /* Check we are not adding the same attribute twice */
1354 if ((node = g_slist_find_custom (info->attributes, attribute,
1355 (GCompareFunc)cell_attribute_find)) != NULL)
1357 cell_attribute = node->data;
1359 g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
1360 "since `%s' is already attributed to column %d",
1362 g_type_name (G_TYPE_FROM_INSTANCE (area)),
1363 attribute, cell_attribute->column);
1368 cell_attribute = cell_attribute_new (renderer, attribute, column);
1370 if (!cell_attribute)
1372 g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
1373 "since attribute does not exist",
1375 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1379 info->attributes = g_slist_prepend (info->attributes, cell_attribute);
1383 * gtk_cell_area_attribute_disconnect:
1384 * @area: a #GtkCellArea
1385 * @renderer: the #GtkCellRenderer to disconnect an attribute for
1386 * @attribute: the attribute name
1388 * Disconnects @attribute for the @renderer in @area so that
1389 * attribute will no longer be updated with values from the
1393 gtk_cell_area_attribute_disconnect (GtkCellArea *area,
1394 GtkCellRenderer *renderer,
1395 const gchar *attribute)
1397 GtkCellAreaPrivate *priv;
1399 CellAttribute *cell_attribute;
1402 g_return_if_fail (GTK_IS_CELL_AREA (area));
1403 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1404 g_return_if_fail (attribute != NULL);
1405 g_return_if_fail (gtk_cell_area_has_renderer (area, renderer));
1408 info = g_hash_table_lookup (priv->cell_info, renderer);
1412 node = g_slist_find_custom (info->attributes, attribute,
1413 (GCompareFunc)cell_attribute_find);
1416 cell_attribute = node->data;
1418 cell_attribute_free (cell_attribute);
1420 info->attributes = g_slist_delete_link (info->attributes, node);
1426 apply_cell_attributes (GtkCellRenderer *renderer,
1428 AttributeData *data)
1430 CellAttribute *attribute;
1432 GValue value = { 0, };
1433 gboolean is_expander;
1434 gboolean is_expanded;
1436 g_object_freeze_notify (G_OBJECT (renderer));
1438 /* Whether a row expands or is presently expanded can only be
1439 * provided by the view (as these states can vary across views
1440 * accessing the same model).
1442 g_object_get (renderer, "is-expander", &is_expander, NULL);
1443 if (is_expander != data->is_expander)
1444 g_object_set (renderer, "is-expander", data->is_expander, NULL);
1446 g_object_get (renderer, "is-expanded", &is_expanded, NULL);
1447 if (is_expanded != data->is_expanded)
1448 g_object_set (renderer, "is-expanded", data->is_expanded, NULL);
1450 /* Apply the attributes directly to the renderer */
1451 for (list = info->attributes; list; list = list->next)
1453 attribute = list->data;
1455 gtk_tree_model_get_value (data->model, data->iter, attribute->column, &value);
1456 g_object_set_property (G_OBJECT (renderer), attribute->attribute, &value);
1457 g_value_unset (&value);
1460 /* Call any GtkCellLayoutDataFunc that may have been set by the user
1463 info->func (GTK_CELL_LAYOUT (data->area), renderer,
1464 data->model, data->iter, info->data);
1466 g_object_thaw_notify (G_OBJECT (renderer));
1470 * gtk_cell_area_apply_attributes
1471 * @area: a #GtkCellArea
1472 * @tree_model: a #GtkTreeModel to pull values from
1473 * @iter: the #GtkTreeIter in @tree_model to apply values for
1474 * @is_expander: whether @iter has children
1475 * @is_expanded: whether @iter is expanded in the view and
1476 * children are visible
1478 * Applies any connected attributes to the renderers in
1479 * @area by pulling the values from @tree_model.
1482 gtk_cell_area_apply_attributes (GtkCellArea *area,
1483 GtkTreeModel *tree_model,
1485 gboolean is_expander,
1486 gboolean is_expanded)
1488 GtkCellAreaPrivate *priv;
1492 g_return_if_fail (GTK_IS_CELL_AREA (area));
1493 g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
1494 g_return_if_fail (iter != NULL);
1498 /* Feed in data needed to apply to every renderer */
1500 data.model = tree_model;
1502 data.is_expander = is_expander;
1503 data.is_expanded = is_expanded;
1505 /* Go over any cells that have attributes or custom GtkCellLayoutDataFuncs and
1506 * apply the data from the treemodel */
1507 g_hash_table_foreach (priv->cell_info, (GHFunc)apply_cell_attributes, &data);
1509 /* Update the currently applied path */
1510 g_free (priv->current_path);
1511 path = gtk_tree_model_get_path (tree_model, iter);
1512 priv->current_path = gtk_tree_path_to_string (path);
1513 gtk_tree_path_free (path);
1517 * gtk_cell_area_get_current_path_string:
1518 * @area: a #GtkCellArea
1520 * Gets the current #GtkTreePath string for the currently
1521 * applied #GtkTreeIter, this is implicitly updated when
1522 * gtk_cell_area_apply_attributes() is called and can be
1523 * used to interact with renderers from #GtkCellArea
1527 gtk_cell_area_get_current_path_string (GtkCellArea *area)
1529 GtkCellAreaPrivate *priv;
1531 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1535 return priv->current_path;
1539 /*************************************************************
1540 * API: Cell Properties *
1541 *************************************************************/
1543 * gtk_cell_area_class_install_cell_property:
1544 * @aclass: a #GtkCellAreaClass
1545 * @property_id: the id for the property
1546 * @pspec: the #GParamSpec for the property
1548 * Installs a cell property on a cell area class.
1551 gtk_cell_area_class_install_cell_property (GtkCellAreaClass *aclass,
1555 g_return_if_fail (GTK_IS_CELL_AREA_CLASS (aclass));
1556 g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1557 if (pspec->flags & G_PARAM_WRITABLE)
1558 g_return_if_fail (aclass->set_cell_property != NULL);
1559 if (pspec->flags & G_PARAM_READABLE)
1560 g_return_if_fail (aclass->get_cell_property != NULL);
1561 g_return_if_fail (property_id > 0);
1562 g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0); /* paranoid */
1563 g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0);
1565 if (g_param_spec_pool_lookup (cell_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (aclass), TRUE))
1567 g_warning (G_STRLOC ": class `%s' already contains a cell property named `%s'",
1568 G_OBJECT_CLASS_NAME (aclass), pspec->name);
1571 g_param_spec_ref (pspec);
1572 g_param_spec_sink (pspec);
1573 PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
1574 g_param_spec_pool_insert (cell_property_pool, pspec, G_OBJECT_CLASS_TYPE (aclass));
1578 * gtk_cell_area_class_find_cell_property:
1579 * @aclass: a #GtkCellAreaClass
1580 * @property_name: the name of the child property to find
1581 * @returns: (allow-none): the #GParamSpec of the child property or %NULL if @aclass has no
1582 * child property with that name.
1584 * Finds a cell property of a cell area class by name.
1587 gtk_cell_area_class_find_cell_property (GtkCellAreaClass *aclass,
1588 const gchar *property_name)
1590 g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
1591 g_return_val_if_fail (property_name != NULL, NULL);
1593 return g_param_spec_pool_lookup (cell_property_pool,
1595 G_OBJECT_CLASS_TYPE (aclass),
1600 * gtk_cell_area_class_list_cell_properties:
1601 * @aclass: a #GtkCellAreaClass
1602 * @n_properties: location to return the number of cell properties found
1603 * @returns: a newly allocated %NULL-terminated array of #GParamSpec*.
1604 * The array must be freed with g_free().
1606 * Returns all cell properties of a cell area class.
1609 gtk_cell_area_class_list_cell_properties (GtkCellAreaClass *aclass,
1610 guint *n_properties)
1612 GParamSpec **pspecs;
1615 g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
1617 pspecs = g_param_spec_pool_list (cell_property_pool,
1618 G_OBJECT_CLASS_TYPE (aclass),
1627 * gtk_cell_area_add_with_properties:
1628 * @area: a #GtkCellArea
1629 * @renderer: a #GtkCellRenderer to be placed inside @area
1630 * @first_prop_name: the name of the first cell property to set
1631 * @Varargs: a %NULL-terminated list of property names and values, starting
1632 * with @first_prop_name
1634 * Adds @renderer to @area, setting cell properties at the same time.
1635 * See gtk_cell_area_add() and gtk_cell_area_child_set() for more details.
1638 gtk_cell_area_add_with_properties (GtkCellArea *area,
1639 GtkCellRenderer *renderer,
1640 const gchar *first_prop_name,
1643 GtkCellAreaClass *class;
1645 g_return_if_fail (GTK_IS_CELL_AREA (area));
1646 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1648 class = GTK_CELL_AREA_GET_CLASS (area);
1654 class->add (area, renderer);
1656 va_start (var_args, first_prop_name);
1657 gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1661 g_warning ("GtkCellAreaClass::add not implemented for `%s'",
1662 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1666 * gtk_cell_area_cell_set:
1667 * @area: a #GtkCellArea
1668 * @renderer: a #GtkCellRenderer which is a cell inside @area
1669 * @first_prop_name: the name of the first cell property to set
1670 * @Varargs: a %NULL-terminated list of property names and values, starting
1671 * with @first_prop_name
1673 * Sets one or more cell properties for @cell in @area.
1676 gtk_cell_area_cell_set (GtkCellArea *area,
1677 GtkCellRenderer *renderer,
1678 const gchar *first_prop_name,
1683 g_return_if_fail (GTK_IS_CELL_AREA (area));
1684 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1686 va_start (var_args, first_prop_name);
1687 gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1692 * gtk_cell_area_cell_get:
1693 * @area: a #GtkCellArea
1694 * @renderer: a #GtkCellRenderer which is inside @area
1695 * @first_prop_name: the name of the first cell property to get
1696 * @Varargs: return location for the first cell property, followed
1697 * optionally by more name/return location pairs, followed by %NULL
1699 * Gets the values of one or more cell properties for @renderer in @area.
1702 gtk_cell_area_cell_get (GtkCellArea *area,
1703 GtkCellRenderer *renderer,
1704 const gchar *first_prop_name,
1709 g_return_if_fail (GTK_IS_CELL_AREA (area));
1710 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1712 va_start (var_args, first_prop_name);
1713 gtk_cell_area_cell_get_valist (area, renderer, first_prop_name, var_args);
1718 area_get_cell_property (GtkCellArea *area,
1719 GtkCellRenderer *renderer,
1723 GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1725 class->get_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), value, pspec);
1729 area_set_cell_property (GtkCellArea *area,
1730 GtkCellRenderer *renderer,
1732 const GValue *value)
1734 GValue tmp_value = { 0, };
1735 GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1737 /* provide a copy to work from, convert (if necessary) and validate */
1738 g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1739 if (!g_value_transform (value, &tmp_value))
1740 g_warning ("unable to set cell property `%s' of type `%s' from value of type `%s'",
1742 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1743 G_VALUE_TYPE_NAME (value));
1744 else if (g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION))
1746 gchar *contents = g_strdup_value_contents (value);
1748 g_warning ("value \"%s\" of type `%s' is invalid for property `%s' of type `%s'",
1750 G_VALUE_TYPE_NAME (value),
1752 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
1757 class->set_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec);
1759 g_value_unset (&tmp_value);
1763 * gtk_cell_area_cell_set_valist:
1764 * @area: a #GtkCellArea
1765 * @renderer: a #GtkCellRenderer which inside @area
1766 * @first_property_name: the name of the first cell property to set
1767 * @var_args: a %NULL-terminated list of property names and values, starting
1768 * with @first_prop_name
1770 * Sets one or more cell properties for @renderer in @area.
1773 gtk_cell_area_cell_set_valist (GtkCellArea *area,
1774 GtkCellRenderer *renderer,
1775 const gchar *first_property_name,
1780 g_return_if_fail (GTK_IS_CELL_AREA (area));
1781 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1783 name = first_property_name;
1786 GValue value = { 0, };
1787 gchar *error = NULL;
1789 g_param_spec_pool_lookup (cell_property_pool, name,
1790 G_OBJECT_TYPE (area), TRUE);
1793 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1794 G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1797 if (!(pspec->flags & G_PARAM_WRITABLE))
1799 g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1800 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1804 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1805 G_VALUE_COLLECT (&value, var_args, 0, &error);
1808 g_warning ("%s: %s", G_STRLOC, error);
1811 /* we purposely leak the value here, it might not be
1812 * in a sane state if an error condition occoured
1816 area_set_cell_property (area, renderer, pspec, &value);
1817 g_value_unset (&value);
1818 name = va_arg (var_args, gchar*);
1823 * gtk_cell_area_cell_get_valist:
1824 * @area: a #GtkCellArea
1825 * @renderer: a #GtkCellRenderer inside @area
1826 * @first_property_name: the name of the first property to get
1827 * @var_args: return location for the first property, followed
1828 * optionally by more name/return location pairs, followed by %NULL
1830 * Gets the values of one or more cell properties for @renderer in @area.
1833 gtk_cell_area_cell_get_valist (GtkCellArea *area,
1834 GtkCellRenderer *renderer,
1835 const gchar *first_property_name,
1840 g_return_if_fail (GTK_IS_CELL_AREA (area));
1841 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1843 name = first_property_name;
1846 GValue value = { 0, };
1850 pspec = g_param_spec_pool_lookup (cell_property_pool, name,
1851 G_OBJECT_TYPE (area), TRUE);
1854 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1855 G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1858 if (!(pspec->flags & G_PARAM_READABLE))
1860 g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1861 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1865 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1866 area_get_cell_property (area, renderer, pspec, &value);
1867 G_VALUE_LCOPY (&value, var_args, 0, &error);
1870 g_warning ("%s: %s", G_STRLOC, error);
1872 g_value_unset (&value);
1875 g_value_unset (&value);
1876 name = va_arg (var_args, gchar*);
1881 * gtk_cell_area_cell_set_property:
1882 * @area: a #GtkCellArea
1883 * @renderer: a #GtkCellRenderer inside @area
1884 * @property_name: the name of the cell property to set
1885 * @value: the value to set the cell property to
1887 * Sets a cell property for @renderer in @area.
1890 gtk_cell_area_cell_set_property (GtkCellArea *area,
1891 GtkCellRenderer *renderer,
1892 const gchar *property_name,
1893 const GValue *value)
1897 g_return_if_fail (GTK_IS_CELL_AREA (area));
1898 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1899 g_return_if_fail (property_name != NULL);
1900 g_return_if_fail (G_IS_VALUE (value));
1902 pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1903 G_OBJECT_TYPE (area), TRUE);
1905 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1906 G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1907 else if (!(pspec->flags & G_PARAM_WRITABLE))
1908 g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1909 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1912 area_set_cell_property (area, renderer, pspec, value);
1917 * gtk_cell_area_cell_get_property:
1918 * @area: a #GtkCellArea
1919 * @renderer: a #GtkCellRenderer inside @area
1920 * @property_name: the name of the property to get
1921 * @value: a location to return the value
1923 * Gets the value of a cell property for @renderer in @area.
1926 gtk_cell_area_cell_get_property (GtkCellArea *area,
1927 GtkCellRenderer *renderer,
1928 const gchar *property_name,
1933 g_return_if_fail (GTK_IS_CELL_AREA (area));
1934 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1935 g_return_if_fail (property_name != NULL);
1936 g_return_if_fail (G_IS_VALUE (value));
1938 pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1939 G_OBJECT_TYPE (area), TRUE);
1941 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1942 G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1943 else if (!(pspec->flags & G_PARAM_READABLE))
1944 g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1945 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1948 GValue *prop_value, tmp_value = { 0, };
1950 /* auto-conversion of the callers value type
1952 if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
1954 g_value_reset (value);
1957 else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
1959 g_warning ("can't retrieve cell property `%s' of type `%s' as value of type `%s'",
1961 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1962 G_VALUE_TYPE_NAME (value));
1967 g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1968 prop_value = &tmp_value;
1971 area_get_cell_property (area, renderer, pspec, prop_value);
1973 if (prop_value != value)
1975 g_value_transform (prop_value, value);
1976 g_value_unset (&tmp_value);
1981 /*************************************************************
1983 *************************************************************/
1986 * gtk_cell_area_can_focus:
1987 * @area: a #GtkCellArea
1989 * Returns whether the area can receive keyboard focus,
1990 * after applying new attributes to @area.
1992 * Returns: whether @area can receive focus.
1995 gtk_cell_area_can_focus (GtkCellArea *area)
1997 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
1999 return GTK_CELL_AREA_GET_CLASS (area)->can_focus (area);
2003 * gtk_cell_area_focus:
2004 * @area: a #GtkCellArea
2005 * @direction: the #GtkDirectionType
2007 * This should be called by the @area's owning layout widget
2008 * when focus is to be passed to @area, or moved within @area
2009 * for a given @direction and row data.
2011 * Implementing #GtkCellArea classes should implement this
2012 * method to receive and navigate focus in it's own way particular
2013 * to how it lays out cells.
2015 * Returns: %TRUE if focus remains inside @area as a result of this call.
2018 gtk_cell_area_focus (GtkCellArea *area,
2019 GtkDirectionType direction)
2021 GtkCellAreaClass *class;
2023 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2025 class = GTK_CELL_AREA_GET_CLASS (area);
2028 return class->focus (area, direction);
2030 g_warning ("GtkCellAreaClass::focus not implemented for `%s'",
2031 g_type_name (G_TYPE_FROM_INSTANCE (area)));
2037 * gtk_cell_area_activate:
2038 * @area: a #GtkCellArea
2039 * @context: the #GtkCellAreaContext in context with the current row data
2040 * @widget: the #GtkWidget that @area is rendering on
2041 * @cell_area: the size and location of @area relative to @widget's allocation
2042 * @flags: the #GtkCellRendererState flags for @area for this row of data.
2044 * Activates @area, usually by activating the currently focused
2045 * cell, however some subclasses which embed widgets in the area
2046 * can also activate a widget if it currently has the focus.
2048 * Returns: Whether @area was successfully activated.
2051 gtk_cell_area_activate (GtkCellArea *area,
2052 GtkCellAreaContext *context,
2054 const GdkRectangle *cell_area,
2055 GtkCellRendererState flags)
2057 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2059 return GTK_CELL_AREA_GET_CLASS (area)->activate (area, context, widget, cell_area, flags);
2064 * gtk_cell_area_set_focus_cell:
2065 * @area: a #GtkCellArea
2066 * @focus_cell: the #GtkCellRenderer to give focus to
2068 * This is generally called from #GtkCellArea implementations
2069 * either gtk_cell_area_grab_focus() or gtk_cell_area_update_focus()
2070 * is called. It's also up to the #GtkCellArea implementation
2071 * to update the focused cell when receiving events from
2072 * gtk_cell_area_event() appropriately.
2075 gtk_cell_area_set_focus_cell (GtkCellArea *area,
2076 GtkCellRenderer *renderer)
2078 GtkCellAreaPrivate *priv;
2080 g_return_if_fail (GTK_IS_CELL_AREA (area));
2081 g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer));
2085 if (priv->focus_cell != renderer)
2087 if (priv->focus_cell)
2088 g_object_unref (priv->focus_cell);
2090 priv->focus_cell = renderer;
2092 if (priv->focus_cell)
2093 g_object_ref (priv->focus_cell);
2095 g_object_notify (G_OBJECT (area), "focus-cell");
2098 /* Signal that the current focus renderer for this path changed
2099 * (it may be that the focus cell did not change, but the row
2100 * may have changed so we need to signal it) */
2101 g_signal_emit (area, cell_area_signals[SIGNAL_FOCUS_CHANGED], 0,
2102 priv->focus_cell, priv->current_path);
2107 * gtk_cell_area_get_focus_cell:
2108 * @area: a #GtkCellArea
2110 * Retrieves the currently focused cell for @area
2112 * Returns: the currently focused cell in @area.
2115 gtk_cell_area_get_focus_cell (GtkCellArea *area)
2117 GtkCellAreaPrivate *priv;
2119 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2123 return priv->focus_cell;
2127 /*************************************************************
2128 * API: Focus Siblings *
2129 *************************************************************/
2132 * gtk_cell_area_add_focus_sibling:
2133 * @area: a #GtkCellArea
2134 * @renderer: the #GtkCellRenderer expected to have focus
2135 * @sibling: the #GtkCellRenderer to add to @renderer's focus area
2137 * Adds @sibling to @renderer's focusable area, focus will be drawn
2138 * around @renderer and all of it's siblings if @renderer can
2139 * focus for a given row.
2141 * Events handled by focus siblings can also activate the given
2142 * focusable @renderer.
2145 gtk_cell_area_add_focus_sibling (GtkCellArea *area,
2146 GtkCellRenderer *renderer,
2147 GtkCellRenderer *sibling)
2149 GtkCellAreaPrivate *priv;
2152 g_return_if_fail (GTK_IS_CELL_AREA (area));
2153 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2154 g_return_if_fail (GTK_IS_CELL_RENDERER (sibling));
2155 g_return_if_fail (renderer != sibling);
2156 g_return_if_fail (gtk_cell_area_has_renderer (area, renderer));
2157 g_return_if_fail (gtk_cell_area_has_renderer (area, sibling));
2158 g_return_if_fail (!gtk_cell_area_is_focus_sibling (area, renderer, sibling));
2160 /* XXX We should also check that sibling is not in any other renderer's sibling
2161 * list already, a renderer can be sibling of only one focusable renderer
2167 siblings = g_hash_table_lookup (priv->focus_siblings, renderer);
2170 siblings = g_list_append (siblings, sibling);
2173 siblings = g_list_append (siblings, sibling);
2174 g_hash_table_insert (priv->focus_siblings, renderer, siblings);
2179 * gtk_cell_area_remove_focus_sibling:
2180 * @area: a #GtkCellArea
2181 * @renderer: the #GtkCellRenderer expected to have focus
2182 * @sibling: the #GtkCellRenderer to remove from @renderer's focus area
2184 * Removes @sibling from @renderer's focus sibling list
2185 * (see gtk_cell_area_add_focus_sibling()).
2188 gtk_cell_area_remove_focus_sibling (GtkCellArea *area,
2189 GtkCellRenderer *renderer,
2190 GtkCellRenderer *sibling)
2192 GtkCellAreaPrivate *priv;
2195 g_return_if_fail (GTK_IS_CELL_AREA (area));
2196 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2197 g_return_if_fail (GTK_IS_CELL_RENDERER (sibling));
2198 g_return_if_fail (gtk_cell_area_is_focus_sibling (area, renderer, sibling));
2202 siblings = g_hash_table_lookup (priv->focus_siblings, renderer);
2204 siblings = g_list_copy (siblings);
2205 siblings = g_list_remove (siblings, sibling);
2208 g_hash_table_remove (priv->focus_siblings, renderer);
2210 g_hash_table_insert (priv->focus_siblings, renderer, siblings);
2214 * gtk_cell_area_is_focus_sibling:
2215 * @area: a #GtkCellArea
2216 * @renderer: the #GtkCellRenderer expected to have focus
2217 * @sibling: the #GtkCellRenderer to check against @renderer's sibling list
2219 * Returns %TRUE if @sibling is one of @renderer's focus siblings
2220 * (see gtk_cell_area_add_focus_sibling()).
2223 gtk_cell_area_is_focus_sibling (GtkCellArea *area,
2224 GtkCellRenderer *renderer,
2225 GtkCellRenderer *sibling)
2227 GtkCellAreaPrivate *priv;
2228 GList *siblings, *l;
2230 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2231 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
2232 g_return_val_if_fail (GTK_IS_CELL_RENDERER (sibling), FALSE);
2236 siblings = g_hash_table_lookup (priv->focus_siblings, renderer);
2238 for (l = siblings; l; l = l->next)
2240 GtkCellRenderer *a_sibling = l->data;
2242 if (a_sibling == sibling)
2250 * gtk_cell_area_get_focus_siblings:
2251 * @area: a #GtkCellArea
2252 * @renderer: the #GtkCellRenderer expected to have focus
2254 * Gets the focus sibling cell renderers for @renderer.
2256 * Returns: A #GList of #GtkCellRenderers. The returned list is internal and should not be freed.
2259 gtk_cell_area_get_focus_siblings (GtkCellArea *area,
2260 GtkCellRenderer *renderer)
2262 GtkCellAreaPrivate *priv;
2264 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2265 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), NULL);
2269 return g_hash_table_lookup (priv->focus_siblings, renderer);
2273 * gtk_cell_area_get_focus_from_sibling:
2274 * @area: a #GtkCellArea
2275 * @renderer: the #GtkCellRenderer
2277 * Gets the #GtkCellRenderer which is expected to be focusable
2278 * for which @renderer is, or may be a sibling.
2280 * This is handy for #GtkCellArea subclasses when handling events,
2281 * after determining the renderer at the event location it can
2282 * then chose to activate the focus cell for which the event
2283 * cell may have been a sibling.
2285 * Returns: the #GtkCellRenderer for which @renderer is a sibling, or %NULL.
2288 gtk_cell_area_get_focus_from_sibling (GtkCellArea *area,
2289 GtkCellRenderer *renderer)
2291 GtkCellRenderer *ret_renderer = NULL;
2292 GList *renderers, *l;
2294 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2295 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), NULL);
2297 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (area));
2299 for (l = renderers; l; l = l->next)
2301 GtkCellRenderer *a_renderer = l->data;
2304 for (list = gtk_cell_area_get_focus_siblings (area, a_renderer);
2305 list; list = list->next)
2307 GtkCellRenderer *sibling_renderer = list->data;
2309 if (sibling_renderer == renderer)
2311 ret_renderer = a_renderer;
2316 g_list_free (renderers);
2318 return ret_renderer;
2321 /*************************************************************
2322 * API: Cell Activation/Editing *
2323 *************************************************************/
2325 gtk_cell_area_add_editable (GtkCellArea *area,
2326 GtkCellRenderer *renderer,
2327 GtkCellEditable *editable,
2328 GdkRectangle *cell_area)
2330 g_signal_emit (area, cell_area_signals[SIGNAL_ADD_EDITABLE], 0,
2331 renderer, editable, cell_area, area->priv->current_path);
2335 gtk_cell_area_remove_editable (GtkCellArea *area,
2336 GtkCellRenderer *renderer,
2337 GtkCellEditable *editable)
2339 g_signal_emit (area, cell_area_signals[SIGNAL_REMOVE_EDITABLE], 0, renderer, editable);
2343 cell_area_remove_widget_cb (GtkCellEditable *editable,
2346 GtkCellAreaPrivate *priv = area->priv;
2348 g_assert (priv->edit_widget == editable);
2349 g_assert (priv->edited_cell != NULL);
2351 gtk_cell_area_remove_editable (area, priv->edited_cell, priv->edit_widget);
2353 /* Now that we're done with editing the widget and it can be removed,
2354 * remove our references to the widget and disconnect handlers */
2355 gtk_cell_area_set_edited_cell (area, NULL);
2356 gtk_cell_area_set_edit_widget (area, NULL);
2360 gtk_cell_area_set_edited_cell (GtkCellArea *area,
2361 GtkCellRenderer *renderer)
2363 GtkCellAreaPrivate *priv;
2365 g_return_if_fail (GTK_IS_CELL_AREA (area));
2366 g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer));
2370 if (priv->edited_cell != renderer)
2372 if (priv->edited_cell)
2373 g_object_unref (priv->edited_cell);
2375 priv->edited_cell = renderer;
2377 if (priv->edited_cell)
2378 g_object_ref (priv->edited_cell);
2380 g_object_notify (G_OBJECT (area), "edited-cell");
2385 gtk_cell_area_set_edit_widget (GtkCellArea *area,
2386 GtkCellEditable *editable)
2388 GtkCellAreaPrivate *priv;
2390 g_return_if_fail (GTK_IS_CELL_AREA (area));
2391 g_return_if_fail (editable == NULL || GTK_IS_CELL_EDITABLE (editable));
2395 if (priv->edit_widget != editable)
2397 if (priv->edit_widget)
2399 g_signal_handler_disconnect (priv->edit_widget, priv->remove_widget_id);
2401 g_object_unref (priv->edit_widget);
2404 priv->edit_widget = editable;
2406 if (priv->edit_widget)
2408 priv->remove_widget_id =
2409 g_signal_connect (priv->edit_widget, "remove-widget",
2410 G_CALLBACK (cell_area_remove_widget_cb), area);
2412 g_object_ref (priv->edit_widget);
2415 g_object_notify (G_OBJECT (area), "edit-widget");
2420 * gtk_cell_area_get_edited_cell:
2421 * @area: a #GtkCellArea
2423 * Gets the #GtkCellRenderer in @area that is currently
2426 * Returns: The currently edited #GtkCellRenderer
2429 gtk_cell_area_get_edited_cell (GtkCellArea *area)
2431 GtkCellAreaPrivate *priv;
2433 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2437 return priv->edited_cell;
2441 * gtk_cell_area_get_edit_widget:
2442 * @area: a #GtkCellArea
2444 * Gets the #GtkCellEditable widget currently used
2445 * to edit the currently edited cell.
2447 * Returns: The currently active #GtkCellEditable widget
2450 gtk_cell_area_get_edit_widget (GtkCellArea *area)
2452 GtkCellAreaPrivate *priv;
2454 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2458 return priv->edit_widget;
2462 * gtk_cell_area_activate_cell:
2463 * @area: a #GtkCellArea
2464 * @widget: the #GtkWidget that @area is rendering onto
2465 * @renderer: the #GtkCellRenderer in @area to activate
2466 * @event: the #GdkEvent for which cell activation should occur
2467 * @cell_area: the #GdkRectangle in @widget relative coordinates
2468 * of @renderer for the current row.
2469 * @flags: the #GtkCellRendererState for @renderer
2471 * This is used by #GtkCellArea subclasses when handling events
2472 * to activate cells, the base #GtkCellArea class activates cells
2473 * for keyboard events for free in it's own GtkCellArea->activate()
2476 * Returns: whether cell activation was successful
2479 gtk_cell_area_activate_cell (GtkCellArea *area,
2481 GtkCellRenderer *renderer,
2483 const GdkRectangle *cell_area,
2484 GtkCellRendererState flags)
2486 GtkCellRendererMode mode;
2487 GdkRectangle inner_area;
2488 GtkCellAreaPrivate *priv;
2490 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2491 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
2492 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
2493 g_return_val_if_fail (cell_area != NULL, FALSE);
2497 /* Remove margins from the background area to produce the cell area.
2499 * XXX Maybe have to do some rtl mode treatment here...
2501 gtk_cell_area_inner_cell_area (area, widget, cell_area, &inner_area);
2503 g_object_get (renderer, "mode", &mode, NULL);
2505 if (mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
2507 if (gtk_cell_renderer_activate (renderer,
2515 else if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
2517 GtkCellEditable *editable_widget;
2520 gtk_cell_renderer_start_editing (renderer,
2527 if (editable_widget != NULL)
2529 GdkRectangle edit_area;
2531 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (editable_widget), FALSE);
2533 gtk_cell_area_set_edited_cell (area, renderer);
2534 gtk_cell_area_set_edit_widget (area, editable_widget);
2536 gtk_cell_area_aligned_cell_area (area, widget, renderer, &inner_area, &edit_area);
2538 /* Signal that editing started so that callers can get
2539 * a handle on the editable_widget */
2540 gtk_cell_area_add_editable (area, priv->focus_cell, editable_widget, &edit_area);
2542 /* If the signal was successfully handled start the editing */
2543 if (gtk_widget_get_parent (GTK_WIDGET (editable_widget)))
2545 gtk_cell_editable_start_editing (editable_widget, NULL);
2546 gtk_widget_grab_focus (GTK_WIDGET (editable_widget));
2550 /* Otherwise clear the editing state and fire a warning */
2551 gtk_cell_area_set_edited_cell (area, NULL);
2552 gtk_cell_area_set_edit_widget (area, NULL);
2554 g_warning ("GtkCellArea::add-editable fired in the dark, no cell editing was started.");
2565 * gtk_cell_area_stop_editing:
2566 * @area: a #GtkCellArea
2567 * @canceled: whether editing was canceled.
2569 * Explicitly stops the editing of the currently
2570 * edited cell (see gtk_cell_area_get_edited_cell()).
2572 * If @canceled is %TRUE, the cell renderer will emit
2573 * the ::editing-canceled signal.
2576 gtk_cell_area_stop_editing (GtkCellArea *area,
2579 GtkCellAreaPrivate *priv;
2581 g_return_if_fail (GTK_IS_CELL_AREA (area));
2585 if (priv->edited_cell)
2587 GtkCellEditable *edit_widget = g_object_ref (priv->edit_widget);
2588 GtkCellRenderer *edit_cell = g_object_ref (priv->edited_cell);
2590 /* Stop editing of the cell renderer */
2591 gtk_cell_renderer_stop_editing (priv->edited_cell, canceled);
2593 /* Remove any references to the editable widget */
2594 gtk_cell_area_set_edited_cell (area, NULL);
2595 gtk_cell_area_set_edit_widget (area, NULL);
2597 /* Send the remove-widget signal explicitly (this is done after setting
2598 * the edit cell/widget NULL to avoid feedback)
2600 gtk_cell_area_remove_editable (area, edit_cell, edit_widget);
2601 g_object_unref (edit_cell);
2602 g_object_unref (edit_widget);
2606 /*************************************************************
2607 * API: Convenience for area implementations *
2608 *************************************************************/
2611 gtk_cell_area_inner_cell_area (GtkCellArea *area,
2613 const GdkRectangle *cell_area,
2614 GdkRectangle *inner_area)
2616 gint focus_line_width;
2618 g_return_if_fail (GTK_IS_CELL_AREA (area));
2619 g_return_if_fail (GTK_IS_WIDGET (widget));
2620 g_return_if_fail (cell_area != NULL);
2621 g_return_if_fail (inner_area != NULL);
2623 gtk_widget_style_get (widget, "focus-line-width", &focus_line_width, NULL);
2625 *inner_area = *cell_area;
2627 inner_area->x += focus_line_width;
2628 inner_area->width -= focus_line_width * 2;
2629 inner_area->y += focus_line_width;
2630 inner_area->height -= focus_line_width * 2;
2634 gtk_cell_area_aligned_cell_area (GtkCellArea *area,
2636 GtkCellRenderer *renderer,
2637 const GdkRectangle *cell_area,
2638 GdkRectangle *aligned_area)
2640 GtkCellAreaPrivate *priv;
2641 gint opposite_size, x_offset, y_offset;
2643 g_return_if_fail (GTK_IS_CELL_AREA (area));
2644 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2645 g_return_if_fail (GTK_IS_WIDGET (widget));
2646 g_return_if_fail (cell_area != NULL);
2647 g_return_if_fail (aligned_area != NULL);
2651 *aligned_area = *cell_area;
2653 /* Trim up the aligned size */
2654 if (gtk_cell_renderer_get_request_mode (renderer) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
2656 gtk_cell_renderer_get_preferred_height_for_width (renderer, widget,
2657 aligned_area->width,
2658 NULL, &opposite_size);
2660 aligned_area->height = MIN (opposite_size, aligned_area->height);
2664 gtk_cell_renderer_get_preferred_width_for_height (renderer, widget,
2665 aligned_area->height,
2666 NULL, &opposite_size);
2668 aligned_area->width = MIN (opposite_size, aligned_area->width);
2671 /* offset the cell position */
2672 _gtk_cell_renderer_calc_offset (renderer, cell_area,
2673 gtk_widget_get_direction (widget),
2674 aligned_area->width,
2675 aligned_area->height,
2676 &x_offset, &y_offset);
2678 aligned_area->x += x_offset;
2679 aligned_area->y += y_offset;
2683 gtk_cell_area_request_renderer (GtkCellArea *area,
2684 GtkCellRenderer *renderer,
2685 GtkOrientation orientation,
2691 GtkCellAreaPrivate *priv;
2692 gint focus_line_width;
2694 g_return_if_fail (GTK_IS_CELL_AREA (area));
2695 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2696 g_return_if_fail (GTK_IS_WIDGET (widget));
2697 g_return_if_fail (minimum_size != NULL);
2698 g_return_if_fail (natural_size != NULL);
2702 gtk_widget_style_get (widget, "focus-line-width", &focus_line_width, NULL);
2704 focus_line_width *= 2;
2706 if (orientation == GTK_ORIENTATION_HORIZONTAL)
2709 gtk_cell_renderer_get_preferred_width (renderer, widget, minimum_size, natural_size);
2712 for_size = MAX (0, for_size - focus_line_width);
2714 gtk_cell_renderer_get_preferred_width_for_height (renderer, widget, for_size,
2715 minimum_size, natural_size);
2718 else /* GTK_ORIENTATION_VERTICAL */
2721 gtk_cell_renderer_get_preferred_height (renderer, widget, minimum_size, natural_size);
2724 for_size = MAX (0, for_size - focus_line_width);
2726 gtk_cell_renderer_get_preferred_height_for_width (renderer, widget, for_size,
2727 minimum_size, natural_size);
2731 *minimum_size += focus_line_width;
2732 *natural_size += focus_line_width;