]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkcombobox.c
Clean up more includes
[~andy/gtk] / gtk / gtkcombobox.c
index c1ca3bc7d94dfef9f3f4127a5b799fe595812129..b123de876473f335019005791001d2c6701cd275 100644 (file)
@@ -38,7 +38,7 @@
 #include "gtktearoffmenuitem.h"
 #include "gtktogglebutton.h"
 #include "gtktreeselection.h"
-#include "gtkvseparator.h"
+#include "gtkseparator.h"
 #include "gtkwindow.h"
 #include "gtktypebuiltins.h"
 #include "gtkprivate.h"
@@ -104,7 +104,6 @@ struct _GtkComboBoxPrivate
   GtkTreeRowReference *active_row;
 
   GtkWidget *tree_view;
-  GtkTreeViewColumn *column;
 
   GtkWidget *cell_view;
   GtkWidget *cell_view_frame;
@@ -129,7 +128,8 @@ struct _GtkComboBoxPrivate
   guint resize_idle_id;
 
   /* For "has-entry" specific behavior we track
-   * an automated cell renderer and text column */
+   * an automated cell renderer and text column
+   */
   gint  text_column;
   GtkCellRenderer *text_renderer;
 
@@ -266,8 +266,8 @@ static void     gtk_combo_box_get_property         (GObject         *object,
                                                     GValue          *value,
                                                     GParamSpec      *spec);
 
-static void     gtk_combo_box_state_changed        (GtkWidget        *widget,
-                                                    GtkStateType      previous);
+static void     gtk_combo_box_state_flags_changed  (GtkWidget       *widget,
+                                                    GtkStateFlags    previous);
 static void     gtk_combo_box_grab_focus           (GtkWidget       *widget);
 static void     gtk_combo_box_style_updated        (GtkWidget       *widget);
 static void     gtk_combo_box_button_toggled       (GtkWidget       *widget,
@@ -406,7 +406,7 @@ static void     gtk_combo_box_menu_popup           (GtkComboBox      *combo_box,
                                                     guint32           activate_time);
 
 /* cell layout */
-GtkCellArea    *gtk_combo_box_cell_layout_get_area (GtkCellLayout    *cell_layout);
+static GtkCellArea *gtk_combo_box_cell_layout_get_area       (GtkCellLayout    *cell_layout);
 
 static gboolean gtk_combo_box_mnemonic_activate              (GtkWidget    *widget,
                                                               gboolean      group_cycling);
@@ -493,7 +493,7 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass)
   widget_class->mnemonic_activate = gtk_combo_box_mnemonic_activate;
   widget_class->grab_focus = gtk_combo_box_grab_focus;
   widget_class->style_updated = gtk_combo_box_style_updated;
-  widget_class->state_changed = gtk_combo_box_state_changed;
+  widget_class->state_flags_changed = gtk_combo_box_state_flags_changed;
   widget_class->get_preferred_width = gtk_combo_box_get_preferred_width;
   widget_class->get_preferred_height = gtk_combo_box_get_preferred_height;
   widget_class->get_preferred_height_for_width = gtk_combo_box_get_preferred_height_for_width;
@@ -933,6 +933,9 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass)
     *
     * The #GtkCellArea used to layout cell renderers for this combo box.
     *
+    * If no area is specified when creating the combo box with gtk_combo_box_new_with_area() 
+    * a horizontally oriented #GtkCellAreaBox will be used.
+    *
     * Since: 3.0
     */
    g_object_class_install_property (object_class,
@@ -969,6 +972,23 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass)
                                                              15,
                                                              GTK_PARAM_READABLE));
 
