]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkcellview.c
Merge branch 'master' into treeview-refactor
[~andy/gtk] / gtk / gtkcellview.c
index 5f8fe39574dba99b9f14c0bbf3eddbf49d4adcae..09840d4ecaf02e022d10b1f8c1c9deb4032d7862 100644 (file)
 #include "gtkcellrenderertext.h"
 #include "gtkcellrendererpixbuf.h"
 #include "gtkprivate.h"
+#include "gtksizerequest.h"
 #include <gobject/gmarshal.h>
 #include "gtkbuildable.h"
-#include "gtkalias.h"
+
 
 typedef struct _GtkCellViewCellInfo GtkCellViewCellInfo;
 struct _GtkCellViewCellInfo
@@ -35,6 +36,7 @@ struct _GtkCellViewCellInfo
   GtkCellRenderer *cell;
 
   gint requested_width;
+  gint natural_width;
   gint real_width;
   guint expand : 1;
   guint pack : 1;
@@ -53,7 +55,7 @@ struct _GtkCellViewPrivate
   GList *cell_list;
   gint spacing;
 
-  GdkColor background;
+  GdkRGBA background;
   gboolean background_set;
 };
 
@@ -68,12 +70,10 @@ static void        gtk_cell_view_set_property             (GObject          *obj
                                                            const GValue     *value,
                                                            GParamSpec       *pspec);
 static void        gtk_cell_view_finalize                 (GObject          *object);
-static void        gtk_cell_view_size_request             (GtkWidget        *widget,
-                                                           GtkRequisition   *requisition);
 static void        gtk_cell_view_size_allocate            (GtkWidget        *widget,
                                                            GtkAllocation    *allocation);
-static gboolean    gtk_cell_view_expose                   (GtkWidget        *widget,
-                                                           GdkEventExpose   *event);
+static gboolean    gtk_cell_view_draw                     (GtkWidget        *widget,
+                                                           cairo_t          *cr);
 static void        gtk_cell_view_set_value                (GtkCellView     *cell_view,
                                                            GtkCellRenderer *renderer,
                                                            gchar           *property,
@@ -120,15 +120,30 @@ static void       gtk_cell_view_buildable_custom_tag_end       (GtkBuildable
                                                                const gchar           *tagname,
                                                                gpointer              *data);
 
+static void       gtk_cell_view_get_preferred_width            (GtkWidget             *widget,
+                                                               gint                  *minimum_size,
+                                                               gint                  *natural_size);
+static void       gtk_cell_view_get_preferred_height           (GtkWidget             *widget,
+                                                               gint                  *minimum_size,
+                                                               gint                  *natural_size);
+static void       gtk_cell_view_get_preferred_width_for_height (GtkWidget             *widget,
+                                                               gint                   avail_size,
+                                                               gint                  *minimum_size,
+                                                               gint                  *natural_size);
+static void       gtk_cell_view_get_preferred_height_for_width (GtkWidget             *widget,
+                                                               gint                   avail_size,
+                                                               gint                  *minimum_size,
+                                                               gint                  *natural_size);
+
 static GtkBuildableIface *parent_buildable_iface;
 
-#define GTK_CELL_VIEW_GET_PRIVATE(obj)    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_CELL_VIEW, GtkCellViewPrivate))
 
 enum
 {
   PROP_0,
   PROP_BACKGROUND,
   PROP_BACKGROUND_GDK,
+  PROP_BACKGROUND_RGBA,
   PROP_BACKGROUND_SET,
   PROP_MODEL
 };
@@ -139,6 +154,7 @@ G_DEFINE_TYPE_WITH_CODE (GtkCellView, gtk_cell_view, GTK_TYPE_WIDGET,
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
                                                gtk_cell_view_buildable_init))
 
