]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkcombobox.c
Various updates to follow new gtk_extended_layout_get_desired_size added argument.
[~andy/gtk] / gtk / gtkcombobox.c
index 555418a19febfadacc8fce2fef9e5d21012f3db4..5a5f3b94a02820c6a4efdc50aed6f9e82e1516a0 100644 (file)
@@ -38,6 +38,7 @@
 #include "gtktreeselection.h"
 #include "gtkvseparator.h"
 #include "gtkwindow.h"
+#include "gtkextendedlayout.h"
 #include "gtkprivate.h"
 
 #include <gdk/gdkkeysyms.h>
@@ -109,8 +110,9 @@ struct _GtkComboBoxPrivate
   guint scroll_timer;
   guint resize_idle_id;
 
-  gint width;
-  gint height;
+  GtkRequisition minimum_size;
+  GtkRequisition natural_size;
+
   GSList *cells;
 
   guint popup_in_progress : 1;
@@ -204,7 +206,8 @@ enum {
   PROP_HAS_FRAME,
   PROP_FOCUS_ON_CLICK,
   PROP_POPUP_SHOWN,
-  PROP_BUTTON_SENSITIVITY
+  PROP_BUTTON_SENSITIVITY,
+  PROP_EDITING_CANCELED
 };
 
 static guint combo_box_signals[LAST_SIGNAL] = {0,};
@@ -276,8 +279,6 @@ static void     gtk_combo_box_remeasure            (GtkComboBox      *combo_box)
 
 static void     gtk_combo_box_unset_model          (GtkComboBox      *combo_box);
 
-static void     gtk_combo_box_size_request         (GtkWidget        *widget,
-                                                    GtkRequisition   *requisition);
 static void     gtk_combo_box_size_allocate        (GtkWidget        *widget,
                                                     GtkAllocation    *allocation);
 static void     gtk_combo_box_forall               (GtkContainer     *container,
@@ -379,6 +380,8 @@ static gboolean gtk_combo_box_menu_button_press    (GtkWidget        *widget,
                                                     gpointer          user_data);
 static void     gtk_combo_box_menu_item_activate   (GtkWidget        *item,
                                                     gpointer          user_data);
+
+static void     gtk_combo_box_update_sensitivity   (GtkComboBox      *combo_box);
 static void     gtk_combo_box_menu_row_inserted    (GtkTreeModel     *model,
                                                     GtkTreePath      *path,
                                                     GtkTreeIter      *iter,
@@ -460,8 +463,16 @@ static void     gtk_combo_box_buildable_custom_tag_end       (GtkBuildable  *bui
                                                              gpointer      *data);
 
 /* GtkCellEditable method implementations */
-static void gtk_combo_box_start_editing (GtkCellEditable *cell_editable,
-                                        GdkEvent        *event);
+static void     gtk_combo_box_start_editing                  (GtkCellEditable *cell_editable,
+                                                             GdkEvent        *event);
+
+static void     gtk_combo_box_extended_layout_init           (GtkExtendedLayoutIface *iface);
+static void     gtk_combo_box_get_desired_width              (GtkExtendedLayout      *layout,
+                                                             gint                   *minimum_size,
+                                                             gint                   *natural_size);
+static void     gtk_combo_box_get_desired_height             (GtkExtendedLayout      *layout,
+                                                             gint                   *minimum_size,
+                                                             gint                   *natural_size);
 
 
 G_DEFINE_TYPE_WITH_CODE (GtkComboBox, gtk_combo_box, GTK_TYPE_BIN,
@@ -470,7 +481,9 @@ G_DEFINE_TYPE_WITH_CODE (GtkComboBox, gtk_combo_box, GTK_TYPE_BIN,
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_EDITABLE,
                                                gtk_combo_box_cell_editable_init)
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
-                                               gtk_combo_box_buildable_init))
+                                               gtk_combo_box_buildable_init)
+                        G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
+                                               gtk_combo_box_extended_layout_init))
 
 
 /* common */
@@ -492,7 +505,6 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass)
 
   widget_class = (GtkWidgetClass *)klass;
   widget_class->size_allocate = gtk_combo_box_size_allocate;
-  widget_class->size_request = gtk_combo_box_size_request;
   widget_class->expose_event = gtk_combo_box_expose_event;
   widget_class->scroll_event = gtk_combo_box_scroll_event;
   widget_class->mnemonic_activate = gtk_combo_box_mnemonic_activate;
@@ -647,6 +659,10 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass)
                                GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_END);
 
   /* properties */
