]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkcombobox.c
texthandles: Keep state internally to avoid X overhead
[~andy/gtk] / gtk / gtkcombobox.c
index 9db2ff818389d017b663ddf9a767146019c906b2..e7ef489f61fa3c686d7aa0d649140a956cf7d87f 100644 (file)
  * Library General Public License for more details.
  *
  * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "config.h"
+
 #include "gtkcombobox.h"
+
+#include "gtkadjustment.h"
 #include "gtkcellareabox.h"
 #include "gtktreemenu.h"
 #include "gtkarrow.h"
 #include "gtkcellview.h"
 #include "gtkeventbox.h"
 #include "gtkframe.h"
-#include "gtkhbox.h"
+#include "gtkbox.h"
 #include "gtkliststore.h"
 #include "gtkmain.h"
 #include "gtkmenuprivate.h"
 #include "gtkmenushellprivate.h"
 #include "gtkscrolledwindow.h"
 #include "gtkseparatormenuitem.h"
-#include "gtktearoffmenuitem.h"
+#include "deprecated/gtktearoffmenuitem.h"
 #include "gtktogglebutton.h"
 #include "gtktreeselection.h"
-#include "gtkvseparator.h"
+#include "gtkseparator.h"
+#include "gtkwidgetpath.h"
+#include "gtkwidgetprivate.h"
 #include "gtkwindow.h"
 #include "gtktypebuiltins.h"
 #include "gtkprivate.h"
@@ -53,6 +56,7 @@
 
 #include "gtkentryprivate.h"
 #include "gtktreeprivate.h"
+#include "a11y/gtkcomboboxaccessible.h"
 
 
 /**
@@ -216,6 +220,7 @@ enum {
   MOVE_ACTIVE,
   POPUP,
   POPDOWN,
+  FORMAT_ENTRY_TEXT,
   LAST_SIGNAL
 };
 
@@ -243,7 +248,6 @@ enum {
 
 static guint combo_box_signals[LAST_SIGNAL] = {0,};
 
-#define BONUS_PADDING 4
 #define SCROLL_TIME  100
 
 /* common */
@@ -266,8 +270,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,
@@ -421,7 +425,8 @@ static void     gtk_combo_box_entry_contents_changed         (GtkEntry        *e
                                                               gpointer         user_data);
 static void     gtk_combo_box_entry_active_changed           (GtkComboBox     *combo_box,
                                                               gpointer         user_data);
-
+static gchar   *gtk_combo_box_format_entry_text              (GtkComboBox     *combo_box,
+                                                             const gchar     *path);
 
 /* GtkBuildable method implementation */
 static GtkBuildableIface *parent_buildable_iface;
@@ -461,7 +466,10 @@ static void     gtk_combo_box_get_preferred_height_for_width (GtkWidget    *widg
                                                               gint          avail_size,
                                                               gint         *minimum_size,
                                                               gint         *natural_size);
-
+static GtkWidgetPath *gtk_combo_box_get_path_for_child       (GtkContainer *container,
+                                                              GtkWidget    *child);
+static void     gtk_combo_box_direction_changed              (GtkWidget    *widget,
+                                                              GtkTextDirection  previous_direction);
 
 G_DEFINE_TYPE_WITH_CODE (GtkComboBox, gtk_combo_box, GTK_TYPE_BIN,
                          G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
@@ -485,6 +493,9 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass)
   container_class->forall = gtk_combo_box_forall;
   container_class->add = gtk_combo_box_add;
   container_class->remove = gtk_combo_box_remove;
+  container_class->get_path_for_child = gtk_combo_box_get_path_for_child;
+
+  gtk_container_class_handle_border_width (container_class);
 
   widget_class = (GtkWidgetClass *)klass;
   widget_class->size_allocate = gtk_combo_box_size_allocate;
@@ -493,12 +504,13 @@ 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;
   widget_class->get_preferred_width_for_height = gtk_combo_box_get_preferred_width_for_height;
   widget_class->destroy = gtk_combo_box_destroy;
