+out:
+ gtk_combo_box_update_sensitivity (combo_box);
+
+ g_object_notify (G_OBJECT (combo_box), "model");
+}
+
+/**
+ * gtk_combo_box_get_model:
+ * @combo_box: A #GtkComboBox
+ *
+ * Returns the #GtkTreeModel which is acting as data source for @combo_box.
+ *
+ * Return value: (transfer none): A #GtkTreeModel which was passed
+ * during construction.
+ *
+ * Since: 2.4
+ */
+GtkTreeModel *
+gtk_combo_box_get_model (GtkComboBox *combo_box)
+{
+ g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), NULL);
+
+ return combo_box->priv->model;
+}
+
+static void
+gtk_combo_box_real_move_active (GtkComboBox *combo_box,
+ GtkScrollType scroll)
+{
+ GtkTreeIter iter;
+ GtkTreeIter new_iter;
+ gboolean active_iter;
+ gboolean found;
+
+ if (!combo_box->priv->model)
+ {
+ gtk_widget_error_bell (GTK_WIDGET (combo_box));
+ return;
+ }
+
+ active_iter = gtk_combo_box_get_active_iter (combo_box, &iter);
+
+ switch (scroll)
+ {
+ case GTK_SCROLL_STEP_BACKWARD:
+ case GTK_SCROLL_STEP_UP:
+ case GTK_SCROLL_STEP_LEFT:
+ if (active_iter)
+ {
+ found = tree_prev (combo_box, combo_box->priv->model,
+ &iter, &new_iter, FALSE);
+ break;
+ }
+ /* else fall through */
+
+ case GTK_SCROLL_PAGE_FORWARD:
+ case GTK_SCROLL_PAGE_DOWN:
+ case GTK_SCROLL_PAGE_RIGHT:
+ case GTK_SCROLL_END:
+ found = tree_last (combo_box, combo_box->priv->model, &new_iter, FALSE);
+ break;
+
+ case GTK_SCROLL_STEP_FORWARD:
+ case GTK_SCROLL_STEP_DOWN:
+ case GTK_SCROLL_STEP_RIGHT:
+ if (active_iter)
+ {
+ found = tree_next (combo_box, combo_box->priv->model,
+ &iter, &new_iter, FALSE);
+ break;
+ }
+ /* else fall through */
+
+ case GTK_SCROLL_PAGE_BACKWARD:
+ case GTK_SCROLL_PAGE_UP:
+ case GTK_SCROLL_PAGE_LEFT:
+ case GTK_SCROLL_START:
+ found = tree_first (combo_box, combo_box->priv->model, &new_iter, FALSE);
+ break;
+
+ default:
+ return;
+ }
+
+ if (found && active_iter)
+ {
+ GtkTreePath *old_path;
+ GtkTreePath *new_path;
+
+ old_path = gtk_tree_model_get_path (combo_box->priv->model, &iter);
+ new_path = gtk_tree_model_get_path (combo_box->priv->model, &new_iter);
+
+ if (gtk_tree_path_compare (old_path, new_path) == 0)
+ found = FALSE;
+
+ gtk_tree_path_free (old_path);
+ gtk_tree_path_free (new_path);
+ }
+
+ if (found)
+ {
+ gtk_combo_box_set_active_iter (combo_box, &new_iter);
+ }
+ else
+ {
+ gtk_widget_error_bell (GTK_WIDGET (combo_box));
+ }
+}
+
+static gboolean
+gtk_combo_box_mnemonic_activate (GtkWidget *widget,
+ gboolean group_cycling)
+{
+ GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
+
+ if (combo_box->priv->has_entry)
+ {
+ GtkWidget* child;
+
+ child = gtk_bin_get_child (GTK_BIN (combo_box));
+ if (child)
+ gtk_widget_grab_focus (child);
+ }
+ else
+ gtk_widget_grab_focus (combo_box->priv->button);
+
+ return TRUE;
+}
+
+static void
+gtk_combo_box_grab_focus (GtkWidget *widget)
+{
+ GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
+
+ if (combo_box->priv->has_entry)
+ {
+ GtkWidget *child;
+
+ child = gtk_bin_get_child (GTK_BIN (combo_box));
+ if (child)
+ gtk_widget_grab_focus (child);
+ }
+ else
+ gtk_widget_grab_focus (combo_box->priv->button);
+}
+
+static void
+gtk_combo_box_destroy (GtkWidget *widget)
+{
+ GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
+
+ if (combo_box->priv->popup_idle_id > 0)
+ {
+ g_source_remove (combo_box->priv->popup_idle_id);
+ combo_box->priv->popup_idle_id = 0;
+ }
+
+ gtk_combo_box_popdown (combo_box);
+
+ if (combo_box->priv->row_separator_destroy)
+ combo_box->priv->row_separator_destroy (combo_box->priv->row_separator_data);
+
+ combo_box->priv->row_separator_func = NULL;
+ combo_box->priv->row_separator_data = NULL;
+ combo_box->priv->row_separator_destroy = NULL;
+
+ GTK_WIDGET_CLASS (gtk_combo_box_parent_class)->destroy (widget);
+ combo_box->priv->cell_view = NULL;
+}
+
+static void
+gtk_combo_box_entry_contents_changed (GtkEntry *entry,
+ gpointer user_data)
+{
+ GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
+
+ /*
+ * Fixes regression reported in bug #574059. The old functionality relied on
+ * bug #572478. As a bugfix, we now emit the "changed" signal ourselves
+ * when the selection was already set to -1.
+ */
+ if (gtk_combo_box_get_active(combo_box) == -1)
+ g_signal_emit_by_name (combo_box, "changed");
+ else
+ gtk_combo_box_set_active (combo_box, -1);
+}
+
+static void
+gtk_combo_box_entry_active_changed (GtkComboBox *combo_box,
+ gpointer user_data)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ if (gtk_combo_box_get_active_iter (combo_box, &iter))
+ {
+ GtkEntry *entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (combo_box)));
+
+ if (entry)
+ {
+ 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);
+
+
+ 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,
+ GObjectConstructParam *construct_properties)
+{
+ GObject *object;
+ GtkComboBox *combo_box;
+ GtkComboBoxPrivate *priv;
+
+ object = G_OBJECT_CLASS (gtk_combo_box_parent_class)->constructor
+ (type, n_construct_properties, construct_properties);
+
+ combo_box = GTK_COMBO_BOX (object);
+ priv = combo_box->priv;
+
+ if (!priv->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);
+ gtk_cell_view_set_fit_model (GTK_CELL_VIEW (priv->cell_view), TRUE);
+ gtk_cell_view_set_model (GTK_CELL_VIEW (priv->cell_view), priv->model);
+ gtk_widget_set_parent (priv->cell_view, GTK_WIDGET (combo_box));
+ _gtk_bin_set_child (GTK_BIN (combo_box), priv->cell_view);
+ gtk_widget_show (priv->cell_view);
+
+ gtk_combo_box_check_appearance (combo_box);
+
+ 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);
+
+ gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), -1);
+
+ g_signal_connect (combo_box, "changed",
+ G_CALLBACK (gtk_combo_box_entry_active_changed), NULL);
+ }
+
+ return object;
+}
+
+
+static void
+gtk_combo_box_dispose(GObject* object)
+{
+ GtkComboBox *combo_box = GTK_COMBO_BOX (object);
+
+ if (GTK_IS_MENU (combo_box->priv->popup_widget))
+ {
+ gtk_combo_box_menu_destroy (combo_box);
+ gtk_menu_detach (GTK_MENU (combo_box->priv->popup_widget));
+ combo_box->priv->popup_widget = NULL;
+ }
+
+ if (combo_box->priv->area)
+ {
+ g_object_unref (combo_box->priv->area);
+ combo_box->priv->area = NULL;
+ }
+
+ if (GTK_IS_TREE_VIEW (combo_box->priv->tree_view))
+ gtk_combo_box_list_destroy (combo_box);
+
+ if (combo_box->priv->popup_window)
+ {
+ gtk_widget_destroy (combo_box->priv->popup_window);
+ combo_box->priv->popup_window = NULL;
+ }
+
+ gtk_combo_box_unset_model (combo_box);
+
+ G_OBJECT_CLASS (gtk_combo_box_parent_class)->dispose (object);
+}
+
+static void
+gtk_combo_box_finalize (GObject *object)
+{
+ GtkComboBox *combo_box = GTK_COMBO_BOX (object);
+
+ g_free (combo_box->priv->tearoff_title);
+
+ G_OBJECT_CLASS (gtk_combo_box_parent_class)->finalize (object);
+}
+
+static gboolean
+gtk_cell_editable_key_press (GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer data)
+{
+ GtkComboBox *combo_box = GTK_COMBO_BOX (data);
+
+ if (event->keyval == GDK_KEY_Escape)
+ {
+ 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));
+
+ return TRUE;
+ }
+ else if (event->keyval == GDK_KEY_Return ||
+ event->keyval == GDK_KEY_ISO_Enter ||
+ event->keyval == GDK_KEY_KP_Enter)
+ {
+ gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (combo_box));
+ gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (combo_box));
+
+ return TRUE;
+ }
+
+ return FALSE;