+  g_object_class_override_property (object_class,
+                                    PROP_EDITING_CANCELED,
+                                    "editing-canceled");
+
   /**
    * GtkComboBox:model:
    *
@@ -925,8 +941,9 @@ gtk_combo_box_init (GtkComboBox *combo_box)
   GTK_BIN (combo_box)->child = priv->cell_view;
   gtk_widget_show (priv->cell_view);
 
-  priv->width = 0;
-  priv->height = 0;
+  memset (&priv->minimum_size, 0x0, sizeof (GtkRequisition));
+  memset (&priv->natural_size, 0x0, sizeof (GtkRequisition));
+
   priv->wrap_width = 0;
 
   priv->active = -1;
@@ -958,58 +975,62 @@ gtk_combo_box_set_property (GObject      *object,
 
   switch (prop_id)
     {
-      case PROP_MODEL:
-        gtk_combo_box_set_model (combo_box, g_value_get_object (value));
-        break;
+    case PROP_MODEL:
+      gtk_combo_box_set_model (combo_box, g_value_get_object (value));
+      break;
 
-      case PROP_WRAP_WIDTH:
-        gtk_combo_box_set_wrap_width (combo_box, g_value_get_int (value));
-        break;
+    case PROP_WRAP_WIDTH:
+      gtk_combo_box_set_wrap_width (combo_box, g_value_get_int (value));
+      break;
 
-      case PROP_ROW_SPAN_COLUMN:
-        gtk_combo_box_set_row_span_column (combo_box, g_value_get_int (value));
-        break;
+    case PROP_ROW_SPAN_COLUMN:
+      gtk_combo_box_set_row_span_column (combo_box, g_value_get_int (value));
+      break;
 
-      case PROP_COLUMN_SPAN_COLUMN:
-        gtk_combo_box_set_column_span_column (combo_box, g_value_get_int (value));
-        break;
+    case PROP_COLUMN_SPAN_COLUMN:
+      gtk_combo_box_set_column_span_column (combo_box, g_value_get_int (value));
+      break;
 
-      case PROP_ACTIVE:
-        gtk_combo_box_set_active (combo_box, g_value_get_int (value));
-        break;
+    case PROP_ACTIVE:
+      gtk_combo_box_set_active (combo_box, g_value_get_int (value));
+      break;
 
-      case PROP_ADD_TEAROFFS:
-        gtk_combo_box_set_add_tearoffs (combo_box, g_value_get_boolean (value));
-        break;
+    case PROP_ADD_TEAROFFS:
+      gtk_combo_box_set_add_tearoffs (combo_box, g_value_get_boolean (value));
+      break;
 
-      case PROP_HAS_FRAME:
-        combo_box->priv->has_frame = g_value_get_boolean (value);
-        break;
+    case PROP_HAS_FRAME:
+      combo_box->priv->has_frame = g_value_get_boolean (value);
+      break;
 
-      case PROP_FOCUS_ON_CLICK:
-       gtk_combo_box_set_focus_on_click (combo_box, 
-                                         g_value_get_boolean (value));
-        break;
+    case PROP_FOCUS_ON_CLICK:
+      gtk_combo_box_set_focus_on_click (combo_box,
+                                        g_value_get_boolean (value));
+      break;
 
-      case PROP_TEAROFF_TITLE:
-       gtk_combo_box_set_title (combo_box, g_value_get_string (value));
-        break;
+    case PROP_TEAROFF_TITLE:
+      gtk_combo_box_set_title (combo_box, g_value_get_string (value));
+      break;
 
-      case PROP_POPUP_SHOWN:
-        if (g_value_get_boolean (value))
-          gtk_combo_box_popup (combo_box);
-        else
-          gtk_combo_box_popdown (combo_box);
-        break;
+    case PROP_POPUP_SHOWN:
+      if (g_value_get_boolean (value))
+        gtk_combo_box_popup (combo_box);
+      else
+        gtk_combo_box_popdown (combo_box);
+      break;
 
-      case PROP_BUTTON_SENSITIVITY:
-        gtk_combo_box_set_button_sensitivity (combo_box,
-                                              g_value_get_enum (value));
-        break;
+    case PROP_BUTTON_SENSITIVITY:
+      gtk_combo_box_set_button_sensitivity (combo_box,
+                                            g_value_get_enum (value));
+      break;
 
-      default:
-        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-        break;
+    case PROP_EDITING_CANCELED:
+      combo_box->priv->editing_canceled = g_value_get_boolean (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
     }
 }
 
@@ -1020,6 +1041,7 @@ gtk_combo_box_get_property (GObject    *object,
                             GParamSpec *pspec)
 {
   GtkComboBox *combo_box = GTK_COMBO_BOX (object);
+  GtkComboBoxPrivate *priv = GTK_COMBO_BOX_GET_PRIVATE (combo_box);
 
   switch (prop_id)
     {
@@ -1067,6 +1089,10 @@ gtk_combo_box_get_property (GObject    *object,
         g_value_set_enum (value, combo_box->priv->button_sensitivity);
         break;
 
+      case PROP_EDITING_CANCELED:
+        g_value_set_boolean (value, priv->editing_canceled);
+        break;
+
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
         break;
@@ -1080,11 +1106,11 @@ gtk_combo_box_state_changed (GtkWidget    *widget,
   GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
   GtkComboBoxPrivate *priv = combo_box->priv;
 
-  if (GTK_WIDGET_REALIZED (widget))
+  if (gtk_widget_get_realized (widget))
     {
       if (priv->tree_view && priv->cell_view)
        gtk_cell_view_set_background_color (GTK_CELL_VIEW (priv->cell_view), 
-                                           &widget->style->base[GTK_WIDGET_STATE (widget)]);
+                                           &widget->style->base[gtk_widget_get_state (widget)]);
     }
 
   gtk_widget_queue_draw (widget);
@@ -1098,16 +1124,16 @@ gtk_combo_box_button_state_changed (GtkWidget    *widget,
   GtkComboBox *combo_box = GTK_COMBO_BOX (data);
   GtkComboBoxPrivate *priv = combo_box->priv;
 
-  if (GTK_WIDGET_REALIZED (widget))
+  if (gtk_widget_get_realized (widget))
     {
       if (!priv->tree_view && priv->cell_view)
        {
-         if ((GTK_WIDGET_STATE (widget) == GTK_STATE_INSENSITIVE) !=
-             (GTK_WIDGET_STATE (priv->cell_view) == GTK_STATE_INSENSITIVE))
-           gtk_widget_set_sensitive (priv->cell_view, GTK_WIDGET_SENSITIVE (widget));
+         if ((gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE) !=
+             (gtk_widget_get_state (priv->cell_view) == GTK_STATE_INSENSITIVE))
+           gtk_widget_set_sensitive (priv->cell_view, gtk_widget_get_sensitive (widget));
          
          gtk_widget_set_state (priv->cell_view, 
-                               GTK_WIDGET_STATE (widget));
+                               gtk_widget_get_state (widget));
        }
     }
 
@@ -1167,7 +1193,7 @@ gtk_combo_box_style_set (GtkWidget *widget,
 
   if (priv->tree_view && priv->cell_view)
     gtk_cell_view_set_background_color (GTK_CELL_VIEW (priv->cell_view), 
-                                       &widget->style->base[GTK_WIDGET_STATE (widget)]);
+                                       &widget->style->base[gtk_widget_get_state (widget)]);
 
   if (GTK_IS_ENTRY (GTK_BIN (combo_box)->child))
     g_object_set (GTK_BIN (combo_box)->child, "shadow-type",
@@ -1470,15 +1496,17 @@ gtk_combo_box_menu_position_below (GtkMenu  *menu,
   
   /* FIXME: is using the size request here broken? */
   child = GTK_BIN (combo_box)->child;