+  widget_class->direction_changed = gtk_combo_box_direction_changed;
 
   object_class = (GObjectClass *)klass;
   object_class->constructor = gtk_combo_box_constructor;
@@ -507,6 +519,8 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass)
   object_class->set_property = gtk_combo_box_set_property;
   object_class->get_property = gtk_combo_box_get_property;
 
+  klass->format_entry_text = gtk_combo_box_format_entry_text;
+
   /* signals */
   /**
    * GtkComboBox::changed:
@@ -591,6 +605,58 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass)
                                 _gtk_marshal_BOOLEAN__VOID,
                                 G_TYPE_BOOLEAN, 0);
 
+  /**
+   * GtkComboBox::format-entry-text:
+   * @combo: the object which received the signal
+   * @path: the GtkTreePath string from the combo box's current model to format text for
+   *
+   * For combo boxes that are created with an entry (See GtkComboBox:has-entry).
+   *
+   * A signal which allows you to change how the text displayed in a combo box's
+   * entry is displayed.
+   *
+   * Connect a signal handler which returns an allocated string representing
+   * @path. That string will then be used to set the text in the combo box's entry.
+   * The default signal handler uses the text from the GtkComboBox::entry-text-column 
+   * model column.
+   *
+   * Here's an example signal handler which fetches data from the model and
+   * displays it in the entry.
+   * |[
+   * static gchar*
+   * format_entry_text_callback (GtkComboBox *combo,
+   *                             const gchar *path,
+   *                             gpointer     user_data)
+   * {
+   *   GtkTreeIter iter;
+   *   GtkTreeModel model;
+   *   gdouble      value;
+   *   
+   *   model = gtk_combo_box_get_model (combo);
+   *
+   *   gtk_tree_model_get_iter_from_string (model, &iter, path);
+   *   gtk_tree_model_get (model, &iter, 
+   *                       THE_DOUBLE_VALUE_COLUMN, &value,
+   *                       -1);
+   *
+   *   return g_strdup_printf ("&percnt;g", value);
+   * }
+   * ]|
+   *
+   * Return value: (transfer full): a newly allocated string representing @path 
+   * for the current GtkComboBox model.
+   *
+   * Since: 3.4
+   */
+  combo_box_signals[FORMAT_ENTRY_TEXT] =
+    g_signal_new (I_("format-entry-text"),
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GtkComboBoxClass, format_entry_text),
+                  _gtk_single_string_accumulator, NULL,
+                  _gtk_marshal_STRING__STRING,
+                  G_TYPE_STRING, 1, G_TYPE_STRING);
+
   /* key bindings */
   binding_set = gtk_binding_set_by_class (widget_class);
 
@@ -933,6 +999,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 +1038,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:
    *
@@ -985,6 +1071,8 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass)
                                                               GTK_PARAM_READABLE));
 
   g_type_class_add_private (object_class, sizeof (GtkComboBoxPrivate));
+
+  gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_COMBO_BOX_ACCESSIBLE);
 }
 
 static void
@@ -1250,8 +1338,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;
@@ -1262,17 +1350,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);
         }
     }
 
@@ -1298,6 +1382,94 @@ gtk_combo_box_button_state_flags_changed (GtkWidget     *widget,
   gtk_widget_queue_draw (widget);
 }
 