+
 static void
 gtk_cell_view_class_init (GtkCellViewClass *klass)
 {
@@ -149,9 +165,12 @@ gtk_cell_view_class_init (GtkCellViewClass *klass)
   gobject_class->set_property = gtk_cell_view_set_property;
   gobject_class->finalize = gtk_cell_view_finalize;
 
-  widget_class->expose_event = gtk_cell_view_expose;
-  widget_class->size_allocate = gtk_cell_view_size_allocate;
-  widget_class->size_request = gtk_cell_view_size_request;
+  widget_class->draw                           = gtk_cell_view_draw;
+  widget_class->size_allocate                  = gtk_cell_view_size_allocate;
+  widget_class->get_preferred_width            = gtk_cell_view_get_preferred_width;
+  widget_class->get_preferred_height           = gtk_cell_view_get_preferred_height;
+  widget_class->get_preferred_width_for_height = gtk_cell_view_get_preferred_width_for_height;
+  widget_class->get_preferred_height_for_width = gtk_cell_view_get_preferred_height_for_width;
 
   /* properties */
   g_object_class_install_property (gobject_class,
@@ -168,6 +187,20 @@ gtk_cell_view_class_init (GtkCellViewClass *klass)
                                                       P_("Background color as a GdkColor"),
                                                       GDK_TYPE_COLOR,
                                                       GTK_PARAM_READWRITE));
+  /**
+   * GtkCellView:background-rgba
+   *
+   * The background color as a #GdkRGBA
+   *
+   * Since: 3.0
+   */
+  g_object_class_install_property (gobject_class,
+                                   PROP_BACKGROUND_RGBA,
+                                   g_param_spec_boxed ("background-rgba",
+                                                      P_("Background RGBA color"),
+                                                      P_("Background color as a GdkRGBA"),
+                                                      GDK_TYPE_RGBA,
+                                                      GTK_PARAM_READWRITE));
 
   /**
    * GtkCellView:model
@@ -229,11 +262,17 @@ gtk_cell_view_get_property (GObject    *object,
         {
           GdkColor color;
 
-          color = view->priv->background;
+          color.red = (guint) (view->priv->background.red * 65535);
+          color.green = (guint) (view->priv->background.green * 65535);
+          color.blue = (guint) (view->priv->background.blue * 65535);
+          color.pixel = 0;
 
           g_value_set_boxed (value, &color);
         }
         break;
+      case PROP_BACKGROUND_RGBA:
+        g_value_set_boxed (value, &view->priv->background);
+        break;
       case PROP_BACKGROUND_SET:
         g_value_set_boolean (value, view->priv->background_set);
         break;
@@ -273,6 +312,9 @@ gtk_cell_view_set_property (GObject      *object,
       case PROP_BACKGROUND_GDK:
         gtk_cell_view_set_background_color (view, g_value_get_boxed (value));
         break;
+      case PROP_BACKGROUND_RGBA:
+        gtk_cell_view_set_background_rgba (view, g_value_get_boxed (value));
+        break;
       case PROP_BACKGROUND_SET:
         view->priv->background_set = g_value_get_boolean (value);
         break;
@@ -288,9 +330,14 @@ gtk_cell_view_set_property (GObject      *object,
 static void
 gtk_cell_view_init (GtkCellView *cellview)
 {
-  GTK_WIDGET_SET_FLAGS (cellview, GTK_NO_WINDOW);
+  GtkCellViewPrivate *priv;
+
+  cellview->priv = G_TYPE_INSTANCE_GET_PRIVATE (cellview,
+                                                GTK_TYPE_CELL_VIEW,
+                                                GtkCellViewPrivate);
+  priv = cellview->priv;
 
-  cellview->priv = GTK_CELL_VIEW_GET_PRIVATE (cellview);
+  gtk_widget_set_has_window (GTK_WIDGET (cellview), FALSE);
 }
 
 static void
@@ -310,117 +357,124 @@ gtk_cell_view_finalize (GObject *object)
 }
 
 static void
-gtk_cell_view_size_request (GtkWidget      *widget,
-                            GtkRequisition *requisition)
+gtk_cell_view_size_allocate (GtkWidget     *widget,
+                             GtkAllocation *allocation)
 {
-  GList *i;
-  gboolean first_cell = TRUE;
-  GtkCellView *cellview;
+  GtkCellView      *cellview;
+  GtkRequestedSize *sizes;
+  GList            *list;
+  gint              n_visible_cells, n_expand_cells;
+  gint              avail_width = 0;
+  gint              extra_per_cell, extra_extra, i;
+  gboolean          first_cell = TRUE;
+
+  gtk_widget_set_allocation (widget, allocation);
 
   cellview = GTK_CELL_VIEW (widget);
 
-  requisition->width = 0;
-  requisition->height = 0;
+  avail_width = allocation->width;
 
-  if (cellview->priv->displayed_row)
-    gtk_cell_view_set_cell_data (cellview);
+  /* Count visible/expand children */
+  for (n_visible_cells = 0, n_expand_cells = 0, list = cellview->priv->cell_list; 
+       list; list = list->next)
+    {
+      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
 
-  for (i = cellview->priv->cell_list; i; i = i->next)
+      n_visible_cells++;
+
+      if (info->expand)
+        n_expand_cells++;
+    }
+
+  sizes = g_new0 (GtkRequestedSize, n_visible_cells);
+
+  /* checking how much extra space we have */
+  for (i = 0, list = cellview->priv->cell_list; list; list = list->next)
     {
-      gint width, height;
-      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
+      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
 
-      if (!info->cell->visible)
+      if (!gtk_cell_renderer_get_visible (info->cell))
         continue;
 
-      if (!first_cell)
-        requisition->width += cellview->priv->spacing;
+      sizes[i].data = info;
+      sizes[i].minimum_size = info->requested_width;
+      sizes[i].natural_size = info->natural_width;
 
-      gtk_cell_renderer_get_size (info->cell, widget, NULL, NULL, NULL,
-                                  &width, &height);
+      if (!first_cell)
+       avail_width -= cellview->priv->spacing;
 
-      info->requested_width = width;
-      requisition->width += width;
-      requisition->height = MAX (requisition->height, height);
+      avail_width -= sizes[i].minimum_size;
 
       first_cell = FALSE;
-    }
-}
 