-   
-  gdk_window_get_origin (child->window, &sx, &sy);
-   
-  if (GTK_WIDGET_NO_WINDOW (child))
+
+  sx = sy = 0;
+
+  if (!gtk_widget_get_has_window (child))
     {
       sx += child->allocation.x;
       sy += child->allocation.y;
     }
 
+  gdk_window_get_root_coords (child->window, sx, sy, &sx, &sy);
+
   if (GTK_SHADOW_NONE != combo_box->priv->shadow_type)
     sx -= GTK_WIDGET (combo_box)->style->xthickness;
 
@@ -1537,10 +1565,9 @@ gtk_combo_box_menu_position_over (GtkMenu  *menu,
   menu_width = requisition.width;
 
   active = gtk_menu_get_active (GTK_MENU (combo_box->priv->popup_widget));
-  gdk_window_get_origin (widget->window, &menu_xpos, &menu_ypos);
 
-  menu_xpos += widget->allocation.x;
-  menu_ypos += widget->allocation.y + widget->allocation.height / 2 - 2;
+  menu_xpos = widget->allocation.x;
+  menu_ypos = widget->allocation.y + widget->allocation.height / 2 - 2;
 
   if (active != NULL)
     {
@@ -1556,7 +1583,7 @@ gtk_combo_box_menu_position_over (GtkMenu  *menu,
       if (active == child)
        break;
 
-      if (GTK_WIDGET_VISIBLE (child))
+      if (gtk_widget_get_visible (child))
        {
          gtk_widget_get_child_requisition (child, &requisition);
          menu_ypos -= requisition.height;
@@ -1568,6 +1595,9 @@ gtk_combo_box_menu_position_over (GtkMenu  *menu,
   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
     menu_xpos = menu_xpos + widget->allocation.width - menu_width;
 
+  gdk_window_get_root_coords (widget->window, menu_xpos, menu_ypos,
+                             &menu_xpos, &menu_ypos);
+
   /* Clamp the position on screen */
   screen_width = gdk_screen_get_width (gtk_widget_get_screen (widget));
   
@@ -1607,7 +1637,7 @@ gtk_combo_box_menu_position (GtkMenu  *menu,
       gtk_combo_box_menu_position_over (menu, x, y, push_in, user_data);
     }
 
-  if (!GTK_WIDGET_VISIBLE (GTK_MENU (priv->popup_widget)->toplevel))
+  if (!gtk_widget_get_visible (GTK_MENU (priv->popup_widget)->toplevel))
     gtk_window_set_type_hint (GTK_WINDOW (GTK_MENU (priv->popup_widget)->toplevel),
                               GDK_WINDOW_TYPE_HINT_COMBO);
 }
@@ -1630,14 +1660,16 @@ gtk_combo_box_list_position (GtkComboBox *combo_box,
      see bug #340204 */
   GtkWidget *sample = GTK_WIDGET (combo_box);
 
-  gdk_window_get_origin (sample->window, x, y);
+  *x = *y = 0;
 
-  if (GTK_WIDGET_NO_WINDOW (sample))
+  if (!gtk_widget_get_has_window (sample))
     {
       *x += sample->allocation.x;
       *y += sample->allocation.y;
     }
   
+  gdk_window_get_root_coords (sample->window, *x, *y, x, y);
+
   *width = sample->allocation.width;
 
   hpolicy = vpolicy = GTK_POLICY_NEVER;
@@ -1695,7 +1727,7 @@ cell_view_is_sensitive (GtkCellView *cell_view)
   GList *cells, *list;
   gboolean sensitive;
   
-  cells = gtk_cell_view_get_cell_renderers (cell_view);
+  cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (cell_view));
 
   sensitive = FALSE;
   for (list = cells; list; list = list->next)
@@ -1732,7 +1764,7 @@ tree_column_row_is_sensitive (GtkComboBox *combo_box,
                                           priv->model,
                                           iter, FALSE, FALSE);
 
-  cells = gtk_tree_view_column_get_cell_renderers (priv->column);
+  cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (priv->column));
 
   sensitive = FALSE;
   for (list = cells; list; list = list->next)
@@ -1889,10 +1921,10 @@ gtk_combo_box_real_popup (GtkComboBox *combo_box)
   GtkTreePath *path = NULL, *ppath;
   GtkWidget *toplevel;
 
-  if (!GTK_WIDGET_REALIZED (combo_box))
+  if (!gtk_widget_get_realized (GTK_WIDGET (combo_box)))
     return;
 
-  if (GTK_WIDGET_MAPPED (priv->popup_widget))
+  if (gtk_widget_get_mapped (priv->popup_widget))
     return;
 
   if (GTK_IS_MENU (priv->popup_widget))
@@ -1940,7 +1972,7 @@ gtk_combo_box_real_popup (GtkComboBox *combo_box)
   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button),
                                 TRUE);
 
-  if (!GTK_WIDGET_HAS_FOCUS (priv->tree_view))
+  if (!gtk_widget_has_focus (priv->tree_view))
     gtk_widget_grab_focus (priv->tree_view);
 
   if (!popup_grab_on_window (priv->popup_window->window,
@@ -1989,7 +2021,7 @@ gtk_combo_box_popdown (GtkComboBox *combo_box)
       return;
     }
 
-  if (!GTK_WIDGET_REALIZED (GTK_WIDGET (combo_box)))
+  if (!gtk_widget_get_realized (GTK_WIDGET (combo_box)))
     return;
 
   gtk_grab_remove (priv->popup_window);
@@ -2025,164 +2057,6 @@ gtk_combo_box_calc_requested_width (GtkComboBox *combo_box,
   return req.width + padding;
 }
 
-static void
-gtk_combo_box_remeasure (GtkComboBox *combo_box)
-{
-  GtkComboBoxPrivate *priv = combo_box->priv;
-  GtkTreeIter iter;
-  GtkTreePath *path;
-
-  if (!priv->model ||
-      !gtk_tree_model_get_iter_first (priv->model, &iter))
-    return;
-
-  priv->width = 0;
-  priv->height = 0;
-
-  path = gtk_tree_path_new_from_indices (0, -1);
-
-  do
-    {
-      GtkRequisition req;
-
-      if (priv->cell_view)
-       gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (priv->cell_view), 
-                                       path, &req);
-      else
-        {
-          req.width = 0;
-          req.height = 0;
-        }
-
-      priv->width = MAX (priv->width, req.width);
-      priv->height = MAX (priv->height, req.height);
-
-      gtk_tree_path_next (path);
-    }
-  while (gtk_tree_model_iter_next (priv->model, &iter));
-
-  gtk_tree_path_free (path);
-}
-
-static void
-gtk_combo_box_size_request (GtkWidget      *widget,
-                            GtkRequisition *requisition)
-{
-  gint width, height;
-  gint focus_width, focus_pad;
-  gint font_size;
-  gint arrow_size;
-  GtkRequisition bin_req;
-  PangoContext *context;
-  PangoFontMetrics *metrics;
-  PangoFontDescription *font_desc;
-
-  GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
-  GtkComboBoxPrivate *priv = combo_box->priv;
-  /* common */
-  gtk_widget_size_request (GTK_BIN (widget)->child, &bin_req);
-  gtk_combo_box_remeasure (combo_box);
-  bin_req.width = MAX (bin_req.width, priv->width);
-  bin_req.height = MAX (bin_req.height, priv->height);
-
-  gtk_widget_style_get (GTK_WIDGET (widget),
-                       "focus-line-width", &focus_width,
-                       "focus-padding", &focus_pad,
-                       "arrow-size", &arrow_size,
-                       NULL);
-
-  font_desc = GTK_BIN (widget)->child->style->font_desc;
-  context = gtk_widget_get_pango_context (widget);
-  metrics = pango_context_get_metrics (context, font_desc,
-                                      pango_context_get_language (context));
-  font_size = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
-                           pango_font_metrics_get_descent (metrics));
-  pango_font_metrics_unref (metrics);
-
-  arrow_size = MAX (arrow_size, font_size);
-
-  gtk_widget_set_size_request (priv->arrow, arrow_size, arrow_size);
-
-  if (!priv->tree_view)
-    {
-      /* menu mode */
-
-      if (priv->cell_view)
-        {
-          GtkRequisition button_req, sep_req, arrow_req;
-          gint border_width, xthickness, ythickness;
-
-          gtk_widget_size_request (priv->button, &button_req);
-         border_width = GTK_CONTAINER (combo_box)->border_width;
-          xthickness = priv->button->style->xthickness;
-          ythickness = priv->button->style->ythickness;
-
-          bin_req.width = MAX (bin_req.width, priv->width);
-          bin_req.height = MAX (bin_req.height, priv->height);
-
-          gtk_widget_size_request (priv->separator, &sep_req);
-          gtk_widget_size_request (priv->arrow, &arrow_req);
-
-          height = MAX (sep_req.height, arrow_req.height);
-          height = MAX (height, bin_req.height);
-
-          width = bin_req.width + sep_req.width + arrow_req.width;
-
-          height += 2*(border_width + ythickness + focus_width + focus_pad);
-          width  += 2*(border_width + xthickness + focus_width + focus_pad);
-
-          requisition->width = width;
-          requisition->height = height;
-        }
-      else
-        {
-          GtkRequisition but_req;
-
-          gtk_widget_size_request (priv->button, &but_req);
-
-          requisition->width = bin_req.width + but_req.width;
-          requisition->height = MAX (bin_req.height, but_req.height);
-        }
-    }
-  else
-    {
-      /* list mode */
-      GtkRequisition button_req, frame_req;
-
-      /* sample + frame */
-      *requisition = bin_req;
-
-      requisition->width += 2 * focus_width;
-      
-      if (priv->cell_view_frame)
-        {
-         gtk_widget_size_request (priv->cell_view_frame, &frame_req);
-         if (priv->has_frame)
-           {
-             requisition->width += 2 *
-               (GTK_CONTAINER (priv->cell_view_frame)->border_width +
-                GTK_WIDGET (priv->cell_view_frame)->style->xthickness);
-             requisition->height += 2 *
-               (GTK_CONTAINER (priv->cell_view_frame)->border_width +
-                GTK_WIDGET (priv->cell_view_frame)->style->ythickness);
-           }
-        }
-
-      /* the button */
-      gtk_widget_size_request (priv->button, &button_req);
-
-      requisition->height = MAX (requisition->height, button_req.height);
-      requisition->width += button_req.width;
-    }
-
-  if (GTK_SHADOW_NONE != priv->shadow_type)
-    {
-      requisition->height += 2 * widget->style->ythickness;
-      requisition->width += 2 * widget->style->xthickness;
-    }
-}
-
 #define GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON                                     \
   gtk_widget_size_request (combo_box->priv->button, &req);                     \
                                                                                \