+  /**
+   * GtkComboBox:arrow-scaling:
+   *
+   * Sets the amount of space used up by the combobox arrow,
+   * proportional to the font size.
+   *
+   * Since: 3.2
+   */
+  gtk_widget_class_install_style_property (widget_class,
+                                           g_param_spec_float ("arrow-scaling",
+                                                               P_("Arrow Scaling"),
+                                                               P_("The amount of space used by the arrow"),
+                                                             0,
+                                                             2.0,
+                                                             1.0,
+                                                             GTK_PARAM_READABLE));
+
   /**
    * GtkComboBox:shadow-type:
    *
@@ -1049,6 +1069,7 @@ gtk_combo_box_set_property (GObject      *object,
                             GParamSpec   *pspec)
 {
   GtkComboBox *combo_box = GTK_COMBO_BOX (object);
+  GtkComboBoxPrivate *priv = combo_box->priv;
   GtkCellArea *area;
 
   switch (prop_id)
@@ -1078,16 +1099,15 @@ gtk_combo_box_set_property (GObject      *object,
       break;
 
     case PROP_HAS_FRAME:
-      combo_box->priv->has_frame = g_value_get_boolean (value);
+      priv->has_frame = g_value_get_boolean (value);
 
-      if (combo_box->priv->has_entry)
+      if (priv->has_entry)
         {
           GtkWidget *child;
 
           child = gtk_bin_get_child (GTK_BIN (combo_box));
 
-          gtk_entry_set_has_frame (GTK_ENTRY (child),
-                                   combo_box->priv->has_frame);
+          gtk_entry_set_has_frame (GTK_ENTRY (child), priv->has_frame);
         }
 
       break;
@@ -1119,11 +1139,11 @@ gtk_combo_box_set_property (GObject      *object,
       break;
 
     case PROP_EDITING_CANCELED:
-      combo_box->priv->editing_canceled = g_value_get_boolean (value);
+      priv->editing_canceled = g_value_get_boolean (value);
       break;
 
     case PROP_HAS_ENTRY:
-      combo_box->priv->has_entry = g_value_get_boolean (value);
+      priv->has_entry = g_value_get_boolean (value);
       break;
 
     case PROP_ENTRY_TEXT_COLUMN:
@@ -1141,9 +1161,17 @@ gtk_combo_box_set_property (GObject      *object,
     case PROP_CELL_AREA:
       /* Construct-only, can only be assigned once */
       area = g_value_get_object (value);
-
       if (area)
-        combo_box->priv->area = g_object_ref_sink (area);
+        {
+          if (priv->area != NULL)
+            {
+              g_warning ("cell-area has already been set, ignoring construct property");
+              g_object_ref_sink (area);
+              g_object_unref (area);
+            }
+          else
+            priv->area = g_object_ref_sink (area);
+        }
       break;
 
     default:
@@ -1242,8 +1270,8 @@ gtk_combo_box_get_property (GObject    *object,
 }
 
 static void