-static void
-gtk_cell_view_size_allocate (GtkWidget     *widget,
-                             GtkAllocation *allocation)
-{
-  GList *i;
-  gint expand_cell_count = 0;
-  gint full_requested_width = 0;
-  gint extra_space;
-  GtkCellView *cellview;
+      i++;
+    }
 
-  widget->allocation = *allocation;
+  avail_width = gtk_distribute_natural_allocation (MAX (0, avail_width), n_visible_cells, sizes);
 
-  cellview = GTK_CELL_VIEW (widget);
+  /* Deal with any expand space... */
+  if (n_expand_cells > 0)
+    {
+      extra_per_cell = avail_width / n_expand_cells;
+      extra_extra    = avail_width % n_expand_cells;
+    }
+  else
+    /* Everything just left-aligned if no cells expand */
+    extra_per_cell = extra_extra = 0;
 
-  /* checking how much extra space we have */
-  for (i = cellview->priv->cell_list; i; i = i->next)
+  for (i = 0, list = cellview->priv->cell_list; list; list = list->next)
     {
-      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
+      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
 
-      if (!info->cell->visible)
+      if (!gtk_cell_renderer_get_visible (info->cell))
         continue;
 
+      info->real_width = sizes[i].minimum_size;
+
       if (info->expand)
-        expand_cell_count++;
+        {
+         info->real_width += extra_per_cell;
 
-      full_requested_width += info->requested_width;
+         if (extra_extra)
+           {
+             info->real_width++;
+             extra_extra--;
+           }
+       }
+      
+      /* increment index into sizes for visible children */
+      i++;
     }
 
-  extra_space = widget->allocation.width - full_requested_width;
-  if (extra_space < 0)
-    extra_space = 0;
-  else if (extra_space > 0 && expand_cell_count > 0)
-    extra_space /= expand_cell_count;
-
-  for (i = cellview->priv->cell_list; i; i = i->next)
-    {
-      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
-
-      if (!info->cell->visible)
-        continue;
-
-      info->real_width = info->requested_width +
-        (info->expand ? extra_space : 0);
-    }
+  g_free (sizes);
 }
 
 static gboolean