+static void
+gtk_combo_box_invalidate_order_foreach (GtkWidget *widget)
+{
+  _gtk_widget_invalidate_style_context (widget, GTK_CSS_CHANGE_POSITION | GTK_CSS_CHANGE_SIBLING_POSITION);
+}
+
+static void
+gtk_combo_box_invalidate_order (GtkComboBox *combo_box)
+{
+  gtk_container_forall (GTK_CONTAINER (combo_box),
+                        (GtkCallback) gtk_combo_box_invalidate_order_foreach,
+                        NULL);
+}
+
+static void
+gtk_combo_box_direction_changed (GtkWidget        *widget,
+                                 GtkTextDirection  previous_direction)
+{
+  gtk_combo_box_invalidate_order (GTK_COMBO_BOX (widget));
+}
+
+static GtkWidgetPath *
+gtk_combo_box_get_path_for_child (GtkContainer *container,
+                                  GtkWidget    *child)
+{
+  GtkComboBoxPrivate *priv = GTK_COMBO_BOX (container)->priv;
+  GtkWidgetPath *path;
+  GtkWidget *widget;
+  gboolean found = FALSE;
+  GList *visible_children, *l;
+  GtkWidgetPath *sibling_path;
+  int pos;
+
+  path = _gtk_widget_create_path (GTK_WIDGET (container));
+
+  if (gtk_widget_get_visible (child))
+    {
+      visible_children = NULL;
+
+      if (priv->button && gtk_widget_get_visible (priv->button))
+        visible_children = g_list_prepend (visible_children, priv->button);
+
+      if (priv->cell_view_frame && gtk_widget_get_visible (priv->cell_view_frame))
+        visible_children = g_list_prepend (visible_children, priv->cell_view_frame);
+
+      widget = gtk_bin_get_child (GTK_BIN (container));
+      if (widget && gtk_widget_get_visible (widget))
+        visible_children = g_list_prepend (visible_children, widget);
+
+      if (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL)
+        visible_children = g_list_reverse (visible_children);
+
+      pos = 0;
+
+      for (l = visible_children; l; l = l->next)
+        {
+          widget = l->data;
+
+          if (widget == child)
+            {
+              found = TRUE;
+              break;
+            }
+
+          pos++;
+        }
+    }
+
+  if (found)
+    {
+      sibling_path = gtk_widget_path_new ();
+
+      for (l = visible_children; l; l = l->next)
+        gtk_widget_path_append_for_widget (sibling_path, l->data);
+
+      gtk_widget_path_append_with_siblings (path, sibling_path, pos);
+
+      g_list_free (visible_children);
+      gtk_widget_path_unref (sibling_path);
+    }
+  else
+    {
+      gtk_widget_path_append_for_widget (path, child);
+    }
+
+  return path;
+}
+
 static void
 gtk_combo_box_check_appearance (GtkComboBox *combo_box)
 {
@@ -1347,22 +1519,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));
@@ -1669,21 +1840,23 @@ gtk_combo_box_set_popup_widget (GtkComboBox *combo_box,
 }
 
 static void
-get_widget_border (GtkWidget *widget,
-                   GtkBorder *border)
+get_widget_padding_and_border (GtkWidget *widget,
+                               GtkBorder *padding)
 {
   GtkStyleContext *context;
-  GtkBorder *border_width;
+  GtkStateFlags state;
+  GtkBorder tmp;
 
   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);
+  gtk_style_context_get_padding (context, state, padding);
+  gtk_style_context_get_border (context, state, &tmp);
 
-  *border = *border_width;
-  gtk_border_free (border_width);
+  padding->top += tmp.top;
+  padding->right += tmp.right;
+  padding->bottom += tmp.bottom;
+  padding->left += tmp.left;
 }
 
 static void
@@ -1701,7 +1874,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));
@@ -1718,8 +1891,12 @@ 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_and_border (GTK_WIDGET (combo_box), &padding);
+
+  if (gtk_widget_get_direction (GTK_WIDGET (combo_box)) == GTK_TEXT_DIR_RTL)
+    sx += padding.left;
+  else
+    sx -= padding.left;
 
   if (combo_box->priv->popup_fixed_width)
     gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL);
