+/**
+ * gtk_tree_selection_get_selected_rows:
+ * @selection: A #GtkTreeSelection.
+ * @model: (out) (allow-none) (transfer none): A pointer to set to the #GtkTreeModel, or %NULL.
+ *
+ * Creates a list of path of all selected rows. Additionally, if you are
+ * planning on modifying the model after calling this function, you may
+ * want to convert the returned list into a list of #GtkTreeRowReference<!-- -->s.
+ * To do this, you can use gtk_tree_row_reference_new().
+ *
+ * To free the return value, use:
+ * |[
+ * g_list_free_full (list, (GDestroyNotify) gtk_tree_path_free);
+ * ]|
+ *
+ * Return value: (element-type GtkTreePath) (transfer full): A #GList containing a #GtkTreePath for each selected row.
+ *
+ * Since: 2.2
+ **/
+GList *
+gtk_tree_selection_get_selected_rows (GtkTreeSelection *selection,
+ GtkTreeModel **model)
+{
+ GtkTreeSelectionPrivate *priv;
+ GList *list = NULL;
+ GtkRBTree *tree = NULL;
+ GtkRBNode *node = NULL;
+ GtkTreePath *path;
+
+ g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL);
+
+ priv = selection->priv;
+
+ g_return_val_if_fail (priv->tree_view != NULL, NULL);
+
+ if (model)
+ *model = gtk_tree_view_get_model (priv->tree_view);
+
+ tree = _gtk_tree_view_get_rbtree (priv->tree_view);
+
+ if (tree == NULL || tree->root == NULL)
+ return NULL;
+
+ if (priv->type == GTK_SELECTION_NONE)
+ return NULL;
+ else if (priv->type != GTK_SELECTION_MULTIPLE)
+ {
+ GtkTreeIter iter;
+
+ if (gtk_tree_selection_get_selected (selection, NULL, &iter))
+ {
+ GtkTreePath *path;
+
+ path = gtk_tree_model_get_path (gtk_tree_view_get_model (priv->tree_view), &iter);
+ list = g_list_append (list, path);
+
+ return list;
+ }
+
+ return NULL;
+ }
+
+ node = _gtk_rbtree_first (tree);
+ path = gtk_tree_path_new_first ();
+
+ do
+ {
+ if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
+ list = g_list_prepend (list, gtk_tree_path_copy (path));
+
+ if (node->children)
+ {
+ tree = node->children;
+ node = _gtk_rbtree_first (tree);
+
+ gtk_tree_path_append_index (path, 0);
+ }
+ else
+ {
+ gboolean done = FALSE;
+
+ do
+ {
+ node = _gtk_rbtree_next (tree, node);
+ if (node != NULL)
+ {
+ done = TRUE;
+ gtk_tree_path_next (path);
+ }
+ else
+ {
+ node = tree->parent_node;
+ tree = tree->parent_tree;
+
+ if (!tree)
+ {
+ gtk_tree_path_free (path);
+
+ goto done;
+ }
+
+ gtk_tree_path_up (path);
+ }
+ }
+ while (!done);
+ }
+ }
+ while (TRUE);
+
+ gtk_tree_path_free (path);
+
+ done:
+ return g_list_reverse (list);
+}
+
+static void
+gtk_tree_selection_count_selected_rows_helper (GtkRBTree *tree,
+ GtkRBNode *node,
+ gpointer data)
+{
+ gint *count = (gint *)data;
+
+ if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
+ (*count)++;
+
+ if (node->children)
+ _gtk_rbtree_traverse (node->children, node->children->root,
+ G_PRE_ORDER,
+ gtk_tree_selection_count_selected_rows_helper, data);
+}
+
+/**
+ * gtk_tree_selection_count_selected_rows:
+ * @selection: A #GtkTreeSelection.
+ *
+ * Returns the number of rows that have been selected in @tree.
+ *
+ * Return value: The number of rows selected.
+ *
+ * Since: 2.2
+ **/
+gint
+gtk_tree_selection_count_selected_rows (GtkTreeSelection *selection)
+{
+ GtkTreeSelectionPrivate *priv;
+ gint count = 0;
+ GtkRBTree *tree;
+
+ g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), 0);
+
+ priv = selection->priv;
+
+ g_return_val_if_fail (priv->tree_view != NULL, 0);
+
+ tree = _gtk_tree_view_get_rbtree (priv->tree_view);
+
+ if (tree == NULL || tree->root == NULL)
+ return 0;
+
+ if (priv->type == GTK_SELECTION_SINGLE ||
+ priv->type == GTK_SELECTION_BROWSE)
+ {
+ if (gtk_tree_selection_get_selected (selection, NULL, NULL))
+ return 1;
+ else
+ return 0;
+ }
+
+ _gtk_rbtree_traverse (tree, tree->root,
+ G_PRE_ORDER,
+ gtk_tree_selection_count_selected_rows_helper,
+ &count);
+
+ return count;
+}
+
+/* gtk_tree_selection_selected_foreach helper */
+static void
+model_changed (gpointer data)
+{
+ gboolean *stop = (gboolean *)data;
+
+ *stop = TRUE;
+}
+