-gtk_cell_view_expose (GtkWidget      *widget,
-                      GdkEventExpose *event)
+gtk_cell_view_draw (GtkWidget *widget,
+                    cairo_t   *cr)
 {
-  GList *i;
+  GList *list;
   GtkCellView *cellview;
   GdkRectangle area;
   GtkCellRendererState state;
   gboolean rtl = (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL);
+  GtkPackType packing;
+  int width;
 
   cellview = GTK_CELL_VIEW (widget);
 
-  if (! GTK_WIDGET_DRAWABLE (widget))
-    return FALSE;
+  /* render cells */
+  area.x = 0;
+  area.y = 0;
+  area.width = width = gtk_widget_get_allocated_width (widget);
+  area.height = gtk_widget_get_allocated_height (widget);
 
   /* "blank" background */
   if (cellview->priv->background_set)
     {
-      cairo_t *cr = gdk_cairo_create (GTK_WIDGET (cellview)->window);
-
-      gdk_cairo_rectangle (cr, &widget->allocation);
-      cairo_set_source_rgb (cr,
-                           cellview->priv->background.red / 65535.,
-                           cellview->priv->background.green / 65535.,
-                           cellview->priv->background.blue / 65535.);
+      gdk_cairo_rectangle (cr, &area);
+      gdk_cairo_set_source_rgba (cr, &cellview->priv->background);
       cairo_fill (cr);
-
-      cairo_destroy (cr);
     }
 
   /* set cell data (if available) */
@@ -429,69 +483,51 @@ gtk_cell_view_expose (GtkWidget      *widget,
   else if (cellview->priv->model)
     return FALSE;
 
-  /* render cells */
-  area = widget->allocation;
-
-  /* we draw on our very own window, initialize x and y to zero */
-  area.x = widget->allocation.x + (rtl ? widget->allocation.width : 0); 
-  area.y = widget->allocation.y;
-
-  if (GTK_WIDGET_STATE (widget) == GTK_STATE_PRELIGHT)
+  if (gtk_widget_get_state (widget) == GTK_STATE_PRELIGHT)
     state = GTK_CELL_RENDERER_PRELIT;
-  else if (GTK_WIDGET_STATE (widget) == GTK_STATE_INSENSITIVE)
+  else if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
     state = GTK_CELL_RENDERER_INSENSITIVE;
   else
     state = 0;
       
-  /* PACK_START */
-  for (i = cellview->priv->cell_list; i; i = i->next)
-    {
-      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
-
-      if (info->pack == GTK_PACK_END)
-        continue;
-
-      if (!info->cell->visible)
-        continue;
-
-      area.width = info->real_width;
-      if (rtl)                                             
-         area.x -= area.width;
-
-      gtk_cell_renderer_render (info->cell,
-                                event->window,
-                                widget,
-                                /* FIXME! */
-                                &area, &area, &event->area, state);
-
-      if (!rtl)                                           
-         area.x += info->real_width;
-    }
-
-   area.x = rtl ? widget->allocation.x : (widget->allocation.x + widget->allocation.width);  
-
-  /* PACK_END */
-  for (i = cellview->priv->cell_list; i; i = i->next)
+  for (packing = GTK_PACK_START; packing <= GTK_PACK_END; ++packing)
     {
-      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
-
-      if (info->pack == GTK_PACK_START)
-        continue;
-
-      if (!info->cell->visible)
-        continue;
+      if (packing == GTK_PACK_START)
+       area.x = rtl ? width : 0;
+      else
+       area.x = rtl ? 0 : width;
 
-      area.width = info->real_width;
-      if (!rtl)
-         area.x -= area.width;   
-
-      gtk_cell_renderer_render (info->cell,
-                                widget->window,
-                                widget,
-                                /* FIXME ! */
-                                &area, &area, &event->area, state);
-      if (rtl)
-         area.x += info->real_width;
+      for (list = cellview->priv->cell_list; list; list = list->next)
+       {
+         GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
+
+         if (info->pack != packing)
+           continue;
+
+         if (!gtk_cell_renderer_get_visible (info->cell))
+           continue;
+
+         area.width = info->real_width;
+
+         if ((packing == GTK_PACK_START && rtl) ||
+             (packing == GTK_PACK_END && !rtl))
+           area.x -= area.width;
+
+         gtk_cell_renderer_render (info->cell,
+                                    cr,
+                                    widget,
+                                    /* FIXME! */
+                                    &area, &area, state);
+
+         if ((packing == GTK_PACK_START && !rtl) ||
+             (packing == GTK_PACK_END && rtl))
+           {
+             area.x += area.width;
+             area.x += cellview->priv->spacing;
+           }
+         else
+           area.x -= cellview->priv->spacing;
+       }
     }
 
   return FALSE;
@@ -580,6 +616,8 @@ gtk_cell_view_cell_layout_pack_start (GtkCellLayout   *layout,
   info->pack = GTK_PACK_START;
 
   cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info);
+
+  gtk_widget_queue_resize (GTK_WIDGET (cellview));
 }
 
 static void
@@ -600,6 +638,8 @@ gtk_cell_view_cell_layout_pack_end (GtkCellLayout   *layout,
   info->pack = GTK_PACK_END;
 
   cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info);
+
+  gtk_widget_queue_resize (GTK_WIDGET (cellview));
 }
 
 static void