@@ -1735,7 +1912,7 @@ gtk_combo_box_menu_position_below (GtkMenu  *menu,
   screen = gtk_widget_get_screen (GTK_WIDGET (combo_box));
   monitor_num = gdk_screen_get_monitor_at_window (screen,
                                                   gtk_widget_get_window (GTK_WIDGET (combo_box)));
-  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+  gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
 
   if (*x < monitor.x)
     *x = monitor.x;
@@ -1934,7 +2111,7 @@ gtk_combo_box_list_position (GtkComboBox *combo_box,
 
   screen = gtk_widget_get_screen (GTK_WIDGET (combo_box));
   monitor_num = gdk_screen_get_monitor_at_window (screen, window);
-  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+  gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
 
   if (gtk_widget_get_direction (GTK_WIDGET (combo_box)) == GTK_TEXT_DIR_RTL)
     *x = *x + allocation.width - *width;
@@ -2353,22 +2530,24 @@ gtk_combo_box_popdown (GtkComboBox *combo_box)
   priv->grab_keyboard = NULL;
 }
 
-#define GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON                                         \
-  gtk_widget_get_preferred_size (combo_box->priv->button,                        \
-                                 &req, NULL);                                         \
-                                                                                  \
-  if (is_rtl)                                                                         \
-    child.x = allocation->x + border.right;                                        \
-  else                                                                                \
-    child.x = allocation->x + allocation->width - req.width - border.left;        \
-                                                                                    \
-  child.y = allocation->y + border.top;                                                \
-  child.width = req.width;                                                        \
-  child.height = allocation->height - (border.top + border.bottom);                \
-  child.width = MAX (1, child.width);                                                \
-  child.height = MAX (1, child.height);                                                \
-                                                                                  \
-  gtk_widget_size_allocate (combo_box->priv->button, &child);
+#define GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON                      \
+  GtkAllocation button_allocation;                              \
+  gtk_widget_get_preferred_size (combo_box->priv->button,       \
+                                 &req, NULL);                   \
+                                                                \
+  if (is_rtl)                                                   \
+    button_allocation.x = allocation->x;                        \
+  else                                                          \
+    button_allocation.x = allocation->x + allocation->width     \
+     - req.width;                                               \
+                                                                \
+  button_allocation.y = allocation->y;                          \
+  button_allocation.width = MAX (1, req.width);                 \
+  button_allocation.height = allocation->height;                \
+  button_allocation.height = MAX (1, button_allocation.height); \
+                                                                \
+  gtk_widget_size_allocate (combo_box->priv->button,            \
+                            &button_allocation);
 
 
 static void
@@ -2378,41 +2557,37 @@ gtk_combo_box_size_allocate (GtkWidget     *widget,
   GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
   GtkComboBoxPrivate *priv = combo_box->priv;
   GtkWidget *child_widget;
-  gint focus_width, focus_pad;
   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_and_border (widget, &padding);
 
-  gtk_widget_style_get (widget,
-                        "focus-line-width", &focus_width,
-                        "focus-padding", &focus_pad,
-                        NULL);
+  allocation->x += padding.left;
+  allocation->y += padding.top;
+  allocation->width -= padding.left + padding.right;
+  allocation->height -= padding.top + padding.bottom;
 
   if (!priv->tree_view)
     {
       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;
+          border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->button));
+          get_widget_padding_and_border (priv->button, &button_padding);
 
+          /* menu mode; child_widget is priv->cell_view.
+           * Allocate the button to the full combobox allocation (minus the
+           * padding).
+           */
           gtk_widget_size_allocate (priv->button, allocation);
 
-          /* set some things ready */
-          border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->button));
-          get_widget_border (priv->button, &button_border);
-
           child.x = allocation->x;
           child.y = allocation->y;
           width = allocation->width;
@@ -2420,44 +2595,37 @@ 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;
-              width -= (2 * (border_width + focus_width + focus_pad)) +
-                button_border.left + button_border.right;
-              child.height -= (2 * (border_width + focus_width + focus_pad)) +
-                button_border.top + button_border.bottom;
+              /* restrict allocation of the child into the button box
+               * if we're not in cell renderer mode.
+               */
+              child.x += border_width + button_padding.left;
+              child.y += border_width + button_padding.top;
+              width -= 2 * border_width +
+                button_padding.left + button_padding.right;
+              child.height -= 2 * border_width +
+                button_padding.top + button_padding.bottom;
             }
 