@@ -2296,7 +2170,7 @@ gtk_combo_box_size_allocate (GtkWidget     *widget,
               child.width -= child.x;
             }
 
-          if (GTK_WIDGET_VISIBLE (priv->popup_widget))
+          if (gtk_widget_get_visible (priv->popup_widget))
             {
               gint width;
               GtkRequisition requisition;
@@ -2383,7 +2257,7 @@ gtk_combo_box_size_allocate (GtkWidget     *widget,
           child.height -= delta_y * 2;
         }
 
-      if (GTK_WIDGET_VISIBLE (priv->popup_window))
+      if (gtk_widget_get_visible (priv->popup_window))
         {
           gint x, y, width, height;
           gtk_combo_box_list_position (combo_box, &x, &y, &width, &height);
@@ -2490,7 +2364,7 @@ gtk_combo_box_expose_event (GtkWidget      *widget,
   GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
   GtkComboBoxPrivate *priv = combo_box->priv;
 
-  if (GTK_WIDGET_DRAWABLE (widget) &&
+  if (gtk_widget_is_drawable (widget) &&
       GTK_SHADOW_NONE != priv->shadow_type)
     {
       gtk_paint_shadow (widget->style, widget->window,
@@ -2840,6 +2714,7 @@ gtk_combo_box_menu_setup (GtkComboBox *combo_box,
   /* create our funky menu */
   menu = gtk_menu_new ();
   gtk_widget_set_name (menu, "gtk-combobox-popup-menu");
+  gtk_menu_set_reserve_toggle_size (GTK_MENU (menu), FALSE);
   
   g_signal_connect (menu, "key-press-event",
                    G_CALLBACK (gtk_combo_box_menu_key_press), combo_box);
@@ -2855,6 +2730,7 @@ gtk_combo_box_menu_setup (GtkComboBox *combo_box,
   gtk_combo_box_sync_cells (combo_box, GTK_CELL_LAYOUT (priv->column));
 
   gtk_combo_box_update_title (combo_box);
+  gtk_combo_box_update_sensitivity (combo_box);
 }
 
 static void
@@ -2952,6 +2828,7 @@ gtk_combo_box_menu_fill_level (GtkComboBox *combo_box,
          if (gtk_tree_model_iter_has_child (model, &iter))
            {
              submenu = gtk_menu_new ();
+              gtk_menu_set_reserve_toggle_size (GTK_MENU (submenu), FALSE);
              gtk_widget_show (submenu);
              gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
              
@@ -3143,7 +3020,7 @@ gtk_combo_box_menu_button_press (GtkWidget      *widget,
       event->type == GDK_BUTTON_PRESS && event->button == 1)
     {
       if (priv->focus_on_click && 
-         !GTK_WIDGET_HAS_FOCUS (priv->button))
+         !gtk_widget_has_focus (priv->button))
        gtk_widget_grab_focus (priv->button);
 
       gtk_combo_box_menu_popup (combo_box, event->button, event->time);
@@ -3177,7 +3054,9 @@ gtk_combo_box_menu_item_activate (GtkWidget *item,
 
   gtk_tree_path_free (path);
 
-  combo_box->priv->editing_canceled = FALSE;
+  g_object_set (combo_box,
+                "editing-canceled", FALSE,
+                NULL);
 }
 
 static void
@@ -3207,6 +3086,11 @@ gtk_combo_box_update_sensitivity (GtkComboBox *combo_box)
     }
 
   gtk_widget_set_sensitive (combo_box->priv->button, sensitive);
+
+  /* In list-mode, we also need to update sensitivity of the event box */
+  if (GTK_IS_TREE_VIEW (combo_box->priv->tree_view)
+      && combo_box->priv->cell_view)
+    gtk_widget_set_sensitive (combo_box->priv->box, sensitive);
 }
 
 static void
@@ -3296,7 +3180,7 @@ list_popup_resize_idle (gpointer user_data)
   GtkComboBoxPrivate *priv = combo_box->priv;
   gint x, y, width, height;
 
-  if (priv->tree_view && GTK_WIDGET_MAPPED (priv->popup_window))
+  if (priv->tree_view && gtk_widget_get_mapped (priv->popup_window))
     {
       gtk_combo_box_list_position (combo_box, &x, &y, &width, &height);
   
@@ -3462,6 +3346,7 @@ gtk_combo_box_menu_row_inserted (GtkTreeModel *model,
       if (!menu)
        {
          menu = gtk_menu_new ();
+          gtk_menu_set_reserve_toggle_size (GTK_MENU (menu), FALSE);
          gtk_widget_show (menu);
          gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent), menu);
          
@@ -3622,14 +3507,14 @@ gtk_combo_box_menu_row_changed (GtkTreeModel *model,
 
   width = gtk_combo_box_calc_requested_width (combo_box, path);
 
-  if (width > priv->width)
+  if (width > priv->minimum_size.width)
     {
       if (priv->cell_view)
        {
          gtk_widget_set_size_request (priv->cell_view, width, -1);
          gtk_widget_queue_resize (priv->cell_view);
        }
-      priv->width = width;
+      priv->minimum_size.width = width;
     }
 }
 
@@ -3642,6 +3527,8 @@ gtk_combo_box_list_setup (GtkComboBox *combo_box)
 {
   GtkComboBoxPrivate *priv = combo_box->priv;
   GtkTreeSelection *sel;
+  GtkStyle *style;
+  GtkWidget *widget = GTK_WIDGET (combo_box);
 
   priv->button = gtk_toggle_button_new ();
   gtk_widget_set_parent (priv->button,
@@ -3658,8 +3545,9 @@ gtk_combo_box_list_setup (GtkComboBox *combo_box)
 
   if (priv->cell_view)
     {
-      gtk_cell_view_set_background_color (GTK_CELL_VIEW (priv->cell_view), 
-                                         &GTK_WIDGET (combo_box)->style->base[GTK_WIDGET_STATE (combo_box)]);
+      style = gtk_widget_get_style (widget);
+      gtk_cell_view_set_background_color (GTK_CELL_VIEW (priv->cell_view),
+                                          &style->base[gtk_widget_get_state (widget)]);
 
       priv->box = gtk_event_box_new ();
       gtk_event_box_set_visible_window (GTK_EVENT_BOX (priv->box), 
@@ -3746,6 +3634,8 @@ gtk_combo_box_list_setup (GtkComboBox *combo_box)
                     combo_box);
 
   gtk_widget_show (priv->tree_view);
+
+  gtk_combo_box_update_sensitivity (combo_box);
 }
 
 static void
@@ -3855,7 +3745,7 @@ gtk_combo_box_list_button_pressed (GtkWidget      *widget,
     return FALSE;
 
   if (priv->focus_on_click && 
-      !GTK_WIDGET_HAS_FOCUS (priv->button))
+      !gtk_widget_has_focus (priv->button))
     gtk_widget_grab_focus (priv->button);
 
   gtk_combo_box_popup (combo_box);
@@ -4097,7 +3987,7 @@ gtk_combo_box_list_select_func (GtkTreeSelection *selection,
       gtk_tree_view_column_cell_set_cell_data (column, model, &iter,
                                               FALSE, FALSE);
 
-      cell = cells = gtk_tree_view_column_get_cell_renderers (column);
+      cell = cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
       while (cell)
         {
          g_object_get (cell->data,
@@ -4130,14 +4020,14 @@ gtk_combo_box_list_row_changed (GtkTreeModel *model,
 
   width = gtk_combo_box_calc_requested_width (combo_box, path);
 
-  if (width > priv->width)
+  if (width > priv->minimum_size.width)
     {
       if (priv->cell_view) 
        {
          gtk_widget_set_size_request (priv->cell_view, width, -1);
          gtk_widget_queue_resize (priv->cell_view);
        }
-      priv->width = width;
+      priv->minimum_size.width = width;
     }
 }
 
@@ -4189,8 +4079,11 @@ gtk_combo_box_cell_layout_pack_start (GtkCellLayout   *layout,
   priv->cells = g_slist_append (priv->cells, info);
 
   if (priv->cell_view)
-    gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (priv->cell_view),
-                                cell, expand);
+    {
+      gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (priv->cell_view),
+                                 cell, expand);
+
+    }
 
   if (priv->column)
     gtk_tree_view_column_pack_start (priv->column, cell, expand);
@@ -4966,10 +4859,12 @@ gtk_combo_box_get_active_iter (GtkComboBox     *combo_box,
 /**
  * gtk_combo_box_set_active_iter:
  * @combo_box: A #GtkComboBox
- * @iter: The #GtkTreeIter
+ * @iter: (allow-none): The #GtkTreeIter, or %NULL
  * 
- * Sets the current active item to be the one referenced by @iter. 
- * @iter must correspond to a path of depth one.
+ * Sets the current active item to be the one referenced by @iter, or
+ * unsets the active item if @iter is %NULL.
+ *
+ * @iter must correspond to a path of depth one, or be %NULL.
  * 
  * Since: 2.4
  */
@@ -4977,11 +4872,13 @@ void
 gtk_combo_box_set_active_iter (GtkComboBox     *combo_box,
                                GtkTreeIter     *iter)
 {
-  GtkTreePath *path;
+  GtkTreePath *path = NULL;
 
   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
 
-  path = gtk_tree_model_get_path (gtk_combo_box_get_model (combo_box), iter);
+  if (iter)
+    path = gtk_tree_model_get_path (gtk_combo_box_get_model (combo_box), iter);
+
   gtk_combo_box_set_active_internal (combo_box, path);
   gtk_tree_path_free (path);
 }
@@ -4989,9 +4886,9 @@ gtk_combo_box_set_active_iter (GtkComboBox     *combo_box,
 /**
  * gtk_combo_box_set_model:
  * @combo_box: A #GtkComboBox
- * @model: A #GtkTreeModel
+ * @model: (allow-none): A #GtkTreeModel
  *
- * Sets the model used by @combo_box to be @model. Will unset a previously set 
+ * Sets the model used by @combo_box to be @model. Will unset a previously set
  * model (if applicable). If model is %NULL, then it will unset the model.
  *
  * Note that this function does not clear the cell renderers, you have to 
@@ -5073,7 +4970,7 @@ out:
  *
  * Returns the #GtkTreeModel which is acting as data source for @combo_box.
  *
- * Return value: A #GtkTreeModel which was passed during construction.
+ * Return value: (transfer none): A #GtkTreeModel which was passed during construction.
  *
  * Since: 2.4
  */
@@ -5098,7 +4995,7 @@ gtk_combo_box_get_model (GtkComboBox *combo_box)
  * gtk_combo_box_insert_text(), gtk_combo_box_prepend_text() and
  * gtk_combo_box_remove_text().
  *
- * Return value: A new text combo box.
+ * Return value: (transfer none): A new text combo box.
  *
  * Since: 2.4
  */
@@ -5481,8 +5378,9 @@ gtk_cell_editable_key_press (GtkWidget   *widget,
 
   if (event->keyval == GDK_Escape)
     {
-      combo_box->priv->editing_canceled = TRUE;
-
+      g_object_set (combo_box,
+                    "editing-canceled", TRUE,
+                    NULL);
       gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (combo_box));
       gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (combo_box));
       
@@ -5537,7 +5435,9 @@ popup_idle (gpointer data)
                             combo_box, 0);
   
   /* we unset this if a menu item is activated */
-  combo_box->priv->editing_canceled = TRUE;
+  g_object_set (combo_box,
+                "editing-canceled", TRUE,
+                NULL);
   gtk_combo_box_popup (combo_box);
 
   combo_box->priv->popup_idle_id = 0;
@@ -5570,7 +5470,7 @@ gtk_combo_box_start_editing (GtkCellEditable *cell_editable,
                               cell_editable, 0);  
 
       gtk_widget_grab_focus (GTK_WIDGET (GTK_BIN (combo_box)->child));
-      GTK_WIDGET_UNSET_FLAGS (combo_box->priv->button, GTK_CAN_FOCUS);
+      gtk_widget_set_can_focus (combo_box->priv->button, FALSE);
     }
 
   /* we do the immediate popup only for the optionmenu-like 
@@ -5698,14 +5598,6 @@ gtk_combo_box_set_title (GtkComboBox *combo_box,
     }
 }
 
-gboolean
-_gtk_combo_box_editing_canceled (GtkComboBox *combo_box)
-{
-  g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), TRUE);
-
-  return combo_box->priv->editing_canceled;
-}
-
 /**
  * gtk_combo_box_get_popup_accessible:
  * @combo_box: a #GtkComboBox
@@ -5757,8 +5649,8 @@ gtk_combo_box_get_row_separator_func (GtkComboBox *combo_box)
  * gtk_combo_box_set_row_separator_func:
  * @combo_box: a #GtkComboBox
  * @func: a #GtkTreeViewRowSeparatorFunc
- * @data: user data to pass to @func, or %NULL
- * @destroy: destroy notifier for @data, or %NULL
+ * @data: (allow-none): user data to pass to @func, or %NULL
+ * @destroy: (allow-none): destroy notifier for @data, or %NULL
  * 
  * Sets the row separator function, which is used to determine
  * whether a row should be drawn as a separator. If the row separator
@@ -5925,5 +5817,241 @@ gtk_combo_box_buildable_custom_tag_end (GtkBuildable *buildable,
                                            data);
 }
 
+
+static void
+gtk_combo_box_extended_layout_init (GtkExtendedLayoutIface *iface)
+{
+  iface->get_desired_width = gtk_combo_box_get_desired_width;
+  iface->get_desired_height = gtk_combo_box_get_desired_height;
+}
+
+static void
+gtk_combo_box_remeasure (GtkComboBox *combo_box)
+{
+  GtkComboBoxPrivate *priv = combo_box->priv;
+  GtkTreeIter iter;
+  GtkTreePath *path;
+
+  if (!priv->model ||
+      !gtk_tree_model_get_iter_first (priv->model, &iter))
+    return;
+
+  memset (&priv->minimum_size, 0x0, sizeof (GtkRequisition));
+  memset (&priv->natural_size, 0x0, sizeof (GtkRequisition));
+
+  path = gtk_tree_path_new_from_indices (0, -1);
+
+  do
+    {
+      GtkRequisition req, nat_req;
+
+      if (priv->cell_view)
+       {
+         /* XXX FIXME: Currently still not doing height-for-width in cell renderers here */
+         gtk_cell_view_get_desired_width_of_row (GTK_CELL_VIEW (priv->cell_view), 
+                                                 path, &req.width, &nat_req.width);
+         gtk_cell_view_get_desired_height_of_row (GTK_CELL_VIEW (priv->cell_view), 
+                                                  path, &req.height, &nat_req.height);
+       }
+      else
+        {
+         memset (&req, 0x0, sizeof (GtkRequisition));
+         memset (&nat_req, 0x0, sizeof (GtkRequisition));
+        }
+
+      priv->minimum_size.width  = MAX (priv->minimum_size.width,  req.width);
+      priv->minimum_size.height = MAX (priv->minimum_size.height, req.height);
+
+      priv->natural_size.width  = MAX (priv->natural_size.width,  nat_req.width);
+      priv->natural_size.height = MAX (priv->natural_size.height, nat_req.height);
+
+      gtk_tree_path_next (path);
+    }
+  while (gtk_tree_model_iter_next (priv->model, &iter));
+
+  gtk_tree_path_free (path);
+}
+
+
+/* XXX TODO: Split this up into 2 orientations so as
+ * to properly support height-for-width/width-for-height here
+ *
+ */
+static void
+gtk_combo_box_get_desired_size (GtkExtendedLayout *layout,
+                               GtkRequisition    *minimum_size,
+                               GtkRequisition    *natural_size)
+{
+  GtkComboBox           *combo_box = GTK_COMBO_BOX (layout);
+  GtkComboBoxPrivate    *priv = combo_box->priv;
+  gint                   focus_width, focus_pad;
+  gint                   font_size, arrow_size;
+  GtkRequisition         bin_req, bin_nat_req;
+  PangoContext          *context;
+  PangoFontMetrics      *metrics;
+  PangoFontDescription  *font_desc;
+  GtkWidget             *child;
+
+  child = gtk_bin_get_child (GTK_BIN (layout));
+  /* common */
+  gtk_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (child), FALSE, &bin_req, &bin_nat_req);
+  gtk_combo_box_remeasure (combo_box);
+
+  bin_req.width      = MAX (bin_req.width,      priv->minimum_size.width);
+  bin_req.height     = MAX (bin_req.height,     priv->minimum_size.height);
+  bin_nat_req.width  = MAX (bin_nat_req.width,  priv->natural_size.width);
+  bin_nat_req.height = MAX (bin_nat_req.height, priv->natural_size.height);
+
+  gtk_widget_style_get (GTK_WIDGET (layout),
+                       "focus-line-width", &focus_width,
+                       "focus-padding", &focus_pad,
+                       "arrow-size", &arrow_size,
+                       NULL);
+
+  font_desc = child->style->font_desc;
+  context = gtk_widget_get_pango_context (GTK_WIDGET (layout));
+  metrics = pango_context_get_metrics (context, font_desc,
+                                      pango_context_get_language (context));
+  font_size = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
+                           pango_font_metrics_get_descent (metrics));
+  pango_font_metrics_unref (metrics);
+
+  arrow_size = MAX (arrow_size, font_size);
+
+  gtk_widget_set_size_request (priv->arrow, arrow_size, arrow_size);
+
+  if (!priv->tree_view)
+    {
+      /* menu mode */
+         
+      if (priv->cell_view)
+        {
+          GtkRequisition button_req, sep_req, arrow_req;
+          gint border_width, xthickness, ythickness, xpad, ypad;
+
+          gtk_widget_size_request (priv->button, &button_req);
+         border_width = GTK_CONTAINER (combo_box)->border_width;
+          xthickness = priv->button->style->xthickness;
+          ythickness = priv->button->style->ythickness;
+
+         xpad = 2*(border_width + xthickness + focus_width + focus_pad);
+         ypad = 2*(border_width + ythickness + focus_width + focus_pad);
+
+          gtk_widget_size_request (priv->separator, &sep_req);
+          gtk_widget_size_request (priv->arrow, &arrow_req);
+
+          minimum_size->width  = bin_req.width + sep_req.width + arrow_req.width;
+          minimum_size->height = MAX (sep_req.height, arrow_req.height);
+          minimum_size->height = MAX (minimum_size->height, bin_req.height);
+
+          natural_size->width  = bin_nat_req.width + sep_req.width + arrow_req.width;
+          natural_size->height = MAX (minimum_size->height, bin_nat_req.height);
+
+          minimum_size->width  += xpad;
+          minimum_size->height += ypad;
+          natural_size->width  += xpad;
+          natural_size->height += ypad;
+        }
+      else
+        {
+          GtkRequisition but_req, but_nat_req;
+
+          gtk_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (priv->button), 
+                                               FALSE, 
+                                               &but_req, &but_nat_req);
+
+          minimum_size->width  = bin_req.width + but_req.width;
+          minimum_size->height = MAX (bin_req.height, but_req.height);
+
+          natural_size->width  = bin_nat_req.width + but_nat_req.width;
+          natural_size->height = MAX (bin_nat_req.height, but_nat_req.height);
+        }
+    }
+  else
+    {
+      /* list mode */
+      GtkRequisition button_req, button_nat_req, frame_req;
+
+      /* sample + frame */
+      *minimum_size = bin_req;
+      *natural_size = bin_nat_req;
+
+      minimum_size->width += 2 * focus_width;
+      natural_size->width += 2 * focus_width;
+      
+      if (priv->cell_view_frame)
+        {
+         gtk_widget_size_request (priv->cell_view_frame, &frame_req);
+         if (priv->has_frame)
+           {
+             gint xpad = 2 * (GTK_CONTAINER (priv->cell_view_frame)->border_width +
+                              GTK_WIDGET (priv->cell_view_frame)->style->xthickness);
+             
+             gint ypad = 2 * (GTK_CONTAINER (priv->cell_view_frame)->border_width +
+                              GTK_WIDGET (priv->cell_view_frame)->style->ythickness);
+
+             minimum_size->width  += xpad;
+             minimum_size->height += ypad;
+             natural_size->width  += xpad;
+             natural_size->height += ypad;
+           }
+        }
+
+      /* the button */
+      gtk_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (priv->button), 
+                                           FALSE, 
+                                           &button_req, &button_nat_req);
+
+      minimum_size->width += button_req.width;
+      minimum_size->height = MAX (minimum_size->height, button_req.height);
+
+      natural_size->width += button_nat_req.width;
+      natural_size->height = MAX (natural_size->height, button_nat_req.height);
+    }
+
+  if (GTK_SHADOW_NONE != priv->shadow_type)
+    {
+      minimum_size->width  += 2 * GTK_WIDGET (layout)->style->xthickness;
+      minimum_size->height += 2 * GTK_WIDGET (layout)->style->ythickness;
+
+      natural_size->width  += 2 * GTK_WIDGET (layout)->style->xthickness;
+      natural_size->height += 2 * GTK_WIDGET (layout)->style->ythickness;
+    }
+}
+
+static void     
+gtk_combo_box_get_desired_width (GtkExtendedLayout      *layout,
+                                gint                   *minimum_size,
+                                gint                   *natural_size)
+{
+  GtkRequisition minimum, natural;
+
+  gtk_combo_box_get_desired_size (layout, &minimum, &natural);
+
+  if (minimum_size)
+    *minimum_size = minimum.width;
+
+  if (natural_size)
+    *natural_size = natural.width;
+}
+
+static void
+gtk_combo_box_get_desired_height (GtkExtendedLayout      *layout,
+                                 gint                   *minimum_size,
+                                 gint                   *natural_size)
+{ 
+  GtkRequisition minimum, natural;
+
+  gtk_combo_box_get_desired_size (layout, &minimum, &natural);
+
+  if (minimum_size)
+    *minimum_size = minimum.height;
+
+  if (natural_size)
+    *natural_size = natural.height;
+}
+
+
 #define __GTK_COMBO_BOX_C__
 #include "gtkaliasdef.c"