@@ -768,7 +808,7 @@ gtk_cell_view_new_with_text (const gchar *text)
  * @markup: the text to display in the cell view
  *
  * Creates a new #GtkCellView widget, adds a #GtkCellRendererText 
- * to it, and makes its show @markup. The text can text can be
+ * to it, and makes it show @markup. The text can be
  * marked up with the <link linkend="PangoMarkupFormat">Pango text 
  * markup language</link>.
  *
@@ -857,10 +897,10 @@ gtk_cell_view_set_value (GtkCellView     *cell_view,
 /**
  * gtk_cell_view_set_model:
  * @cell_view: a #GtkCellView
- * @model: a #GtkTreeModel
+ * @model: (allow-none): a #GtkTreeModel
  *
  * Sets the model for @cell_view.  If @cell_view already has a model
- * set, it will remove it before setting the new model.  If @model is 
+ * set, it will remove it before setting the new model.  If @model is
  * %NULL, then it will unset the old model.
  *
  * Since: 2.6
@@ -895,7 +935,7 @@ gtk_cell_view_set_model (GtkCellView  *cell_view,
  * Returns the model for @cell_view. If no model is used %NULL is
  * returned.
  *
- * Returns: a #GtkTreeModel used or %NULL
+ * Returns: (transfer none): a #GtkTreeModel used or %NULL
  *
  * Since: 2.16
  **/
@@ -910,8 +950,8 @@ gtk_cell_view_get_model (GtkCellView *cell_view)
 /**
  * gtk_cell_view_set_displayed_row:
  * @cell_view: a #GtkCellView
- * @path: a #GtkTreePath or %NULL to unset.
- * 
+ * @path: (allow-none): a #GtkTreePath or %NULL to unset.
+ *
  * Sets the row of the model that is currently displayed
  * by the #GtkCellView. If the path is unset, then the
  * contents of the cellview "stick" at their last value;
@@ -979,32 +1019,108 @@ gtk_cell_view_get_displayed_row (GtkCellView *cell_view)
  * Return value: %TRUE
  *
  * Since: 2.6
+ * 
+ * Deprecated: 3.0: Use gtk_cell_view_get_desired_width_of_row() and
+ * gtk_cell_view_get_desired_height_for_width_of_row() instead.
  */
 gboolean
 gtk_cell_view_get_size_of_row (GtkCellView    *cell_view,
                                GtkTreePath    *path,
                                GtkRequisition *requisition)
 {
-  GtkTreeRowReference *tmp;
   GtkRequisition req;
 
   g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), FALSE);
   g_return_val_if_fail (path != NULL, FALSE);