-          /* handle the children */
-          gtk_widget_get_preferred_size (priv->arrow, &req, NULL);
+          /* allocate the box containing the separator and the arrow */
+          gtk_widget_get_preferred_size (priv->box, &req, NULL);
           child.width = req.width;
           if (!is_rtl)
             child.x += width - req.width;
           child.width = MAX (1, child.width);
           child.height = MAX (1, child.height);
-          gtk_widget_size_allocate (priv->arrow, &child);
-          if (is_rtl)
-            child.x += req.width;
-          gtk_widget_get_preferred_size (priv->separator, &req, NULL);
-          child.width = req.width;
-          if (!is_rtl)
-            child.x -= req.width;
-          child.width = MAX (1, child.width);
-          child.height = MAX (1, child.height);
-          gtk_widget_size_allocate (priv->separator, &child);
+          gtk_widget_size_allocate (priv->box, &child);
 
           if (is_rtl)
             {
               child.x += req.width;
               child.width = allocation->x + allocation->width
-                - (border_width + button_border.right + focus_width + focus_pad)
-                - child.x;
+                - border_width - child.x - button_padding.right;
             }
           else
             {
               child.width = child.x;
               child.x = allocation->x
-                + border_width + button_border.left + focus_width + focus_pad;
+                + border_width + button_padding.left;
               child.width -= child.x;
             }
 
@@ -2492,66 +2660,66 @@ gtk_combo_box_size_allocate (GtkWidget     *widget,
         }
       else
         {
+          /* menu mode; child_widget has been set with gtk_container_add().
+           * E.g. it might be a GtkEntry if priv->has_entry is TRUE.
+           * Allocate the button at the far end, according to the direction
+           * of the widget.
+           */
           GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON
 
+            /* After the macro, button_allocation has the button allocation rect */
+
           if (is_rtl)
-            child.x = allocation->x + req.width + border.right;
+            child.x = button_allocation.x + button_allocation.width;
           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;
+
+          child.y = allocation->y;
+          child.width = allocation->width - button_allocation.width;
+          child.height = button_allocation.height;
+
           child.width = MAX (1, child.width);
-          child.height = MAX (1, child.height);
+
           gtk_widget_size_allocate (child_widget, &child);
         }
     }
   else
     {
-      /* list mode */
-      guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
+      /* list mode; child_widget might be either priv->cell_view or a child
+       * added with gtk_container_add().
+       */
 
-      /* button */
+      /* After the macro, button_allocation has the button allocation rect */
       GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON
 
-      /* frame */
       if (is_rtl)
-        child.x = allocation->x + req.width;
+        child.x = button_allocation.x + button_allocation.width;
       else
         child.x = allocation->x;
 
       child.y = allocation->y;
-      child.width = allocation->width - req.width;
-      child.height = allocation->height;
+      child.width = allocation->width - button_allocation.width;
+      child.height = button_allocation.height;
 
       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));
           gtk_widget_size_allocate (priv->cell_view_frame, &child);
 
