+static GtkSizeRequestMode
+gtk_cell_area_real_get_request_mode (GtkCellArea *area)
+{
+ /* By default cell areas are height-for-width. */
+ return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
+}
+
+static void
+gtk_cell_area_real_get_preferred_width (GtkCellArea *area,
+ GtkCellAreaContext *context,
+ GtkWidget *widget,
+ gint *minimum_width,
+ gint *natural_width)
+{
+ g_warning ("GtkCellAreaClass::get_preferred_width not implemented for `%s'",
+ g_type_name (G_TYPE_FROM_INSTANCE (area)));
+}
+
+static void
+gtk_cell_area_real_get_preferred_height (GtkCellArea *area,
+ GtkCellAreaContext *context,
+ GtkWidget *widget,
+ gint *minimum_height,
+ gint *natural_height)
+{
+ g_warning ("GtkCellAreaClass::get_preferred_height not implemented for `%s'",
+ g_type_name (G_TYPE_FROM_INSTANCE (area)));
+}
+
+static void
+gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area,
+ GtkCellAreaContext *context,
+ GtkWidget *widget,
+ gint width,
+ gint *minimum_height,
+ gint *natural_height)
+{
+ /* If the area doesnt do height-for-width, fallback on base preferred height */
+ GTK_CELL_AREA_GET_CLASS (area)->get_preferred_height (area, context, widget, minimum_height, natural_height);
+}
+
+static void
+gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area,
+ GtkCellAreaContext *context,
+ GtkWidget *widget,
+ gint height,
+ gint *minimum_width,
+ gint *natural_width)
+{
+ /* If the area doesnt do width-for-height, fallback on base preferred width */
+ GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, context, widget, minimum_width, natural_width);
+}
+
+static gboolean
+get_is_activatable (GtkCellRenderer *renderer,
+ gboolean *activatable)
+{
+
+ if (gtk_cell_renderer_is_activatable (renderer))
+ *activatable = TRUE;
+
+ return *activatable;
+}
+
+static gboolean
+gtk_cell_area_real_is_activatable (GtkCellArea *area)
+{
+ gboolean activatable = FALSE;
+
+ /* Checks if any renderer can focus for the currently applied
+ * attributes.
+ *
+ * Subclasses can override this in the case that they are also
+ * rendering widgets as well as renderers.
+ */
+ gtk_cell_area_foreach (area, (GtkCellCallback)get_is_activatable, &activatable);
+
+ return activatable;
+}
+
+static gboolean
+gtk_cell_area_real_activate (GtkCellArea *area,
+ GtkCellAreaContext *context,
+ GtkWidget *widget,
+ const GdkRectangle *cell_area,
+ GtkCellRendererState flags,
+ gboolean edit_only)
+{
+ GtkCellAreaPrivate *priv = area->priv;
+ GdkRectangle renderer_area;
+ GtkCellRenderer *activate_cell = NULL;
+ GtkCellRendererMode mode;
+
+ if (priv->focus_cell)
+ {
+ g_object_get (priv->focus_cell, "mode", &mode, NULL);
+
+ if (gtk_cell_renderer_get_visible (priv->focus_cell) &&
+ (edit_only ? mode == GTK_CELL_RENDERER_MODE_EDITABLE :
+ mode != GTK_CELL_RENDERER_MODE_INERT))
+ activate_cell = priv->focus_cell;
+ }
+ else
+ {
+ GList *cells, *l;
+
+ /* GtkTreeView sometimes wants to activate a cell when no
+ * cells are in focus.
+ */
+ cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (area));
+ for (l = cells; l && !activate_cell; l = l->next)
+ {
+ GtkCellRenderer *renderer = l->data;
+
+ g_object_get (renderer, "mode", &mode, NULL);
+
+ if (gtk_cell_renderer_get_visible (renderer) &&
+ (edit_only ? mode == GTK_CELL_RENDERER_MODE_EDITABLE :
+ mode != GTK_CELL_RENDERER_MODE_INERT))
+ activate_cell = renderer;
+ }
+ g_list_free (cells);
+ }
+
+ if (activate_cell)
+ {
+ /* Get the allocation of the focused cell.
+ */
+ gtk_cell_area_get_cell_allocation (area, context, widget, activate_cell,
+ cell_area, &renderer_area);
+
+ /* Activate or Edit the cell
+ *
+ * Currently just not sending an event, renderers afaics dont use
+ * the event argument anyway, worst case is we can synthesize one.
+ */
+ if (gtk_cell_area_activate_cell (area, widget, activate_cell, NULL,
+ &renderer_area, flags))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+gtk_cell_area_real_focus (GtkCellArea *area,
+ GtkDirectionType direction)
+{
+ g_warning ("GtkCellAreaClass::focus not implemented for `%s'",
+ g_type_name (G_TYPE_FROM_INSTANCE (area)));
+ return FALSE;
+}
+
+/*************************************************************
+ * GtkCellLayoutIface *
+ *************************************************************/
+static void
+gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface)
+{
+ iface->pack_start = gtk_cell_area_pack_default;
+ iface->pack_end = gtk_cell_area_pack_default;
+ iface->clear = gtk_cell_area_clear;
+ iface->add_attribute = gtk_cell_area_add_attribute;
+ iface->set_cell_data_func = gtk_cell_area_set_cell_data_func;
+ iface->clear_attributes = gtk_cell_area_clear_attributes;
+ iface->reorder = gtk_cell_area_reorder;
+ iface->get_cells = gtk_cell_area_get_cells;
+ iface->get_area = gtk_cell_area_get_area;
+}
+
+static void
+gtk_cell_area_pack_default (GtkCellLayout *cell_layout,
+ GtkCellRenderer *renderer,
+ gboolean expand)
+{
+ gtk_cell_area_add (GTK_CELL_AREA (cell_layout), renderer);
+}
+
+static void
+gtk_cell_area_clear (GtkCellLayout *cell_layout)
+{
+ GtkCellArea *area = GTK_CELL_AREA (cell_layout);
+ GList *l, *cells =
+ gtk_cell_layout_get_cells (cell_layout);
+
+ for (l = cells; l; l = l->next)
+ {
+ GtkCellRenderer *renderer = l->data;
+ gtk_cell_area_remove (area, renderer);
+ }
+
+ g_list_free (cells);
+}
+
+static void
+gtk_cell_area_add_attribute (GtkCellLayout *cell_layout,
+ GtkCellRenderer *renderer,
+ const gchar *attribute,
+ gint column)
+{
+ gtk_cell_area_attribute_connect (GTK_CELL_AREA (cell_layout),
+ renderer, attribute, column);
+}
+
+static void
+gtk_cell_area_set_cell_data_func (GtkCellLayout *cell_layout,
+ GtkCellRenderer *renderer,
+ GtkCellLayoutDataFunc func,
+ gpointer func_data,
+ GDestroyNotify destroy)
+{
+ GtkCellArea *area = GTK_CELL_AREA (cell_layout);
+
+ _gtk_cell_area_set_cell_data_func_with_proxy (area, renderer, (GFunc)func, func_data, destroy, NULL);
+}
+
+static void
+gtk_cell_area_clear_attributes (GtkCellLayout *cell_layout,
+ GtkCellRenderer *renderer)
+{
+ GtkCellArea *area = GTK_CELL_AREA (cell_layout);
+ GtkCellAreaPrivate *priv = area->priv;
+ CellInfo *info;
+
+ info = g_hash_table_lookup (priv->cell_info, renderer);
+
+ if (info)
+ {
+ g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
+ g_slist_free (info->attributes);
+
+ info->attributes = NULL;
+ }
+}
+
+static void
+gtk_cell_area_reorder (GtkCellLayout *cell_layout,
+ GtkCellRenderer *cell,
+ gint position)
+{
+ g_warning ("GtkCellLayout::reorder not implemented for `%s'",
+ g_type_name (G_TYPE_FROM_INSTANCE (cell_layout)));
+}
+
+static gboolean
+accum_cells (GtkCellRenderer *renderer,
+ GList **accum)
+{
+ *accum = g_list_prepend (*accum, renderer);
+
+ return FALSE;
+}
+
+static GList *
+gtk_cell_area_get_cells (GtkCellLayout *cell_layout)
+{
+ GList *cells = NULL;
+
+ gtk_cell_area_foreach (GTK_CELL_AREA (cell_layout),
+ (GtkCellCallback)accum_cells,
+ &cells);
+
+ return g_list_reverse (cells);
+}
+
+static GtkCellArea *
+gtk_cell_area_get_area (GtkCellLayout *cell_layout)
+{
+ return GTK_CELL_AREA (cell_layout);
+}
+
+/*************************************************************
+ * GtkBuildableIface *
+ *************************************************************/
+static void
+gtk_cell_area_buildable_init (GtkBuildableIface *iface)
+{
+ iface->add_child = _gtk_cell_layout_buildable_add_child;
+ iface->custom_tag_start = _gtk_cell_layout_buildable_custom_tag_start;
+ iface->custom_tag_end = gtk_cell_area_buildable_custom_tag_end;
+}
+
+static void
+gtk_cell_area_buildable_custom_tag_end (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer *data)
+{
+ /* Just ignore the boolean return from here */
+ _gtk_cell_layout_buildable_custom_tag_end (buildable, builder, child, tagname, data);
+}
+
+/*************************************************************
+ * API *
+ *************************************************************/
+
+/**
+ * gtk_cell_area_add:
+ * @area: a #GtkCellArea
+ * @renderer: the #GtkCellRenderer to add to @area
+ *
+ * Adds @renderer to @area with the default child cell properties.
+ *
+ * Since: 3.0
+ */
+void
+gtk_cell_area_add (GtkCellArea *area,
+ GtkCellRenderer *renderer)
+{
+ g_return_if_fail (GTK_IS_CELL_AREA (area));
+ g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
+
+ GTK_CELL_AREA_GET_CLASS (area)->add (area, renderer);
+}
+
+/**
+ * gtk_cell_area_remove:
+ * @area: a #GtkCellArea
+ * @renderer: the #GtkCellRenderer to remove from @area
+ *
+ * Removes @renderer from @area.
+ *
+ * Since: 3.0
+ */
+void
+gtk_cell_area_remove (GtkCellArea *area,
+ GtkCellRenderer *renderer)
+{
+ GtkCellAreaPrivate *priv;
+ GList *renderers, *l;
+
+ g_return_if_fail (GTK_IS_CELL_AREA (area));
+ g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
+
+ priv = area->priv;
+
+ /* Remove any custom attributes and custom cell data func here first */
+ g_hash_table_remove (priv->cell_info, renderer);
+
+ /* Remove focus siblings of this renderer */
+ g_hash_table_remove (priv->focus_siblings, renderer);
+
+ /* Remove this renderer from any focus renderer's sibling list */
+ renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (area));
+
+ for (l = renderers; l; l = l->next)
+ {
+ GtkCellRenderer *focus_renderer = l->data;
+
+ if (gtk_cell_area_is_focus_sibling (area, focus_renderer, renderer))
+ {
+ gtk_cell_area_remove_focus_sibling (area, focus_renderer, renderer);
+ break;
+ }
+ }
+
+ g_list_free (renderers);
+
+ GTK_CELL_AREA_GET_CLASS (area)->remove (area, renderer);
+}
+
+static gboolean
+get_has_renderer (GtkCellRenderer *renderer,
+ HasRendererCheck *check)
+{
+ if (renderer == check->renderer)
+ check->has_renderer = TRUE;
+
+ return check->has_renderer;
+}
+
+/**
+ * gtk_cell_area_has_renderer:
+ * @area: a #GtkCellArea
+ * @renderer: the #GtkCellRenderer to check
+ *
+ * Checks if @area contains @renderer.
+ *
+ * Return value: %TRUE if @renderer is in the @area.
+ *
+ * Since: 3.0
+ */
+gboolean
+gtk_cell_area_has_renderer (GtkCellArea *area,
+ GtkCellRenderer *renderer)
+{
+ HasRendererCheck check = { renderer, FALSE };
+
+ g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
+ g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
+
+ gtk_cell_area_foreach (area, (GtkCellCallback)get_has_renderer, &check);
+
+ return check.has_renderer;
+}
+
+/**
+ * gtk_cell_area_foreach:
+ * @area: a #GtkCellArea
+ * @callback: (scope call): the #GtkCellCallback to call
+ * @callback_data: user provided data pointer
+ *
+ * Calls @callback for every #GtkCellRenderer in @area.
+ *
+ * Since: 3.0
+ */
+void
+gtk_cell_area_foreach (GtkCellArea *area,
+ GtkCellCallback callback,
+ gpointer callback_data)
+{
+ g_return_if_fail (GTK_IS_CELL_AREA (area));
+ g_return_if_fail (callback != NULL);
+
+ GTK_CELL_AREA_GET_CLASS (area)->foreach (area, callback, callback_data);
+}
+
+/**
+ * gtk_cell_area_foreach_alloc:
+ * @area: a #GtkCellArea
+ * @context: the #GtkCellAreaContext for this row of data.
+ * @widget: the #GtkWidget that @area is rendering to
+ * @cell_area: the @widget relative coordinates and size for @area
+ * @background_area: the @widget relative coordinates of the background area
+ * @callback: (scope call): the #GtkCellAllocCallback to call
+ * @callback_data: user provided data pointer
+ *
+ * Calls @callback for every #GtkCellRenderer in @area with the
+ * allocated rectangle inside @cell_area.
+ *
+ * Since: 3.0
+ */
+void
+gtk_cell_area_foreach_alloc (GtkCellArea *area,
+ GtkCellAreaContext *context,
+ GtkWidget *widget,
+ const GdkRectangle *cell_area,
+ const GdkRectangle *background_area,
+ GtkCellAllocCallback callback,
+ gpointer callback_data)
+{
+ g_return_if_fail (GTK_IS_CELL_AREA (area));
+ g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (cell_area != NULL);
+ g_return_if_fail (callback != NULL);
+
+ GTK_CELL_AREA_GET_CLASS (area)->foreach_alloc (area, context, widget,
+ cell_area, background_area,
+ callback, callback_data);
+}
+
+/**
+ * gtk_cell_area_event:
+ * @area: a #GtkCellArea
+ * @context: the #GtkCellAreaContext for this row of data.
+ * @widget: the #GtkWidget that @area is rendering to
+ * @event: the #GdkEvent to handle
+ * @cell_area: the @widget relative coordinates for @area
+ * @flags: the #GtkCellRendererState for @area in this row.
+ *
+ * Delegates event handling to a #GtkCellArea.
+ *
+ * Return value: %TRUE if the event was handled by @area.
+ *
+ * Since: 3.0
+ */
+gint
+gtk_cell_area_event (GtkCellArea *area,
+ GtkCellAreaContext *context,
+ GtkWidget *widget,
+ GdkEvent *event,
+ const GdkRectangle *cell_area,
+ GtkCellRendererState flags)
+{
+ GtkCellAreaClass *class;
+
+ g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
+ g_return_val_if_fail (GTK_IS_CELL_AREA_CONTEXT (context), 0);
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
+ g_return_val_if_fail (event != NULL, 0);
+ g_return_val_if_fail (cell_area != NULL, 0);
+
+ class = GTK_CELL_AREA_GET_CLASS (area);
+
+ if (class->event)
+ return class->event (area, context, widget, event, cell_area, flags);
+
+ g_warning ("GtkCellAreaClass::event not implemented for `%s'",
+ g_type_name (G_TYPE_FROM_INSTANCE (area)));
+ return 0;
+}
+
+/**
+ * gtk_cell_area_render:
+ * @area: a #GtkCellArea
+ * @context: the #GtkCellAreaContext for this row of data.
+ * @widget: the #GtkWidget that @area is rendering to
+ * @cr: the #cairo_t to render with
+ * @background_area: the @widget relative coordinates for @area's background
+ * @cell_area: the @widget relative coordinates for @area
+ * @flags: the #GtkCellRendererState for @area in this row.
+ * @paint_focus: whether @area should paint focus on focused cells for focused rows or not.
+ *
+ * Renders @area's cells according to @area's layout onto @widget at
+ * the given coordinates.
+ *
+ * Since: 3.0
+ */
+void
+gtk_cell_area_render (GtkCellArea *area,
+ GtkCellAreaContext *context,
+ GtkWidget *widget,
+ cairo_t *cr,
+ const GdkRectangle *background_area,
+ const GdkRectangle *cell_area,
+ GtkCellRendererState flags,
+ gboolean paint_focus)
+{
+ GtkCellAreaClass *class;
+
+ g_return_if_fail (GTK_IS_CELL_AREA (area));
+ g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (cr != NULL);
+ g_return_if_fail (background_area != NULL);
+ g_return_if_fail (cell_area != NULL);
+
+ class = GTK_CELL_AREA_GET_CLASS (area);
+
+ if (class->render)
+ class->render (area, context, widget, cr, background_area, cell_area, flags, paint_focus);
+ else
+ g_warning ("GtkCellAreaClass::render not implemented for `%s'",
+ g_type_name (G_TYPE_FROM_INSTANCE (area)));
+}
+
+static gboolean
+get_cell_allocation (GtkCellRenderer *renderer,
+ const GdkRectangle *cell_area,
+ const GdkRectangle *cell_background,
+ RendererAllocationData *data)
+{
+ if (data->renderer == renderer)
+ data->allocation = *cell_area;
+
+ return (data->renderer == renderer);
+}
+
+/**
+ * gtk_cell_area_get_cell_allocation:
+ * @area: a #GtkCellArea
+ * @context: the #GtkCellAreaContext used to hold sizes for @area.
+ * @widget: the #GtkWidget that @area is rendering on
+ * @renderer: the #GtkCellRenderer to get the allocation for
+ * @cell_area: the whole allocated area for @area in @widget
+ * for this row
+ * @allocation: (out): where to store the allocation for @renderer
+ *
+ * Derives the allocation of @renderer inside @area if @area
+ * were to be renderered in @cell_area.
+ *
+ * Since: 3.0
+ */
+void
+gtk_cell_area_get_cell_allocation (GtkCellArea *area,
+ GtkCellAreaContext *context,
+ GtkWidget *widget,
+ GtkCellRenderer *renderer,
+ const GdkRectangle *cell_area,
+ GdkRectangle *allocation)
+{
+ RendererAllocationData data = { renderer, { 0, } };
+
+ g_return_if_fail (GTK_IS_CELL_AREA (area));
+ g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
+ g_return_if_fail (cell_area != NULL);
+ g_return_if_fail (allocation != NULL);
+
+ gtk_cell_area_foreach_alloc (area, context, widget, cell_area, cell_area,
+ (GtkCellAllocCallback)get_cell_allocation, &data);
+
+ *allocation = data.allocation;
+}
+
+static gboolean
+get_cell_by_position (GtkCellRenderer *renderer,
+ const GdkRectangle *cell_area,
+ const GdkRectangle *cell_background,
+ CellByPositionData *data)
+{
+ if (data->x >= cell_area->x && data->x < cell_area->x + cell_area->width &&
+ data->y >= cell_area->y && data->y < cell_area->y + cell_area->height)
+ {
+ data->renderer = renderer;
+ data->cell_area = *cell_area;
+ }
+
+ return (data->renderer != NULL);
+}
+
+/**
+ * gtk_cell_area_get_cell_at_position:
+ * @area: a #GtkCellArea
+ * @context: the #GtkCellAreaContext used to hold sizes for @area.
+ * @widget: the #GtkWidget that @area is rendering on
+ * @cell_area: the whole allocated area for @area in @widget
+ * for this row
+ * @x: the x position
+ * @y: the y position
+ * @alloc_area: (out) (allow-none): where to store the inner allocated area of the
+ * returned cell renderer, or %NULL.
+ *
+ * Gets the #GtkCellRenderer at @x and @y coordinates inside @area and optionally
+ * returns the full cell allocation for it inside @cell_area.
+ *
+ * Return value: (transfer none): the #GtkCellRenderer at @x and @y.
+ *
+ * Since: 3.0
+ */
+GtkCellRenderer *
+gtk_cell_area_get_cell_at_position (GtkCellArea *area,
+ GtkCellAreaContext *context,
+ GtkWidget *widget,
+ const GdkRectangle *cell_area,
+ gint x,
+ gint y,
+ GdkRectangle *alloc_area)
+{
+ CellByPositionData data = { x, y, NULL, { 0, } };
+
+ g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
+ g_return_val_if_fail (GTK_IS_CELL_AREA_CONTEXT (context), NULL);
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+ g_return_val_if_fail (cell_area != NULL, NULL);
+ g_return_val_if_fail (x >= cell_area->x && x <= cell_area->x + cell_area->width, NULL);
+ g_return_val_if_fail (y >= cell_area->y && y <= cell_area->y + cell_area->height, NULL);
+
+ gtk_cell_area_foreach_alloc (area, context, widget, cell_area, cell_area,
+ (GtkCellAllocCallback)get_cell_by_position, &data);
+
+ if (alloc_area)
+ *alloc_area = data.cell_area;
+
+ return data.renderer;
+}
+
+/*************************************************************
+ * API: Geometry *
+ *************************************************************/
+/**
+ * gtk_cell_area_create_context:
+ * @area: a #GtkCellArea
+ *
+ * Creates a #GtkCellAreaContext to be used with @area for
+ * all purposes. #GtkCellAreaContext stores geometry information
+ * for rows for which it was operated on, it is important to use
+ * the same context for the same row of data at all times (i.e.
+ * one should render and handle events with the same #GtkCellAreaContext
+ * which was used to request the size of those rows of data).
+ *
+ * Return value: (transfer full): a newly created #GtkCellAreaContext which can be used with @area.
+ *
+ * Since: 3.0
+ */
+GtkCellAreaContext *
+gtk_cell_area_create_context (GtkCellArea *area)
+{
+ g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
+
+ return GTK_CELL_AREA_GET_CLASS (area)->create_context (area);
+}
+
+/**
+ * gtk_cell_area_copy_context:
+ * @area: a #GtkCellArea
+ * @context: the #GtkCellAreaContext to copy
+ *
+ * This is sometimes needed for cases where rows need to share
+ * alignments in one orientation but may be separately grouped
+ * in the opposing orientation.
+ *
+ * For instance, #GtkIconView creates all icons (rows) to have
+ * the same width and the cells theirin to have the same
+ * horizontal alignments. However each row of icons may have
+ * a separate collective height. #GtkIconView uses this to
+ * request the heights of each row based on a context which
+ * was already used to request all the row widths that are
+ * to be displayed.
+ *
+ * Return value: (transfer full): a newly created #GtkCellAreaContext copy of @context.
+ *
+ * Since: 3.0
+ */
+GtkCellAreaContext *
+gtk_cell_area_copy_context (GtkCellArea *area,
+ GtkCellAreaContext *context)
+{
+ g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
+ g_return_val_if_fail (GTK_IS_CELL_AREA_CONTEXT (context), NULL);
+
+ return GTK_CELL_AREA_GET_CLASS (area)->copy_context (area, context);
+}
+
+/**
+ * gtk_cell_area_get_request_mode:
+ * @area: a #GtkCellArea
+ *
+ * Gets whether the area prefers a height-for-width layout
+ * or a width-for-height layout.
+ *
+ * Return value: The #GtkSizeRequestMode preferred by @area.
+ *
+ * Since: 3.0
+ */
+GtkSizeRequestMode
+gtk_cell_area_get_request_mode (GtkCellArea *area)
+{
+ g_return_val_if_fail (GTK_IS_CELL_AREA (area),
+ GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH);
+
+ return GTK_CELL_AREA_GET_CLASS (area)->get_request_mode (area);
+}
+
+/**
+ * gtk_cell_area_get_preferred_width:
+ * @area: a #GtkCellArea
+ * @context: the #GtkCellAreaContext to perform this request with
+ * @widget: the #GtkWidget where @area will be rendering
+ * @minimum_width: (out) (allow-none): location to store the minimum width, or %NULL
+ * @natural_width: (out) (allow-none): location to store the natural width, or %NULL
+ *
+ * Retrieves a cell area's initial minimum and natural width.
+ *
+ * @area will store some geometrical information in @context along the way;
+ * when requesting sizes over an arbitrary number of rows, it's not important
+ * to check the @minimum_width and @natural_width of this call but rather to
+ * consult gtk_cell_area_context_get_preferred_width() after a series of
+ * requests.
+ *
+ * Since: 3.0
+ */
+void
+gtk_cell_area_get_preferred_width (GtkCellArea *area,
+ GtkCellAreaContext *context,
+ GtkWidget *widget,
+ gint *minimum_width,
+ gint *natural_width)
+{
+ g_return_if_fail (GTK_IS_CELL_AREA (area));
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, context, widget,
+ minimum_width, natural_width);
+}
+
+/**
+ * gtk_cell_area_get_preferred_height_for_width:
+ * @area: a #GtkCellArea
+ * @context: the #GtkCellAreaContext which has already been requested for widths.
+ * @widget: the #GtkWidget where @area will be rendering
+ * @width: the width for which to check the height of this area
+ * @minimum_height: (out) (allow-none): location to store the minimum height, or %NULL
+ * @natural_height: (out) (allow-none): location to store the natural height, or %NULL
+ *
+ * Retrieves a cell area's minimum and natural height if it would be given
+ * the specified @width.
+ *
+ * @area stores some geometrical information in @context along the way
+ * while calling gtk_cell_area_get_preferred_width(). It's important to
+ * perform a series of gtk_cell_area_get_preferred_width() requests with
+ * @context first and then call gtk_cell_area_get_preferred_height_for_width()
+ * on each cell area individually to get the height for width of each
+ * fully requested row.
+ *
+ * If at some point, the width of a single row changes, it should be
+ * requested with gtk_cell_area_get_preferred_width() again and then
+ * the full width of the requested rows checked again with
+ * gtk_cell_area_context_get_preferred_width().
+ *
+ * Since: 3.0
+ */
+void
+gtk_cell_area_get_preferred_height_for_width (GtkCellArea *area,
+ GtkCellAreaContext *context,
+ GtkWidget *widget,
+ gint width,
+ gint *minimum_height,
+ gint *natural_height)
+{
+ GtkCellAreaClass *class;
+
+ g_return_if_fail (GTK_IS_CELL_AREA (area));
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ class = GTK_CELL_AREA_GET_CLASS (area);
+ class->get_preferred_height_for_width (area, context, widget, width, minimum_height, natural_height);
+}
+
+
+/**
+ * gtk_cell_area_get_preferred_height:
+ * @area: a #GtkCellArea
+ * @context: the #GtkCellAreaContext to perform this request with
+ * @widget: the #GtkWidget where @area will be rendering
+ * @minimum_height: (out) (allow-none): location to store the minimum height, or %NULL
+ * @natural_height: (out) (allow-none): location to store the natural height, or %NULL
+ *
+ * Retrieves a cell area's initial minimum and natural height.
+ *
+ * @area will store some geometrical information in @context along the way;
+ * when requesting sizes over an arbitrary number of rows, it's not important
+ * to check the @minimum_height and @natural_height of this call but rather to
+ * consult gtk_cell_area_context_get_preferred_height() after a series of
+ * requests.
+ *
+ * Since: 3.0
+ */
+void
+gtk_cell_area_get_preferred_height (GtkCellArea *area,
+ GtkCellAreaContext *context,
+ GtkWidget *widget,
+ gint *minimum_height,
+ gint *natural_height)
+{
+ g_return_if_fail (GTK_IS_CELL_AREA (area));
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ GTK_CELL_AREA_GET_CLASS (area)->get_preferred_height (area, context, widget,
+ minimum_height, natural_height);
+}
+
+/**
+ * gtk_cell_area_get_preferred_width_for_height:
+ * @area: a #GtkCellArea
+ * @context: the #GtkCellAreaContext which has already been requested for widths.
+ * @widget: the #GtkWidget where @area will be rendering
+ * @height: the height for which to check the width of this area
+ * @minimum_width: (out) (allow-none): location to store the minimum width, or %NULL
+ * @natural_width: (out) (allow-none): location to store the natural width, or %NULL
+ *
+ * Retrieves a cell area's minimum and natural width if it would be given
+ * the specified @height.
+ *
+ * @area stores some geometrical information in @context along the way
+ * while calling gtk_cell_area_get_preferred_height(). It's important to
+ * perform a series of gtk_cell_area_get_preferred_height() requests with
+ * @context first and then call gtk_cell_area_get_preferred_width_for_height()
+ * on each cell area individually to get the height for width of each
+ * fully requested row.
+ *
+ * If at some point, the height of a single row changes, it should be
+ * requested with gtk_cell_area_get_preferred_height() again and then
+ * the full height of the requested rows checked again with
+ * gtk_cell_area_context_get_preferred_height().
+ *
+ * Since: 3.0
+ */
+void
+gtk_cell_area_get_preferred_width_for_height (GtkCellArea *area,
+ GtkCellAreaContext *context,
+ GtkWidget *widget,
+ gint height,
+ gint *minimum_width,
+ gint *natural_width)
+{
+ GtkCellAreaClass *class;
+
+ g_return_if_fail (GTK_IS_CELL_AREA (area));
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ class = GTK_CELL_AREA_GET_CLASS (area);
+ class->get_preferred_width_for_height (area, context, widget, height, minimum_width, natural_width);
+}
+
+/*************************************************************
+ * API: Attributes *
+ *************************************************************/
+
+/**
+ * gtk_cell_area_attribute_connect:
+ * @area: a #GtkCellArea
+ * @renderer: the #GtkCellRenderer to connect an attribute for
+ * @attribute: the attribute name
+ * @column: the #GtkTreeModel column to fetch attribute values from
+ *
+ * Connects an @attribute to apply values from @column for the
+ * #GtkTreeModel in use.
+ *
+ * Since: 3.0
+ */
+void
+gtk_cell_area_attribute_connect (GtkCellArea *area,
+ GtkCellRenderer *renderer,
+ const gchar *attribute,
+ gint column)
+{
+ GtkCellAreaPrivate *priv;
+ CellInfo *info;
+ CellAttribute *cell_attribute;
+
+ g_return_if_fail (GTK_IS_CELL_AREA (area));
+ g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
+ g_return_if_fail (attribute != NULL);
+ g_return_if_fail (gtk_cell_area_has_renderer (area, renderer));
+
+ priv = area->priv;
+ info = g_hash_table_lookup (priv->cell_info, renderer);
+
+ if (!info)
+ {
+ info = cell_info_new (NULL, NULL, NULL);
+
+ g_hash_table_insert (priv->cell_info, renderer, info);
+ }
+ else
+ {
+ GSList *node;
+
+ /* Check we are not adding the same attribute twice */
+ if ((node = g_slist_find_custom (info->attributes, attribute,
+ (GCompareFunc)cell_attribute_find)) != NULL)
+ {
+ cell_attribute = node->data;
+
+ g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
+ "since `%s' is already attributed to column %d",
+ attribute,
+ G_OBJECT_TYPE_NAME (renderer),
+ attribute, cell_attribute->column);
+ return;
+ }
+ }
+
+ cell_attribute = cell_attribute_new (renderer, attribute, column);
+
+ if (!cell_attribute)
+ {
+ g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
+ "since attribute does not exist",
+ attribute,
+ G_OBJECT_TYPE_NAME (renderer));
+ return;
+ }
+
+ info->attributes = g_slist_prepend (info->attributes, cell_attribute);
+}
+
+/**
+ * gtk_cell_area_attribute_disconnect:
+ * @area: a #GtkCellArea
+ * @renderer: the #GtkCellRenderer to disconnect an attribute for
+ * @attribute: the attribute name
+ *
+ * Disconnects @attribute for the @renderer in @area so that
+ * attribute will no longer be updated with values from the
+ * model.
+ *
+ * Since: 3.0
+ */
+void
+gtk_cell_area_attribute_disconnect (GtkCellArea *area,
+ GtkCellRenderer *renderer,
+ const gchar *attribute)
+{
+ GtkCellAreaPrivate *priv;
+ CellInfo *info;
+ CellAttribute *cell_attribute;
+ GSList *node;
+
+ g_return_if_fail (GTK_IS_CELL_AREA (area));
+ g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
+ g_return_if_fail (attribute != NULL);
+ g_return_if_fail (gtk_cell_area_has_renderer (area, renderer));
+
+ priv = area->priv;
+ info = g_hash_table_lookup (priv->cell_info, renderer);
+
+ if (info)
+ {
+ node = g_slist_find_custom (info->attributes, attribute,
+ (GCompareFunc)cell_attribute_find);
+ if (node)
+ {
+ cell_attribute = node->data;
+
+ cell_attribute_free (cell_attribute);
+
+ info->attributes = g_slist_delete_link (info->attributes, node);
+ }
+ }
+}
+
+/**
+ * gtk_cell_area_apply_attributes:
+ * @area: a #GtkCellArea
+ * @tree_model: the #GtkTreeModel to pull values from
+ * @iter: the #GtkTreeIter in @tree_model to apply values for
+ * @is_expander: whether @iter has children
+ * @is_expanded: whether @iter is expanded in the view and
+ * children are visible
+ *
+ * Applies any connected attributes to the renderers in
+ * @area by pulling the values from @tree_model.
+ *
+ * Since: 3.0
+ */
+void
+gtk_cell_area_apply_attributes (GtkCellArea *area,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gboolean is_expander,
+ gboolean is_expanded)
+{
+ g_return_if_fail (GTK_IS_CELL_AREA (area));
+ g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
+ g_return_if_fail (iter != NULL);
+
+ g_signal_emit (area, cell_area_signals[SIGNAL_APPLY_ATTRIBUTES], 0,
+ tree_model, iter, is_expander, is_expanded);
+}
+
+/**
+ * gtk_cell_area_get_current_path_string:
+ * @area: a #GtkCellArea
+ *
+ * Gets the current #GtkTreePath string for the currently
+ * applied #GtkTreeIter, this is implicitly updated when
+ * gtk_cell_area_apply_attributes() is called and can be
+ * used to interact with renderers from #GtkCellArea
+ * subclasses.
+ *
+ * Return value: The current #GtkTreePath string for the current
+ * attributes applied to @area. This string belongs to the area and
+ * should not be freed.
+ *
+ * Since: 3.0
+ */
+const gchar *
+gtk_cell_area_get_current_path_string (GtkCellArea *area)
+{
+ GtkCellAreaPrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
+
+ priv = area->priv;
+
+ return priv->current_path;
+}
+
+
+/*************************************************************
+ * API: Cell Properties *
+ *************************************************************/
+/**
+ * gtk_cell_area_class_install_cell_property:
+ * @aclass: a #GtkCellAreaClass
+ * @property_id: the id for the property
+ * @pspec: the #GParamSpec for the property
+ *
+ * Installs a cell property on a cell area class.
+ *
+ * Since: 3.0
+ */
+void
+gtk_cell_area_class_install_cell_property (GtkCellAreaClass *aclass,
+ guint property_id,
+ GParamSpec *pspec)
+{
+ g_return_if_fail (GTK_IS_CELL_AREA_CLASS (aclass));
+ g_return_if_fail (G_IS_PARAM_SPEC (pspec));
+ if (pspec->flags & G_PARAM_WRITABLE)
+ g_return_if_fail (aclass->set_cell_property != NULL);
+ if (pspec->flags & G_PARAM_READABLE)
+ g_return_if_fail (aclass->get_cell_property != NULL);
+ g_return_if_fail (property_id > 0);
+ g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0); /* paranoid */
+ g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0);
+
+ if (g_param_spec_pool_lookup (cell_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (aclass), TRUE))
+ {
+ g_warning (G_STRLOC ": class `%s' already contains a cell property named `%s'",
+ G_OBJECT_CLASS_NAME (aclass), pspec->name);
+ return;
+ }
+ g_param_spec_ref (pspec);
+ g_param_spec_sink (pspec);
+ PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
+ g_param_spec_pool_insert (cell_property_pool, pspec, G_OBJECT_CLASS_TYPE (aclass));
+}
+
+/**
+ * gtk_cell_area_class_find_cell_property:
+ * @aclass: a #GtkCellAreaClass
+ * @property_name: the name of the child property to find
+ *
+ * Finds a cell property of a cell area class by name.
+ *
+ * Return value: (transfer none): the #GParamSpec of the child property
+ * or %NULL if @aclass has no child property with that name.
+ *
+ * Since: 3.0
+ */
+GParamSpec*
+gtk_cell_area_class_find_cell_property (GtkCellAreaClass *aclass,
+ const gchar *property_name)
+{
+ g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
+ g_return_val_if_fail (property_name != NULL, NULL);
+
+ return g_param_spec_pool_lookup (cell_property_pool,
+ property_name,
+ G_OBJECT_CLASS_TYPE (aclass),
+ TRUE);
+}
+
+/**
+ * gtk_cell_area_class_list_cell_properties:
+ * @aclass: a #GtkCellAreaClass
+ * @n_properties: location to return the number of cell properties found
+ *
+ * Returns all cell properties of a cell area class.
+ *
+ * Return value: (array length=n_properties) (transfer container): a newly
+ * allocated %NULL-terminated array of #GParamSpec*. The array
+ * must be freed with g_free().
+ *
+ * Since: 3.0
+ */
+GParamSpec**
+gtk_cell_area_class_list_cell_properties (GtkCellAreaClass *aclass,
+ guint *n_properties)
+{
+ GParamSpec **pspecs;
+ guint n;
+
+ g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
+
+ pspecs = g_param_spec_pool_list (cell_property_pool,
+ G_OBJECT_CLASS_TYPE (aclass),
+ &n);
+ if (n_properties)
+ *n_properties = n;
+
+ return pspecs;
+}
+
+/**
+ * gtk_cell_area_add_with_properties:
+ * @area: a #GtkCellArea
+ * @renderer: a #GtkCellRenderer to be placed inside @area
+ * @first_prop_name: the name of the first cell property to set
+ * @...: a %NULL-terminated list of property names and values, starting
+ * with @first_prop_name
+ *
+ * Adds @renderer to @area, setting cell properties at the same time.
+ * See gtk_cell_area_add() and gtk_cell_area_cell_set() for more details.
+ *
+ * Since: 3.0
+ */
+void
+gtk_cell_area_add_with_properties (GtkCellArea *area,
+ GtkCellRenderer *renderer,
+ const gchar *first_prop_name,
+ ...)