-  g_return_val_if_fail (requisition != NULL, FALSE);
+
+  /* Return the minimum height for the minimum width */
+  gtk_cell_view_get_desired_width_of_row (cell_view, path, &req.width, NULL);
+  gtk_cell_view_get_desired_height_for_width_of_row (cell_view, path, req.width, &req.height, NULL);
+
+  if (requisition)
+    *requisition = req;
+
+  return TRUE;
+}
+
+
+/**
+ * gtk_cell_view_get_desired_width_of_row:
+ * @cell_view: a #GtkCellView
+ * @path: a #GtkTreePath 
+ * @minimum_size: location to store the minimum size 
+ * @natural_size: location to store the natural size 
+ *
+ * Sets @minimum_size and @natural_size to the width desired by @cell_view 
+ * to display the model row pointed to by @path.
+ * 
+ * Since: 3.0
+ */
+void
+gtk_cell_view_get_desired_width_of_row (GtkCellView     *cell_view,
+                                       GtkTreePath     *path,
+                                       gint            *minimum_size,
+                                       gint            *natural_size)
+{
+  GtkTreeRowReference *tmp;
+
+  g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
+  g_return_if_fail (path != NULL);
+  g_return_if_fail (minimum_size != NULL || natural_size != NULL);
 
   tmp = cell_view->priv->displayed_row;
   cell_view->priv->displayed_row =
     gtk_tree_row_reference_new (cell_view->priv->model, path);
 
-  gtk_cell_view_size_request (GTK_WIDGET (cell_view), requisition);
+  gtk_cell_view_get_preferred_width (GTK_WIDGET (cell_view), minimum_size, natural_size);
 
   gtk_tree_row_reference_free (cell_view->priv->displayed_row);
   cell_view->priv->displayed_row = tmp;
 
-  /* restore actual size info */
-  gtk_cell_view_size_request (GTK_WIDGET (cell_view), &req);
+  /* Restore active size (this will restore the cellrenderer info->width/requested_width's) */
+  gtk_cell_view_get_preferred_width (GTK_WIDGET (cell_view), NULL, NULL);
+}
 