-          /* the sample */
+          /* restrict allocation of the child into the frame box if it's present */
           if (priv->has_frame)
             {
-              GtkBorder frame_border;
+              GtkBorder frame_padding;
+              guint border_width;
 
               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_and_border (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);
-        }
 
       if (gtk_widget_get_visible (priv->popup_window))
         {
@@ -2561,6 +2729,7 @@ gtk_combo_box_size_allocate (GtkWidget     *widget,
           gtk_widget_set_size_request (priv->popup_window, width, height);
         }
 
+      /* allocate the child */
       child.width = MAX (1, child.width);
       child.height = MAX (1, child.height);
       gtk_widget_size_allocate (child_widget, &child);
@@ -2655,11 +2824,8 @@ gtk_combo_box_draw (GtkWidget *widget,
   if (priv->shadow_type != GTK_SHADOW_NONE)
     {
       GtkStyleContext *context;
-      GtkStateFlags state;
 
       context = gtk_widget_get_style_context (widget);
-      state = gtk_widget_get_state_flags (widget);
-      gtk_style_context_set_state (context, state);
 
       gtk_render_background (context, cr, 0, 0,
                              gtk_widget_get_allocated_width (widget),
@@ -2974,6 +3140,7 @@ gtk_combo_box_menu_setup (GtkComboBox *combo_box,
 
       priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
       gtk_container_add (GTK_CONTAINER (priv->box), priv->arrow);
+      gtk_widget_add_events (priv->button, GDK_SCROLL_MASK);
 
       gtk_widget_show_all (priv->button);
     }
@@ -2990,6 +3157,7 @@ gtk_combo_box_menu_setup (GtkComboBox *combo_box,
 
       priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
       gtk_container_add (GTK_CONTAINER (priv->button), priv->arrow);
+      gtk_widget_add_events (priv->button, GDK_SCROLL_MASK);
       gtk_widget_show_all (priv->button);
     }
 
@@ -3024,8 +3192,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);
@@ -3072,7 +3238,7 @@ gtk_combo_box_menu_button_press (GtkWidget      *widget,
   GtkComboBoxPrivate *priv = combo_box->priv;
 
   if (GTK_IS_MENU (priv->popup_widget) &&
-      event->type == GDK_BUTTON_PRESS && event->button == 1)
+      event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_PRIMARY)
     {
       if (priv->focus_on_click &&
           !gtk_widget_has_focus (priv->button))
@@ -3277,17 +3443,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),
@@ -3739,13 +3901,15 @@ gtk_combo_box_list_select_func (GtkTreeSelection *selection,
                         NULL);
 
           if (cell_visible && cell_sensitive)
-            break;
+            {
+              sensitive = TRUE;
+              break;
+            }
 
           cell = cell->next;
         }
-      g_list_free (cells);
 
-      sensitive = cell_sensitive;
+      g_list_free (cells);
     }
 
   g_list_free (columns);
@@ -4521,7 +4685,6 @@ static void
 gtk_combo_box_entry_active_changed (GtkComboBox *combo_box,
                                     gpointer     user_data)
 {
-  GtkComboBoxPrivate *priv = combo_box->priv;
   GtkTreeModel *model;
   GtkTreeIter iter;
 
@@ -4531,26 +4694,58 @@ gtk_combo_box_entry_active_changed (GtkComboBox *combo_box,
 
       if (entry)
         {
-          GValue value = {0,};
+         GtkTreePath *path;
+         gchar       *path_str;
+         gchar       *text = NULL;
+
+          model    = gtk_combo_box_get_model (combo_box);
+         path     = gtk_tree_model_get_path (model, &iter);
+         path_str = gtk_tree_path_to_string (path);
 
           g_signal_handlers_block_by_func (entry,
                                            gtk_combo_box_entry_contents_changed,
                                            combo_box);
 
-          model = gtk_combo_box_get_model (combo_box);
 
-          gtk_tree_model_get_value (model, &iter,
-                                    priv->text_column, &value);
-          g_object_set_property (G_OBJECT (entry), "text", &value);
-          g_value_unset (&value);
+         g_signal_emit (combo_box, combo_box_signals[FORMAT_ENTRY_TEXT], 0, 
+                        path_str, &text);
+
+         gtk_entry_set_text (entry, text);
 
           g_signal_handlers_unblock_by_func (entry,
                                              gtk_combo_box_entry_contents_changed,
                                              combo_box);
+
+         gtk_tree_path_free (path);
+         g_free (text);
+         g_free (path_str);
         }
     }
 }
 
+static gchar *
+gtk_combo_box_format_entry_text (GtkComboBox     *combo_box,
+                                const gchar     *path)
+{
+  GtkComboBoxPrivate *priv = combo_box->priv;
+  GtkTreeModel       *model;
+  GtkTreeIter         iter;
+  gchar              *text = NULL;
+
+  if (priv->text_column >= 0)
+    {
+      model = gtk_combo_box_get_model (combo_box);
+      gtk_tree_model_get_iter_from_string (model, &iter, path);
+
+      gtk_tree_model_get (model, &iter,
+                         priv->text_column, &text,
+                         -1);
+    }
+
+  return text;
+}
+
+
 static GObject *
 gtk_combo_box_constructor (GType                  type,
                            guint                  n_construct_properties,
@@ -4559,7 +4754,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);
@@ -4582,17 +4776,18 @@ 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;
+      GtkStyleContext *context;
 
       entry = gtk_entry_new ();
       gtk_widget_show (entry);
       gtk_container_add (GTK_CONTAINER (combo_box), entry);
 
+      context = gtk_widget_get_style_context (GTK_WIDGET (combo_box));
+      gtk_style_context_add_class (context, GTK_STYLE_CLASS_COMBOBOX_ENTRY);
+
       priv->text_renderer = gtk_cell_renderer_text_new ();
       gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box),
                                   priv->text_renderer, TRUE);