-gtk_combo_box_state_changed (GtkWidget    *widget,
-                             GtkStateType  previous)
+gtk_combo_box_state_flags_changed (GtkWidget     *widget,
+                                   GtkStateFlags  previous)
 {
   GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
   GtkComboBoxPrivate *priv = combo_box->priv;
@@ -1254,17 +1282,13 @@ gtk_combo_box_state_changed (GtkWidget    *widget,
         {
           GtkStyleContext *context;
           GtkStateFlags state;
-          GdkRGBA *color;
+          GdkRGBA color;
 
           context  = gtk_widget_get_style_context (widget);
           state = gtk_widget_get_state_flags (widget);
+          gtk_style_context_get_background_color (context, state, &color);
 
-          gtk_style_context_get (context, state,
-                                 "background-color", &color,
-                                 NULL);
-
-          gtk_cell_view_set_background_rgba (GTK_CELL_VIEW (priv->cell_view), color);
-          gdk_rgba_free (color);
+          gtk_cell_view_set_background_rgba (GTK_CELL_VIEW (priv->cell_view), &color);
         }
     }
 
@@ -1339,22 +1363,21 @@ gtk_combo_box_style_updated (GtkWidget *widget)
   GtkComboBoxPrivate *priv = combo_box->priv;
   GtkWidget *child;
 
+  GTK_WIDGET_CLASS (gtk_combo_box_parent_class)->style_updated (widget);
+
   gtk_combo_box_check_appearance (combo_box);
 
   if (priv->tree_view && priv->cell_view)
     {
       GtkStyleContext *context;
-      GdkRGBA *color;
-
-      context = gtk_widget_get_style_context (widget);
-      gtk_style_context_get (context, 0,
-                             "background-color", &color,
-                             NULL);
+      GtkStateFlags state;
+      GdkRGBA color;
 
-      gtk_cell_view_set_background_rgba (GTK_CELL_VIEW (priv->cell_view),
-                                         color);
+      context  = gtk_widget_get_style_context (widget);
+      state = gtk_widget_get_state_flags (widget);
+      gtk_style_context_get_background_color (context, state, &color);
 
-      gdk_rgba_free (color);
+      gtk_cell_view_set_background_rgba (GTK_CELL_VIEW (priv->cell_view), &color);
     }
 
   child = gtk_bin_get_child (GTK_BIN (combo_box));
@@ -1661,21 +1684,16 @@ gtk_combo_box_set_popup_widget (GtkComboBox *combo_box,
 }
 
 static void
-get_widget_border (GtkWidget *widget,
-                   GtkBorder *border)
+get_widget_padding (GtkWidget *widget,
+                    GtkBorder *padding)
 {
   GtkStyleContext *context;
-  GtkBorder *border_width;
+  GtkStateFlags state;
 
   context = gtk_widget_get_style_context (widget);
+  state = gtk_style_context_get_state (context);
 
-  gtk_style_context_get (context,
-                         gtk_widget_get_state_flags (widget),
-                         "border-width", &border_width,
-                         NULL);
-
-  *border = *border_width;
-  gtk_border_free (border_width);
+  gtk_style_context_get_padding (context, state, padding);
 }
 
 static void
@@ -1693,7 +1711,7 @@ gtk_combo_box_menu_position_below (GtkMenu  *menu,
   GdkScreen *screen;
   gint monitor_num;
   GdkRectangle monitor;
-  GtkBorder border;
+  GtkBorder padding;
 
   /* FIXME: is using the size request here broken? */
   child = gtk_bin_get_child (GTK_BIN (combo_box));
@@ -1710,8 +1728,8 @@ gtk_combo_box_menu_position_below (GtkMenu  *menu,
 
   gdk_window_get_root_coords (gtk_widget_get_window (child),
                               sx, sy, &sx, &sy);
-  get_widget_border (GTK_WIDGET (combo_box), &border);
-  sx -= border.left;
+  get_widget_padding (GTK_WIDGET (combo_box), &padding);
+  sx -= padding.left;
 
   if (combo_box->priv->popup_fixed_width)
     gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL);
@@ -1961,12 +1979,12 @@ gtk_combo_box_list_position (GtkComboBox *combo_box,
 }
 
 static gboolean
-cell_view_is_sensitive (GtkCellView *cell_view)
+cell_layout_is_sensitive (GtkCellLayout *layout)
 {
   GList *cells, *list;
   gboolean sensitive;
 
-  cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (cell_view));
+  cells = gtk_cell_layout_get_cells (layout);
 
   sensitive = FALSE;
   for (list = cells; list; list = list->next)
@@ -1981,16 +1999,22 @@ cell_view_is_sensitive (GtkCellView *cell_view)
   return sensitive;
 }
 
+static gboolean
+cell_is_sensitive (GtkCellRenderer *cell,
+                   gpointer         data)
+{
+  gboolean *sensitive = data;
+
+  g_object_get (cell, "sensitive", sensitive, NULL);
+
+  return *sensitive;
+}
+
 static gboolean
 tree_column_row_is_sensitive (GtkComboBox *combo_box,
                               GtkTreeIter *iter)
 {
   GtkComboBoxPrivate *priv = combo_box->priv;
-  GList *cells, *list;
-  gboolean sensitive;
-
-  if (!priv->column)
-    return TRUE;
 
   if (priv->row_separator_func)
     {
@@ -1999,23 +2023,20 @@ tree_column_row_is_sensitive (GtkComboBox *combo_box,
         return FALSE;
     }
 
-  gtk_tree_view_column_cell_set_cell_data (priv->column,
-                                           priv->model,
-                                           iter, FALSE, FALSE);
+  if (priv->area)
+    {
+      gboolean sensitive;
 
-  cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (priv->column));
+      gtk_cell_area_apply_attributes (priv->area, priv->model, iter, FALSE, FALSE);
 
-  sensitive = FALSE;
-  for (list = cells; list; list = list->next)
-    {
-      g_object_get (list->data, "sensitive", &sensitive, NULL);
+      sensitive = FALSE;
 
-      if (sensitive)
-        break;
+      gtk_cell_area_foreach (priv->area, cell_is_sensitive, &sensitive);
+
+      return sensitive;
     }
-  g_list_free (cells);
 
-  return sensitive;
+  return TRUE;
 }
 
 static void
@@ -2049,7 +2070,7 @@ update_menu_sensitivity (GtkComboBox *combo_box,
         }
       else
         {
-          sensitive = cell_view_is_sensitive (GTK_CELL_VIEW (cell_view));
+          sensitive = cell_layout_is_sensitive (GTK_CELL_LAYOUT (cell_view));
 
           if (menu != priv->popup_widget && child == children)
             {
@@ -2347,13 +2368,13 @@ gtk_combo_box_popdown (GtkComboBox *combo_box)
                                  &req, NULL);                                         \
                                                                                   \
   if (is_rtl)                                                                         \
-    child.x = allocation->x + border.right;                                        \
+    child.x = allocation->x + padding.right;                                        \
   else                                                                                \
-    child.x = allocation->x + allocation->width - req.width - border.left;        \
+    child.x = allocation->x + allocation->width - req.width - padding.left;        \
                                                                                     \
-  child.y = allocation->y + border.top;                                                \
+  child.y = allocation->y + padding.top;                                                \
   child.width = req.width;                                                        \
-  child.height = allocation->height - (border.top + border.bottom);                \
+  child.height = allocation->height - (padding.top + padding.bottom);                \
   child.width = MAX (1, child.width);                                                \
   child.height = MAX (1, child.height);                                                \
                                                                                   \
@@ -2371,11 +2392,11 @@ gtk_combo_box_size_allocate (GtkWidget     *widget,
   GtkAllocation child;
   GtkRequisition req;
   gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
-  GtkBorder border;
+  GtkBorder padding;
 
   gtk_widget_set_allocation (widget, allocation);
   child_widget = gtk_bin_get_child (GTK_BIN (widget));
-  get_widget_border (widget, &border);
+  get_widget_padding (widget, &padding);
 
   gtk_widget_style_get (widget,
                         "focus-line-width", &focus_width,
@@ -2386,21 +2407,21 @@ gtk_combo_box_size_allocate (GtkWidget     *widget,
     {
       if (priv->cell_view)
         {
-          GtkBorder button_border;
+          GtkBorder button_padding;
           gint width;
           guint border_width;
 
-          /* menu mode */
-          allocation->x += border.left;
-          allocation->y += border.top;
-          allocation->width -= border.left + border.right;
-          allocation->height -= border.top + border.bottom;
-
           gtk_widget_size_allocate (priv->button, allocation);
 
+          /* menu mode */
+          allocation->x += padding.left;
+          allocation->y += padding.top;
+          allocation->width -= padding.left + padding.right;
+          allocation->height -= padding.top + padding.bottom;
+
           /* set some things ready */
           border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->button));
-          get_widget_border (priv->button, &button_border);
+          get_widget_padding (priv->button, &button_padding);
 
           child.x = allocation->x;
           child.y = allocation->y;
@@ -2409,19 +2430,19 @@ gtk_combo_box_size_allocate (GtkWidget     *widget,
 
           if (!priv->is_cell_renderer)
             {
-              child.x += border_width + button_border.left + focus_width + focus_pad;
-              child.y += border_width + button_border.top + focus_width + focus_pad;
+              child.x += border_width + button_padding.left + focus_width + focus_pad;
+              child.y += border_width + button_padding.top + focus_width + focus_pad;
               width -= (2 * (border_width + focus_width + focus_pad)) +
-                button_border.left + button_border.right;
+                button_padding.left + button_padding.right;
               child.height -= (2 * (border_width + focus_width + focus_pad)) +
-                button_border.top + button_border.bottom;
+                button_padding.top + button_padding.bottom;
             }
 
           /* handle the children */
           gtk_widget_get_preferred_size (priv->arrow, &req, NULL);
           child.width = req.width;
           if (!is_rtl)
-            child.x += width - req.width;
+            child.x += width - req.width - button_padding.right;
           child.width = MAX (1, child.width);
           child.height = MAX (1, child.height);
           gtk_widget_size_allocate (priv->arrow, &child);
@@ -2439,14 +2460,14 @@ gtk_combo_box_size_allocate (GtkWidget     *widget,
             {
               child.x += req.width;
               child.width = allocation->x + allocation->width
-                - (border_width + button_border.right + focus_width + focus_pad)
+                - (border_width + focus_width + focus_pad)
                 - child.x;
             }
           else
             {
               child.width = child.x;
               child.x = allocation->x
-                + border_width + button_border.left + focus_width + focus_pad;
+                + border_width + button_padding.left + focus_width + focus_pad;
               child.width -= child.x;
             }
 
@@ -2484,11 +2505,11 @@ gtk_combo_box_size_allocate (GtkWidget     *widget,
           GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON
 
           if (is_rtl)
-            child.x = allocation->x + req.width + border.right;
+            child.x = allocation->x + req.width + padding.right;
           else
-            child.x = allocation->x + border.left;
-          child.y = allocation->y + border.top;
-          child.width = allocation->width - req.width - (border.left + border.right);
+            child.x = allocation->x + padding.left;
+          child.y = allocation->y + padding.top;
+          child.width = allocation->width - req.width - (padding.left + padding.right);
           child.width = MAX (1, child.width);
           child.height = MAX (1, child.height);
           gtk_widget_size_allocate (child_widget, &child);
@@ -2514,32 +2535,32 @@ gtk_combo_box_size_allocate (GtkWidget     *widget,
 
       if (priv->cell_view_frame)
         {
-          child.x += border.left + border_width;
-          child.y += border.top + border_width;
-          child.width = MAX (1, child.width - (2 * border_width) - (border.left + border.right));
-          child.height = MAX (1, child.height - (2 * border_width) - (border.top + border.bottom));
+          child.x += padding.left + border_width;
+          child.y += padding.top + border_width;
+          child.width = MAX (1, child.width - (2 * border_width) - (padding.left + padding.right));
+          child.height = MAX (1, child.height - (2 * border_width) - (padding.top + padding.bottom));
           gtk_widget_size_allocate (priv->cell_view_frame, &child);
 
           /* the sample */
           if (priv->has_frame)
             {
-              GtkBorder frame_border;
+              GtkBorder frame_padding;
 
               border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->cell_view_frame));
-              get_widget_border (priv->cell_view_frame, &frame_border);
+              get_widget_padding (priv->cell_view_frame, &frame_padding);
 
-              child.x += border_width + frame_border.left;
-              child.y += border_width + frame_border.right;
-              child.width -= (2 * border_width) + frame_border.left + frame_border.right;
-              child.height -= (2 * border_width) + frame_border.top + frame_border.bottom;
+              child.x += border_width + frame_padding.left;
+              child.y += border_width + frame_padding.right;
+              child.width -= (2 * border_width) + frame_padding.left + frame_padding.right;
+              child.height -= (2 * border_width) + frame_padding.top + frame_padding.bottom;
             }
         }
       else
         {
-          child.x += border.left + border_width;
-          child.y += border.top + border_width;
-          child.width -= (2 * border_width) - (border.left + border.right);
-          child.height -= (2 * border_width) - (border.top + border.bottom);
+          child.x += padding.left + border_width;
+          child.y += padding.top + border_width;
+          child.width -= (2 * border_width) - (padding.left + padding.right);
+          child.height -= (2 * border_width) - (padding.top + padding.bottom);
         }
 
       if (gtk_widget_get_visible (priv->popup_window))
@@ -3013,8 +3034,6 @@ gtk_combo_box_menu_setup (GtkComboBox *combo_box,
                                   (GtkTreeMenuHeaderFunc)gtk_combo_box_header_func,
                                   combo_box, NULL);
 
-  gtk_widget_set_name (menu, "gtk-combobox-popup-menu");
-
   g_signal_connect (menu, "key-press-event",
                     G_CALLBACK (gtk_combo_box_menu_key_press), combo_box);
   gtk_combo_box_set_popup_widget (combo_box, menu);
@@ -3048,8 +3067,6 @@ gtk_combo_box_menu_destroy (GtkComboBox *combo_box)
   priv->arrow = NULL;
   priv->separator = NULL;
 
-  priv->column = NULL;
-
   /* changing the popup window will unref the menu and the children */
 }
 
@@ -3268,17 +3285,13 @@ gtk_combo_box_list_setup (GtkComboBox *combo_box)
     {
       GtkStyleContext *context;
       GtkStateFlags state;
-      GdkRGBA *color;
+      GdkRGBA color;
 
-      context = gtk_widget_get_style_context (widget);
+      context  = gtk_widget_get_style_context (widget);
       state = gtk_widget_get_state_flags (widget);
+      gtk_style_context_get_background_color (context, state, &color);
 
-      gtk_style_context_get (context, state,
-                             "background-color", &color,
-                             NULL);
-
-      gtk_cell_view_set_background_rgba (GTK_CELL_VIEW (priv->cell_view), color);
-      gdk_rgba_free (color);
+      gtk_cell_view_set_background_rgba (GTK_CELL_VIEW (priv->cell_view), &color);
 
       priv->box = gtk_event_box_new ();
       gtk_event_box_set_visible_window (GTK_EVENT_BOX (priv->box),
@@ -3325,8 +3338,8 @@ gtk_combo_box_list_setup (GtkComboBox *combo_box)
   if (priv->model)
     gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view), priv->model);
 
-  priv->column = gtk_tree_view_column_new_with_area (priv->area);
-  gtk_tree_view_append_column (GTK_TREE_VIEW (priv->tree_view), priv->column);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (priv->tree_view),
+                               gtk_tree_view_column_new_with_area (priv->area));
 
   if (gtk_tree_row_reference_valid (priv->active_row))
     {
@@ -3632,35 +3645,35 @@ gtk_combo_box_list_auto_scroll (GtkComboBox *combo_box,
   gtk_widget_get_allocation (tree_view, &allocation);
 
   adj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (combo_box->priv->scrolled_window));
-  if (adj && adj->upper - adj->lower > adj->page_size)
+  if (adj && gtk_adjustment_get_upper (adj) - gtk_adjustment_get_lower (adj) > gtk_adjustment_get_page_size (adj))
     {
       if (x <= allocation.x &&
-          adj->lower < adj->value)
+          gtk_adjustment_get_lower (adj) < gtk_adjustment_get_value (adj))
         {
-          value = adj->value - (allocation.x - x + 1);
+          value = gtk_adjustment_get_value (adj) - (allocation.x - x + 1);
           gtk_adjustment_set_value (adj, value);
         }
       else if (x >= allocation.x + allocation.width &&
-               adj->upper - adj->page_size > adj->value)
+               gtk_adjustment_get_upper (adj) - gtk_adjustment_get_page_size (adj) > gtk_adjustment_get_value (adj))
         {
-          value = adj->value + (x - allocation.x - allocation.width + 1);
+          value = gtk_adjustment_get_value (adj) + (x - allocation.x - allocation.width + 1);
           gtk_adjustment_set_value (adj, MAX (value, 0.0));
         }
     }
 
   adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (combo_box->priv->scrolled_window));
-  if (adj && adj->upper - adj->lower > adj->page_size)
+  if (adj && gtk_adjustment_get_upper (adj) - gtk_adjustment_get_lower (adj) > gtk_adjustment_get_page_size (adj))
     {
       if (y <= allocation.y &&
-          adj->lower < adj->value)
+          gtk_adjustment_get_lower (adj) < gtk_adjustment_get_value (adj))
         {
-          value = adj->value - (allocation.y - y + 1);
+          value = gtk_adjustment_get_value (adj) - (allocation.y - y + 1);
           gtk_adjustment_set_value (adj, value);
         }
       else if (y >= allocation.height &&
-               adj->upper - adj->page_size > adj->value)
+               gtk_adjustment_get_upper (adj) - gtk_adjustment_get_page_size (adj) > gtk_adjustment_get_value (adj))
         {
-          value = adj->value + (y - allocation.height + 1);
+          value = gtk_adjustment_get_value (adj) + (y - allocation.height + 1);
           gtk_adjustment_set_value (adj, MAX (value, 0.0));
         }
     }
@@ -3756,10 +3769,19 @@ gtk_combo_box_list_row_changed (GtkTreeModel *model,
 /*
  * GtkCellLayout implementation
  */
-GtkCellArea *
-gtk_combo_box_cell_layout_get_area (GtkCellLayout    *cell_layout)
+static GtkCellArea *
+gtk_combo_box_cell_layout_get_area (GtkCellLayout *cell_layout)
 {
-  return GTK_COMBO_BOX (cell_layout)->priv->area;
+  GtkComboBox *combo = GTK_COMBO_BOX (cell_layout);
+  GtkComboBoxPrivate *priv = combo->priv;
+
+  if (G_UNLIKELY (!priv->area))
+    {
+      priv->area = gtk_cell_area_box_new ();
+      g_object_ref_sink (priv->area);
+    }
+
+  return priv->area;
 }
 
 /*
@@ -4541,7 +4563,6 @@ gtk_combo_box_constructor (GType                  type,
   GObject            *object;
   GtkComboBox        *combo_box;
   GtkComboBoxPrivate *priv;
-  GtkStyleContext    *context;
 
   object = G_OBJECT_CLASS (gtk_combo_box_parent_class)->constructor
     (type, n_construct_properties, construct_properties);
@@ -4551,9 +4572,8 @@ gtk_combo_box_constructor (GType                  type,
 
   if (!priv->area)
     {
-      GtkCellArea *area = gtk_cell_area_box_new ();
-
-      priv->area = g_object_ref_sink (area);
+      priv->area = gtk_cell_area_box_new ();
+      g_object_ref_sink (priv->area);
     }
 
   priv->cell_view = gtk_cell_view_new_with_context (priv->area, NULL);
@@ -4565,9 +4585,6 @@ gtk_combo_box_constructor (GType                  type,
 
   gtk_combo_box_check_appearance (combo_box);
 
-  context = gtk_widget_get_style_context (GTK_WIDGET (combo_box));
-  gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON);
-
   if (priv->has_entry)
     {
       GtkWidget *entry;
@@ -4944,7 +4961,7 @@ gtk_combo_box_get_popup_accessible (GtkComboBox *combo_box)
 }
 
 /**
- * gtk_combo_box_get_row_separator_func:
+ * gtk_combo_box_get_row_separator_func: (skip)
  * @combo_box: a #GtkComboBox
  *
  * Returns the current row separator function.
@@ -5235,13 +5252,14 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget,
   gint                   font_size, arrow_size;
   PangoContext          *context;
   PangoFontMetrics      *metrics;
-  PangoFontDescription  *font_desc;
+  const PangoFontDescription *font_desc;
   GtkWidget             *child;
   gint                   minimum_width = 0, natural_width = 0;
   gint                   child_min, child_nat;
   GtkStyleContext       *style_context;
   GtkStateFlags          state;
-  GtkBorder             *border;
+  GtkBorder              padding;
+  gfloat                 arrow_scaling;
 
   child = gtk_bin_get_child (GTK_BIN (widget));
 
@@ -5252,15 +5270,14 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget,
                         "focus-line-width", &focus_width,
                         "focus-padding", &focus_pad,
                         "arrow-size", &arrow_size,
+                        "arrow-scaling", &arrow_scaling,
                         NULL);
 
   style_context = gtk_widget_get_style_context (widget);
   state = gtk_widget_get_state_flags (widget);
 
-  gtk_style_context_get (style_context, state,
-                         "font", &font_desc,
-                         "border-width", &border,
-                         NULL);
+  get_widget_padding (widget, &padding);
+  font_desc = gtk_style_context_get_font (style_context, state);
 
   context = gtk_widget_get_pango_context (GTK_WIDGET (widget));
   metrics = pango_context_get_metrics (context, font_desc,
@@ -5268,9 +5285,8 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget,
   font_size = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
                             pango_font_metrics_get_descent (metrics));
   pango_font_metrics_unref (metrics);
-  pango_font_description_free (font_desc);
 
-  arrow_size = MAX (arrow_size, font_size);
+  arrow_size = MAX (arrow_size, font_size) * arrow_scaling;
 
   gtk_widget_set_size_request (priv->arrow, arrow_size, arrow_size);
 
@@ -5281,16 +5297,16 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget,
         {
           gint sep_width, arrow_width;
           gint border_width, xpad;
-          GtkBorder button_border;
+          GtkBorder button_padding;
 
           border_width = gtk_container_get_border_width (GTK_CONTAINER (combo_box));
-          get_widget_border (priv->button, &button_border);
+          get_widget_padding (priv->button, &button_padding);
 
           gtk_widget_get_preferred_width (priv->separator, &sep_width, NULL);
           gtk_widget_get_preferred_width (priv->arrow, &arrow_width, NULL);
 
           xpad = 2 * (border_width + focus_width + focus_pad) +
-            button_border.left + button_border.right;
+            button_padding.left + button_padding.right + padding.left + padding.right;
 
           minimum_width  = child_min + sep_width + arrow_width + xpad;
           natural_width  = child_nat + sep_width + arrow_width + xpad;
@@ -5323,11 +5339,11 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget,
           if (priv->has_frame)
             {
               gint border_width, xpad;
-              GtkBorder frame_border;
+              GtkBorder frame_padding;
 
               border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->cell_view_frame));
-              get_widget_border (priv->cell_view_frame, &frame_border);
-              xpad = (2 * border_width) + frame_border.left + frame_border.right;
+              get_widget_padding (priv->cell_view_frame, &frame_padding);
+              xpad = (2 * border_width) + frame_padding.left + frame_padding.right;
 
               minimum_width  += xpad;
               natural_width  += xpad;
@@ -5342,9 +5358,8 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget,
       natural_width += button_nat_width;
     }
 
-  minimum_width += border->left + border->right;
-  natural_width += border->left + border->right;
-  gtk_border_free (border);
+  minimum_width += padding.left + padding.right;
+  natural_width += padding.left + padding.right;
 
   if (minimum_size)
     *minimum_size = minimum_width;
@@ -5390,7 +5405,7 @@ gtk_combo_box_get_preferred_height_for_width (GtkWidget *widget,
   gint                   min_height = 0, nat_height = 0;
   gint                   size;
   GtkWidget             *child;
-  GtkBorder              border;
+  GtkBorder              padding;
 
   gtk_widget_style_get (GTK_WIDGET (widget),
                         "focus-line-width", &focus_width,
@@ -5399,8 +5414,8 @@ gtk_combo_box_get_preferred_height_for_width (GtkWidget *widget,
 
   child = gtk_bin_get_child (GTK_BIN (widget));
 
-  get_widget_border (widget, &border);
-  size = avail_size - border.left;
+  get_widget_padding (widget, &padding);
+  size = avail_size;
 
   if (!priv->tree_view)
     {
@@ -5410,10 +5425,10 @@ gtk_combo_box_get_preferred_height_for_width (GtkWidget *widget,
           /* calculate x/y padding and separator/arrow size */
           gint sep_width, arrow_width, sep_height, arrow_height;
           gint border_width, xpad, ypad;
-          GtkBorder button_border;
+          GtkBorder button_padding;
 
           border_width = gtk_container_get_border_width (GTK_CONTAINER (combo_box));
-          get_widget_border (priv->button, &button_border);
+          get_widget_padding (priv->button, &button_padding);
 
           gtk_widget_get_preferred_width (priv->separator, &sep_width, NULL);
           gtk_widget_get_preferred_width (priv->arrow, &arrow_width, NULL);
@@ -5423,9 +5438,9 @@ gtk_combo_box_get_preferred_height_for_width (GtkWidget *widget,
                                                      arrow_width, &arrow_height, NULL);
 
           xpad = 2 * (border_width + focus_width + focus_pad) +
-            button_border.left + button_border.right;
+            button_padding.left + button_padding.right;
           ypad = 2 * (border_width + focus_width + focus_pad) +
-            button_border.top + button_border.bottom;
+            button_padding.top + button_padding.bottom;
 
           size -= sep_width + arrow_width + xpad;
 
@@ -5471,14 +5486,14 @@ gtk_combo_box_get_preferred_height_for_width (GtkWidget *widget,
 
       if (priv->cell_view_frame && priv->has_frame)
         {
-          GtkBorder frame_border;
+          GtkBorder frame_padding;
           gint border_width;
 
           border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->cell_view_frame));
-          get_widget_border (GTK_WIDGET (priv->cell_view_frame), &frame_border);
+          get_widget_padding (GTK_WIDGET (priv->cell_view_frame), &frame_padding);
 
-          xpad = (2 * border_width) + border.left + frame_border.right;
-          ypad = (2 * border_width) + border.top + frame_border.bottom;
+          xpad = (2 * border_width) + padding.left + frame_padding.right;
+          ypad = (2 * border_width) + padding.top + frame_padding.bottom;
         }
 
       size -= but_width;
@@ -5496,8 +5511,8 @@ gtk_combo_box_get_preferred_height_for_width (GtkWidget *widget,
       nat_height += ypad;
     }
 
-  min_height += border.top + border.bottom;
-  nat_height += border.top + border.bottom;
+  min_height += padding.top + padding.bottom;
+  nat_height += padding.top + padding.bottom;
 
   if (minimum_size)
     *minimum_size = min_height;
@@ -5565,15 +5580,16 @@ gtk_combo_box_get_id_column (GtkComboBox *combo_box)
  * @combo_box: a #GtkComboBox
  *
  * Returns the ID of the active row of @combo_box.  This value is taken
- * from the active row and the column specified by the 'id-column'
+ * from the active row and the column specified by the #GtkComboBox:id-column
  * property of @combo_box (see gtk_combo_box_set_id_column()).
  *
  * The returned value is an interned string which means that you can
  * compare the pointer by value to other interned strings and that you
  * must not free it.
  *
- * If the 'id-column' property of @combo_box is not set or if no row is
- * selected then %NULL is returned.
+ * If the #GtkComboBox:id-column property of @combo_box is not set, or if
+ * no row is active, or if the active row has a %NULL ID value, then %NULL
+ * is returned.
  *
  * Return value: the ID of the active row, or %NULL
  *
@@ -5586,7 +5602,7 @@ gtk_combo_box_get_active_id (GtkComboBox *combo_box)
   GtkTreeIter iter;
   gint column;
 
-  g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), 0);
+  g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), NULL);
 
   column = combo_box->priv->id_column;
 