-  return TRUE;
+
+/**
+ * gtk_cell_view_get_desired_height_for_width_of_row:
+ * @cell_view: a #GtkCellView
+ * @path: a #GtkTreePath 
+ * @avail_size: available width
+ * @minimum_size: location to store the minimum height 
+ * @natural_size: location to store the natural height
+ *
+ * Sets @minimum_size and @natural_size to the height desired by @cell_view 
+ * if it were allocated a width of @avail_size to display the model row 
+ * pointed to by @path.
+ * 
+ * Since: 3.0
+ */
+void
+gtk_cell_view_get_desired_height_for_width_of_row (GtkCellView     *cell_view,
+                                                  GtkTreePath     *path,
+                                                  gint             avail_size,
+                                                  gint            *minimum_size,
+                                                  gint            *natural_size)
+{
+  GtkTreeRowReference *tmp;
+
+  g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
+  g_return_if_fail (path != NULL);
+  g_return_if_fail (minimum_size != NULL || natural_size != NULL);
+
+  tmp = cell_view->priv->displayed_row;
+  cell_view->priv->displayed_row =
+    gtk_tree_row_reference_new (cell_view->priv->model, path);
+
+  /* Then get the collective height_for_width based on the cached values */
+  gtk_cell_view_get_preferred_height_for_width (GTK_WIDGET (cell_view), avail_size, minimum_size, natural_size);
+
+  gtk_tree_row_reference_free (cell_view->priv->displayed_row);
+  cell_view->priv->displayed_row = tmp;
+
+  /* Restore active size (this will restore the cellrenderer info->width/requested_width's) */
+  gtk_cell_view_get_preferred_width (GTK_WIDGET (cell_view), NULL, NULL);
 }
 
 /**
@@ -1030,7 +1146,47 @@ gtk_cell_view_set_background_color (GtkCellView    *cell_view,
           g_object_notify (G_OBJECT (cell_view), "background-set");
         }
 
-      cell_view->priv->background = *color;
+      cell_view->priv->background.red = color->red / 65535.;
+      cell_view->priv->background.green = color->green / 65535.;
+      cell_view->priv->background.blue = color->blue / 65535.;
+      cell_view->priv->background.alpha = 1;
+    }
+  else
+    {
+      if (cell_view->priv->background_set)
+        {
+          cell_view->priv->background_set = FALSE;
+          g_object_notify (G_OBJECT (cell_view), "background-set");
+        }
+    }
+
+  gtk_widget_queue_draw (GTK_WIDGET (cell_view));
+}
+
+/**
+ * gtk_cell_view_set_background_rgba:
+ * @cell_view: a #GtkCellView
+ * @rgba: the new background color
+ *
+ * Sets the background color of @cell_view.
+ *
+ * Since: 3.0
+ */
+void
+gtk_cell_view_set_background_rgba (GtkCellView   *cell_view,
+                                   const GdkRGBA *rgba)
+{
+  g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
+
+  if (rgba)
+    {
+      if (!cell_view->priv->background_set)
+        {
+          cell_view->priv->background_set = TRUE;
+          g_object_notify (G_OBJECT (cell_view), "background-set");
+        }
+
+      cell_view->priv->background = *rgba;
     }
   else
     {
@@ -1064,26 +1220,6 @@ gtk_cell_view_cell_layout_get_cells (GtkCellLayout *layout)
   return g_list_reverse (retval);
 }
 
-/**
- * gtk_cell_view_get_cell_renderers:
- * @cell_view: a #GtkCellView
- *
- * Returns the cell renderers which have been added to @cell_view.
- *
- * Return value: a list of cell renderers. The list, but not the
- *   renderers has been newly allocated and should be freed with
- *   g_list_free() when no longer needed.
- *
- * Since: 2.6
- *
- * Deprecated: 2.18: use gtk_cell_layout_get_cells() instead.
- **/
-GList *
-gtk_cell_view_get_cell_renderers (GtkCellView *cell_view)
-{
-  return gtk_cell_view_cell_layout_get_cells (GTK_CELL_LAYOUT (cell_view));
-}
-
 static gboolean
 gtk_cell_view_buildable_custom_tag_start (GtkBuildable  *buildable,
                                          GtkBuilder    *builder,
@@ -1116,6 +1252,183 @@ gtk_cell_view_buildable_custom_tag_end (GtkBuildable *buildable,
                                            data);
 }
 
+static void
+gtk_cell_view_get_preferred_width  (GtkWidget *widget,
+                                    gint      *minimum_size,
+                                    gint      *natural_size)
+{
+  GList *list;
+  gint cell_min, cell_nat;
+  gboolean first_cell = TRUE;
+  GtkCellView *cellview = GTK_CELL_VIEW (widget);
+  gint minimum, natural;
+
+  minimum = natural = 0;
+
+  if (cellview->priv->displayed_row)
+    gtk_cell_view_set_cell_data (cellview);
+
+  for (list = cellview->priv->cell_list; list; list = list->next)
+    {
+      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
+
+      if (gtk_cell_renderer_get_visible (info->cell))
+        {
+         
+         if (!first_cell)
+           {
+             minimum += cellview->priv->spacing;
+             natural += cellview->priv->spacing;
+           }
+
+         gtk_cell_renderer_get_preferred_width (info->cell,
+                                                 GTK_WIDGET (cellview), &cell_min, &cell_nat);
+         
+         info->requested_width = cell_min;
+         info->natural_width   = cell_nat;
+         
+         minimum += info->requested_width;
+         natural += info->natural_width;
+
+         first_cell = FALSE;
+        }
+    }
+
+  if (minimum_size)
+    *minimum_size = minimum;
+
+  if (natural_size)
+    *natural_size = natural;
+}
+
+static void       
+gtk_cell_view_get_preferred_height (GtkWidget *widget,
+                                    gint      *minimum_size,
+                                    gint      *natural_size)
+{
+  gint minimum_width;
+
+  /* CellViews only need to respond to height-for-width mode (cellview is pretty much
+   * an implementation detail of GtkComboBox) */
+  gtk_cell_view_get_preferred_width (widget, &minimum_width, NULL);
+  gtk_cell_view_get_preferred_height_for_width (widget, minimum_width, minimum_size, natural_size);
+}
 
-#define __GTK_CELL_VIEW_C__
-#include "gtkaliasdef.c"
+static void       
+gtk_cell_view_get_preferred_width_for_height (GtkWidget *widget,
+                                              gint       for_size,
+                                              gint      *minimum_size,
+                                              gint      *natural_size)
+{
+  /* CellViews only need to respond to height-for-width mode (cellview is pretty much
+   * an implementation detail of GtkComboBox) */
+  gtk_cell_view_get_preferred_width (widget, minimum_size, natural_size);
+}
+
+static void       
+gtk_cell_view_get_preferred_height_for_width (GtkWidget *widget,
+                                              gint       for_size,
+                                              gint      *minimum_size,
+                                              gint      *natural_size)
+{
+  GtkCellView      *cellview = GTK_CELL_VIEW (widget);
+  GList            *list;
+  GtkRequestedSize *sizes;
+  GArray           *array;
+  gint              minimum, natural, avail_size;
+  gboolean          first_cell = TRUE;
+  gint              n_expand_cells = 0;
+  gint              extra_per_cell, extra_extra, i;
+
+  minimum = natural = 0;
+  avail_size = for_size;
+
+  array = g_array_new (0, TRUE, sizeof (GtkRequestedSize));
+
+  if (cellview->priv->displayed_row)
+    gtk_cell_view_set_cell_data (cellview);
+
+  /* First allocate the right width to all cells */
+  for (list = cellview->priv->cell_list; list; list = list->next)
+    {
+      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
+
+      if (gtk_cell_renderer_get_visible (info->cell))
+        {
+         GtkRequestedSize requested;
+
+         gtk_cell_renderer_get_preferred_width (GTK_CELL_RENDERER (info->cell),
+                                                 GTK_WIDGET (cellview), 
+                                                 &requested.minimum_size, 
+                                                 &requested.natural_size);
+
+         requested.data = info;
+         g_array_append_val (array, requested);
+
+         avail_size -= requested.minimum_size;
+
+         if (!first_cell)
+           avail_size -= cellview->priv->spacing;
+
+         first_cell = FALSE;
+
+         if (info->expand)
+           n_expand_cells++;
+        }
+    }
+
+  sizes      = (GtkRequestedSize *)array->data;
+  avail_size = gtk_distribute_natural_allocation (MAX (0, avail_size), array->len, sizes);
+
+  /* Deal with any expand space... */
+  if (n_expand_cells > 0)
+    {
+      extra_per_cell = avail_size / n_expand_cells;
+      extra_extra    = avail_size % n_expand_cells;
+    }
+  else
+    /* Everything just left-aligned if no cells expand */
+    extra_per_cell = extra_extra = 0;
+
+  /* Now get the height for the real width of each cell */
+  for (i = 0, list = cellview->priv->cell_list; list; list = list->next)
+    {
+      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
+      gint cell_minimum, cell_natural;
+
+      if (gtk_cell_renderer_get_visible (info->cell))
+        {
+         gint cell_width = sizes[i].minimum_size;
+
+         g_assert (sizes[i].data == info);
+
+         if (info->expand)
+           {
+             cell_width += extra_per_cell;
+             if (extra_extra)
+               {
+                 cell_width++;
+                 extra_extra--;
+               }
+           }
+
+         /* Get the height for the real width of this cell */
+         gtk_cell_renderer_get_preferred_height_for_width (GTK_CELL_RENDERER (info->cell),
+                                                            GTK_WIDGET (widget),
+                                                            cell_width, &cell_minimum, &cell_natural);
+
+         minimum = MAX (minimum, cell_minimum);
+         natural = MAX (natural, cell_natural);
+
+         /* increment sizes[] index for visible cells */
+         i++;
+        }
+    }
+
+  g_array_free (array, TRUE);
+
+  if (minimum_size)
+    *minimum_size = minimum;
+  if (natural_size)
+    *natural_size = natural;
+}