@@ -4835,7 +5030,7 @@ gtk_combo_box_set_add_tearoffs (GtkComboBox *combo_box,
  *
  * Since: 2.10
  */
-G_CONST_RETURN gchar*
+const gchar*
 gtk_combo_box_get_title (GtkComboBox *combo_box)
 {
   g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), NULL);
@@ -5248,17 +5443,14 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget,
 {
   GtkComboBox           *combo_box = GTK_COMBO_BOX (widget);
   GtkComboBoxPrivate    *priv = combo_box->priv;
-  gint                   focus_width, focus_pad;
   gint                   font_size, arrow_size;
   PangoContext          *context;
   PangoFontMetrics      *metrics;
-  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));
 
@@ -5266,28 +5458,21 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget,
   gtk_widget_get_preferred_width (child, &child_min, &child_nat);
 
   gtk_widget_style_get (GTK_WIDGET (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_and_border (widget, &padding);
 
   context = gtk_widget_get_pango_context (GTK_WIDGET (widget));
-  metrics = pango_context_get_metrics (context, font_desc,
+  metrics = pango_context_get_metrics (context,
+                                       pango_context_get_font_description (context),
                                        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);
-  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);
 
@@ -5296,21 +5481,16 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget,
       /* menu mode */
       if (priv->cell_view)
         {
-          gint sep_width, arrow_width;
-          gint border_width, xpad;
-          GtkBorder button_border;
-
-          border_width = gtk_container_get_border_width (GTK_CONTAINER (combo_box));
-          get_widget_border (priv->button, &button_border);
+          gint box_width, xpad;
+          GtkBorder button_padding;
 
-          gtk_widget_get_preferred_width (priv->separator, &sep_width, NULL);
-          gtk_widget_get_preferred_width (priv->arrow, &arrow_width, NULL);
+          get_widget_padding_and_border (priv->button, &button_padding);
 
-          xpad = 2 * (border_width + focus_width + focus_pad) +
-            button_border.left + button_border.right;
+          gtk_widget_get_preferred_width (priv->box, &box_width, NULL);
+          xpad = 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;
+          minimum_width  = child_min + box_width + xpad;
+          natural_width  = child_nat + box_width + xpad;
         }
       else
         {
@@ -5332,19 +5512,16 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget,
       minimum_width = child_min;
       natural_width = child_nat;
 
-      minimum_width += 2 * focus_width;
-      natural_width += 2 * focus_width;
-
       if (priv->cell_view_frame)
         {
           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_and_border (priv->cell_view_frame, &frame_padding);
+              xpad = (2 * border_width) + frame_padding.left + frame_padding.right;
 
               minimum_width  += xpad;
               natural_width  += xpad;
@@ -5359,9 +5536,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;
@@ -5403,21 +5579,15 @@ gtk_combo_box_get_preferred_height_for_width (GtkWidget *widget,
 {
   GtkComboBox           *combo_box = GTK_COMBO_BOX (widget);
   GtkComboBoxPrivate    *priv = combo_box->priv;
-  gint                   focus_width, focus_pad;
   gint                   min_height = 0, nat_height = 0;
   gint                   size;
   GtkWidget             *child;
-  GtkBorder              border;
-
-  gtk_widget_style_get (GTK_WIDGET (widget),
-                        "focus-line-width", &focus_width,
-                        "focus-padding", &focus_pad,
-                        NULL);
+  GtkBorder              padding;
 
   child = gtk_bin_get_child (GTK_BIN (widget));
 
-  get_widget_border (widget, &border);
-  size = avail_size - border.left;
+  get_widget_padding_and_border (widget, &padding);
+  size = avail_size;
 
   if (!priv->tree_view)
     {
@@ -5425,34 +5595,27 @@ gtk_combo_box_get_preferred_height_for_width (GtkWidget *widget,
       if (priv->cell_view)
         {
           /* 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;
+          gint box_width, box_height;
+          gint xpad, ypad;
+          GtkBorder button_padding;
 
-          border_width = gtk_container_get_border_width (GTK_CONTAINER (combo_box));
-          get_widget_border (priv->button, &button_border);
+          get_widget_padding_and_border (priv->button, &button_padding);
 
-          gtk_widget_get_preferred_width (priv->separator, &sep_width, NULL);
-          gtk_widget_get_preferred_width (priv->arrow, &arrow_width, NULL);
-          gtk_widget_get_preferred_height_for_width (priv->separator,
-                                                     sep_width, &sep_height, NULL);
-          gtk_widget_get_preferred_height_for_width (priv->arrow,
-                                                     arrow_width, &arrow_height, NULL);
+          gtk_widget_get_preferred_width (priv->box, &box_width, NULL);
+          gtk_widget_get_preferred_height_for_width (priv->box,
+                                                     box_width, &box_height, NULL);
 
-          xpad = 2 * (border_width + focus_width + focus_pad) +
-            button_border.left + button_border.right;
-          ypad = 2 * (border_width + focus_width + focus_pad) +
-            button_border.top + button_border.bottom;
+          xpad = button_padding.left + button_padding.right;
+          ypad = button_padding.top + button_padding.bottom;
 
-          size -= sep_width + arrow_width + xpad;
+          size -= box_width + xpad;
 
           /* Get height-for-width of the child widget, usually a GtkCellArea calculating
            * and fitting the whole treemodel */
           gtk_widget_get_preferred_height_for_width (child, size, &min_height, &nat_height);
 
-          arrow_height = MAX (arrow_height, sep_height);
-          min_height = MAX (min_height, arrow_height);
-          nat_height = MAX (nat_height, arrow_height);
+          min_height = MAX (min_height, box_height);
+          nat_height = MAX (nat_height, box_height);
 
           min_height += ypad;
           nat_height += ypad;
@@ -5488,18 +5651,17 @@ 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_and_border (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;
-      size -= 2 * focus_width;
       size -= xpad;
 
       /* Get height-for-width of the child widget, usually a GtkCellArea calculating
@@ -5513,8 +5675,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;
@@ -5582,15 +5744,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
  *
@@ -5603,7 +5766,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;
 
@@ -5632,41 +5795,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)
@@ -5675,4 +5851,6 @@ gtk_combo_box_set_active_id (GtkComboBox *combo_box,
           break;
         }
     } while (gtk_tree_model_iter_next (model, &iter));
+
+    return match;
 }