@@ -5615,41 +5631,54 @@ gtk_combo_box_get_active_id (GtkComboBox *combo_box)
 /**
  * gtk_combo_box_set_active_id:
  * @combo_box: a #GtkComboBox
- * @active_id: the ID of the row to select
+ * @active_id: (allow-none): the ID of the row to select, or %NULL
+ *
+ * Changes the active row of @combo_box to the one that has an ID equal to
+ * @active_id, or unsets the active row if @active_id is %NULL.  Rows having
+ * a %NULL ID string cannot be made active by this function.
  *
- * Changes the active row of @combo_box to the one that has an ID equal to @id.
+ * If the #GtkComboBox:id-column property of @combo_box is unset or if no
+ * row has the given ID then the function does nothing and returns %FALSE.
  *
- * If the 'id-column' property of @combo_box is unset or if no row has
- * the given ID then nothing happens.
+ * Returns: %TRUE if a row with a matching ID was found.  If a %NULL
+ *          @active_id was given to unset the active row, the function
+ *          always returns %TRUE.
  *
  * Since: 3.0
  **/
-void
+gboolean
 gtk_combo_box_set_active_id (GtkComboBox *combo_box,
                              const gchar *active_id)
 {
   GtkTreeModel *model;
   GtkTreeIter iter;
+  gboolean match = FALSE;
   gint column;
 
-  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
+  g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), FALSE);
+
+  if (active_id == NULL)
+    {
+      gtk_combo_box_set_active (combo_box, -1);
+      return TRUE;  /* active row was successfully unset */
+    }
 
   column = combo_box->priv->id_column;
 
   if (column < 0)
-    return;
+    return FALSE;
 
   model = gtk_combo_box_get_model (combo_box);
-  g_return_if_fail (gtk_tree_model_get_column_type (model, column) ==
-                    G_TYPE_STRING);
+  g_return_val_if_fail (gtk_tree_model_get_column_type (model, column) ==
+                        G_TYPE_STRING, FALSE);
 
   if (gtk_tree_model_get_iter_first (model, &iter))
     do {
-      gboolean match;
       gchar *id;
 
       gtk_tree_model_get (model, &iter, column, &id, -1);
-      match = strcmp (id, active_id) == 0;
+      if (id != NULL)
+        match = strcmp (id, active_id) == 0;
       g_free (id);
 
       if (match)
@@ -5658,4 +5687,6 @@ gtk_combo_box_set_active_id (GtkComboBox *combo_box,
           break;
         }
     } while (gtk_tree_model_iter_next (model, &iter));
+
+    return match;
 }