]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtktreemodel.c
Handle the case where the pointer isn't on the same screen as the widget
[~andy/gtk] / gtk / gtktreemodel.c
index e516b976038d409cce74fa46cc09631c25e4a91b..2c4a94a5390b68bc2b0193cca3cf9b77539f5bba 100644 (file)
 #include "gtktreeview.h"
 #include "gtktreeprivate.h"
 #include "gtkmarshalers.h"
-#include "gtksignal.h"
+
+
+#define INITIALIZE_TREE_ITER(Iter) \
+    G_STMT_START{ \
+      (Iter)->stamp = 0; \
+      (Iter)->user_data  = NULL; \
+      (Iter)->user_data2 = NULL; \
+      (Iter)->user_data3 = NULL; \
+    }G_STMT_END
+
+
+enum {
+  ROW_CHANGED,
+  ROW_INSERTED,
+  ROW_HAS_CHILD_TOGGLED,
+  ROW_DELETED,
+  ROWS_REORDERED,
+  LAST_SIGNAL
+};
+
+static guint tree_model_signals[LAST_SIGNAL] = { 0 };
 
 
 struct _GtkTreePath
@@ -38,10 +58,10 @@ struct _GtkTreePath
 static void gtk_tree_model_base_init (gpointer g_class);
 
 
-GtkType
+GType
 gtk_tree_model_get_type (void)
 {
-  static GtkType tree_model_type = 0;
+  static GType tree_model_type = 0;
 
   if (! tree_model_type)
     {
@@ -58,7 +78,10 @@ gtk_tree_model_get_type (void)
        NULL
       };
 
-      tree_model_type = g_type_register_static (G_TYPE_INTERFACE, "GtkTreeModel", &tree_model_info, 0);
+      tree_model_type =
+       g_type_register_static (G_TYPE_INTERFACE, "GtkTreeModel",
+                               &tree_model_info, 0);
+
       g_type_interface_add_prerequisite (tree_model_type, G_TYPE_OBJECT);
     }
 
@@ -72,51 +95,56 @@ gtk_tree_model_base_init (gpointer g_class)
 
   if (! initialized)
     {
-      g_signal_new ("row_changed",
-                    GTK_TYPE_TREE_MODEL,
-                    G_SIGNAL_RUN_LAST,
-                    G_STRUCT_OFFSET (GtkTreeModelIface, row_changed),
-                    NULL, NULL,
-                    _gtk_marshal_VOID__BOXED_BOXED,
-                    G_TYPE_NONE, 2,
-                    GTK_TYPE_TREE_PATH,
-                    GTK_TYPE_TREE_ITER);
-      g_signal_new ("row_inserted",
-                    GTK_TYPE_TREE_MODEL,
-                    G_SIGNAL_RUN_LAST,
-                    G_STRUCT_OFFSET (GtkTreeModelIface, row_inserted),
-                    NULL, NULL,
-                    _gtk_marshal_VOID__BOXED_BOXED,
-                    G_TYPE_NONE, 2,
-                    GTK_TYPE_TREE_PATH,
-                    GTK_TYPE_TREE_ITER);
-      g_signal_new ("row_has_child_toggled",
-                    GTK_TYPE_TREE_MODEL,
-                    G_SIGNAL_RUN_LAST,
-                    G_STRUCT_OFFSET (GtkTreeModelIface, row_has_child_toggled),
-                    NULL, NULL,
-                    _gtk_marshal_VOID__BOXED_BOXED,
-                    G_TYPE_NONE, 2,
-                    GTK_TYPE_TREE_PATH,
-                    GTK_TYPE_TREE_ITER);
-      g_signal_new ("row_deleted",
-                    GTK_TYPE_TREE_MODEL,
-                    G_SIGNAL_RUN_LAST,
-                    G_STRUCT_OFFSET (GtkTreeModelIface, row_deleted),
-                    NULL, NULL,
-                    _gtk_marshal_VOID__BOXED,
-                    G_TYPE_NONE, 1,
-                    GTK_TYPE_TREE_PATH);
-      g_signal_new ("rows_reordered",
-                    GTK_TYPE_TREE_MODEL,
-                    G_SIGNAL_RUN_LAST,
-                    G_STRUCT_OFFSET (GtkTreeModelIface, rows_reordered),
-                    NULL, NULL,
-                    _gtk_marshal_VOID__BOXED_BOXED_POINTER,
-                    G_TYPE_NONE, 3,
-                    GTK_TYPE_TREE_PATH,
-                    GTK_TYPE_TREE_ITER,
-                    G_TYPE_POINTER);
+      tree_model_signals[ROW_CHANGED] =
+        g_signal_new ("row_changed",
+                      GTK_TYPE_TREE_MODEL,
+                      G_SIGNAL_RUN_LAST,
+                      G_STRUCT_OFFSET (GtkTreeModelIface, row_changed),
+                      NULL, NULL,
+                      _gtk_marshal_VOID__BOXED_BOXED,
+                      G_TYPE_NONE, 2,
+                      GTK_TYPE_TREE_PATH,
+                      GTK_TYPE_TREE_ITER);
+      tree_model_signals[ROW_INSERTED] =
+        g_signal_new ("row_inserted",
+                      GTK_TYPE_TREE_MODEL,
+                      G_SIGNAL_RUN_LAST,
+                      G_STRUCT_OFFSET (GtkTreeModelIface, row_inserted),
+                      NULL, NULL,
+                      _gtk_marshal_VOID__BOXED_BOXED,
+                      G_TYPE_NONE, 2,
+                      GTK_TYPE_TREE_PATH,
+                      GTK_TYPE_TREE_ITER);
+      tree_model_signals[ROW_HAS_CHILD_TOGGLED] =
+        g_signal_new ("row_has_child_toggled",
+                      GTK_TYPE_TREE_MODEL,
+                      G_SIGNAL_RUN_LAST,
+                      G_STRUCT_OFFSET (GtkTreeModelIface, row_has_child_toggled),
+                      NULL, NULL,
+                      _gtk_marshal_VOID__BOXED_BOXED,
+                      G_TYPE_NONE, 2,
+                      GTK_TYPE_TREE_PATH,
+                      GTK_TYPE_TREE_ITER);
+      tree_model_signals[ROW_DELETED] =
+        g_signal_new ("row_deleted",
+                      GTK_TYPE_TREE_MODEL,
+                      G_SIGNAL_RUN_LAST,
+                      G_STRUCT_OFFSET (GtkTreeModelIface, row_deleted),
+                      NULL, NULL,
+                      _gtk_marshal_VOID__BOXED,
+                      G_TYPE_NONE, 1,
+                      GTK_TYPE_TREE_PATH);
+      tree_model_signals[ROWS_REORDERED] =
+        g_signal_new ("rows_reordered",
+                      GTK_TYPE_TREE_MODEL,
+                      G_SIGNAL_RUN_LAST,
+                      G_STRUCT_OFFSET (GtkTreeModelIface, rows_reordered),
+                      NULL, NULL,
+                      _gtk_marshal_VOID__BOXED_BOXED_POINTER,
+                      G_TYPE_NONE, 3,
+                      GTK_TYPE_TREE_PATH,
+                      GTK_TYPE_TREE_ITER,
+                      G_TYPE_POINTER);
       initialized = TRUE;
     }
 }
@@ -190,6 +218,41 @@ gtk_tree_path_new_from_string (const gchar *path)
   return retval;
 }
 
+/**
+ * gtk_tree_path_new_from_indices:
+ * @first_index: first integer
+ * @varargs: list of integers terminated by -1
+ *
+ * Creates a new path with @first_index and @varargs as indices.
+ *
+ * Return value: A newly created GtkTreePath.
+ *
+ * Since: 2.2
+ **/
+GtkTreePath *
+gtk_tree_path_new_from_indices (gint first_index,
+                               ...)
+{
+  int arg;
+  va_list args;
+  GtkTreePath *path;
+
+  path = gtk_tree_path_new ();
+
+  va_start (args, first_index);
+  arg = first_index;
+
+  while (arg != -1)
+    {
+      gtk_tree_path_append_index (path, arg);
+      arg = va_arg (args, gint);
+    }
+
+  va_end (args);
+
+  return path;
+}
+
 /**
  * gtk_tree_path_to_string:
  * @path: A #GtkTreePath
@@ -246,7 +309,7 @@ gtk_tree_path_new_first (void)
 /**
  * gtk_tree_path_append_index:
  * @path: A #GtkTreePath.
- * @index: The index.
+ * @index_: The index.
  *
  * Appends a new index to a path.  As a result, the depth of the path is
  * increased.
@@ -266,7 +329,7 @@ gtk_tree_path_append_index (GtkTreePath *path,
 /**
  * gtk_tree_path_prepend_index:
  * @path: A #GtkTreePath.
- * @index: The index.
+ * @index_: The index.
  *
  * Prepends a new index to a path.  As a result, the depth of the path is
  * increased.
@@ -275,7 +338,11 @@ void
 gtk_tree_path_prepend_index (GtkTreePath *path,
                             gint       index)
 {
-  gint *new_indices = g_new (gint, ++path->depth);
+  gint *new_indices;
+
+  (path->depth)++;
+  new_indices = g_new (gint, path->depth);
+
   if (path->indices == NULL)
     {
       path->indices = new_indices;
@@ -364,7 +431,7 @@ gtk_tree_path_get_type (void)
   static GType our_type = 0;
   
   if (our_type == 0)
-    our_type = g_boxed_type_register_static ("GtkTypeTreePath",
+    our_type = g_boxed_type_register_static ("GtkTreePath",
                                             (GBoxedCopyFunc) gtk_tree_path_copy,
                                             (GBoxedFreeFunc) gtk_tree_path_free);
 
@@ -588,7 +655,7 @@ gtk_tree_iter_get_type (void)
   static GType our_type = 0;
   
   if (our_type == 0)
-    our_type = g_boxed_type_register_static ("GtkTypeTreeIter",
+    our_type = g_boxed_type_register_static ("GtkTreeIter",
                                             (GBoxedCopyFunc) gtk_tree_iter_copy,
                                             (GBoxedFreeFunc) gtk_tree_iter_free);
 
@@ -636,7 +703,7 @@ gtk_tree_model_get_n_columns (GtkTreeModel *tree_model)
 /**
  * gtk_tree_model_get_column_type:
  * @tree_model: A #GtkTreeModel.
- * @index: The column index.
+ * @index_: The column index.
  *
  * Returns the type of the column.
  *
@@ -674,6 +741,8 @@ gtk_tree_model_get_iter (GtkTreeModel *tree_model,
   g_return_val_if_fail (GTK_TREE_MODEL_GET_IFACE (tree_model)->get_iter != NULL, FALSE);
   g_return_val_if_fail (path->depth > 0, FALSE);
 
+  INITIALIZE_TREE_ITER (iter);
+
   return (* GTK_TREE_MODEL_GET_IFACE (tree_model)->get_iter) (tree_model, iter, path);
 }
 
@@ -710,6 +779,38 @@ gtk_tree_model_get_iter_from_string (GtkTreeModel *tree_model,
   return retval;
 }
 
+/**
+ * gtk_tree_model_get_string_from_iter:
+ * @tree_model: A #GtkTreeModel.
+ * @iter: An #GtkTreeIter.
+ *
+ * Generates a string representation of the iter. This string is a ':'
+ * separated list of numbers. For example, "4:10:0:3" would be an
+ * acceptable return value for this string.
+ *
+ * Return value: A newly-allocated string. Must be freed with g_free().
+ *
+ * Since: 2.2
+ **/
+gchar *
+gtk_tree_model_get_string_from_iter (GtkTreeModel *tree_model,
+                                     GtkTreeIter  *iter)
+{
+  GtkTreePath *path;
+  gchar *ret;
+
+  g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), NULL);
+  g_return_val_if_fail (iter != NULL, NULL);
+
+  path = gtk_tree_model_get_path (tree_model, iter);
+
+  g_return_val_if_fail (path != NULL, NULL);
+
+  ret = gtk_tree_path_to_string (path);
+  gtk_tree_path_free (path);
+
+  return ret;
+}
 
 /**
  * gtk_tree_model_get_iter_first:
@@ -808,12 +909,15 @@ gtk_tree_model_iter_next (GtkTreeModel  *tree_model,
  * gtk_tree_model_iter_children:
  * @tree_model: A #GtkTreeModel.
  * @iter: The new #GtkTreeIter to be set to the child.
- * @parent: The #GtkTreeIter.
+ * @parent: The #GtkTreeIter, or %NULL
  *
  * Sets @iter to point to the first child of @parent.  If @parent has no children,
  * %FALSE is returned and @iter is set to be invalid.  @parent will remain a valid
  * node after this function has been called.
  *
+ * If @parent is %NULL returns the first node, equivalent to
+ * <literal>gtk_tree_model_get_iter_first (tree_model, iter);</literal>
+ *
  * Return value: %TRUE, if @child has been set to the first child.
  **/
 gboolean
@@ -825,6 +929,8 @@ gtk_tree_model_iter_children (GtkTreeModel *tree_model,
   g_return_val_if_fail (iter != NULL, FALSE);
   g_return_val_if_fail (GTK_TREE_MODEL_GET_IFACE (tree_model)->iter_children != NULL, FALSE);
 
+  INITIALIZE_TREE_ITER (iter);
+
   return (* GTK_TREE_MODEL_GET_IFACE (tree_model)->iter_children) (tree_model, iter, parent);
 }
 
@@ -876,12 +982,12 @@ gtk_tree_model_iter_n_children (GtkTreeModel *tree_model,
  * @n: Then index of the desired child.
  *
  * Sets @iter to be the child of @parent, using the given index.  The first
- * index is 0.  If @index is too big, or @parent has no children, @iter is set
+ * index is 0.  If @n is too big, or @parent has no children, @iter is set
  * to an invalid iterator and %FALSE is returned.  @parent will remain a valid
  * node after this function has been called.  As a special case, if @parent is
- * %NULL, then the @n<!>th root node is set.
+ * %NULL, then the @n<!-- -->th root node is set.
  *
- * Return value: %TRUE, if @parent has an @n<!>th child.
+ * Return value: %TRUE, if @parent has an @n<!-- -->th child.
  **/
 gboolean
 gtk_tree_model_iter_nth_child (GtkTreeModel *tree_model,
@@ -894,6 +1000,8 @@ gtk_tree_model_iter_nth_child (GtkTreeModel *tree_model,
   g_return_val_if_fail (n >= 0, FALSE);
   g_return_val_if_fail (GTK_TREE_MODEL_GET_IFACE (tree_model)->iter_nth_child != NULL, FALSE);
 
+  INITIALIZE_TREE_ITER (iter);
+
   return (* GTK_TREE_MODEL_GET_IFACE (tree_model)->iter_nth_child) (tree_model, iter, parent, n);
 }
 
@@ -920,6 +1028,8 @@ gtk_tree_model_iter_parent (GtkTreeModel *tree_model,
   g_return_val_if_fail (child != NULL, FALSE);
   g_return_val_if_fail (GTK_TREE_MODEL_GET_IFACE (tree_model)->iter_parent != NULL, FALSE);
 
+  INITIALIZE_TREE_ITER (iter);
+
   return (* GTK_TREE_MODEL_GET_IFACE (tree_model)->iter_parent) (tree_model, iter, child);
 }
 
@@ -1075,7 +1185,7 @@ gtk_tree_model_row_changed (GtkTreeModel *tree_model,
   g_return_if_fail (path != NULL);
   g_return_if_fail (iter != NULL);
 
-  g_signal_emit_by_name (tree_model, "row_changed", path, iter);
+  g_signal_emit (tree_model, tree_model_signals[ROW_CHANGED], 0, path, iter);
 }
 
 /**
@@ -1095,7 +1205,7 @@ gtk_tree_model_row_inserted (GtkTreeModel *tree_model,
   g_return_if_fail (path != NULL);
   g_return_if_fail (iter != NULL);
 
-  g_signal_emit_by_name (tree_model, "row_inserted", path, iter);
+  g_signal_emit (tree_model, tree_model_signals[ROW_INSERTED], 0, path, iter);
 }
 
 /**
@@ -1116,7 +1226,7 @@ gtk_tree_model_row_has_child_toggled (GtkTreeModel *tree_model,
   g_return_if_fail (path != NULL);
   g_return_if_fail (iter != NULL);
 
-  g_signal_emit_by_name (tree_model, "row_has_child_toggled", path, iter);
+  g_signal_emit (tree_model, tree_model_signals[ROW_HAS_CHILD_TOGGLED], 0, path, iter);
 }
 
 /**
@@ -1136,7 +1246,7 @@ gtk_tree_model_row_deleted (GtkTreeModel *tree_model,
   g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
   g_return_if_fail (path != NULL);
 
-  g_signal_emit_by_name (tree_model, "row_deleted", path);
+  g_signal_emit (tree_model, tree_model_signals[ROW_DELETED], 0, path);
 }
 
 /**
@@ -1160,7 +1270,7 @@ gtk_tree_model_rows_reordered (GtkTreeModel *tree_model,
   g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
   g_return_if_fail (new_order != NULL);
 
-  g_signal_emit_by_name (tree_model, "rows_reordered", path, iter, new_order);
+  g_signal_emit (tree_model, tree_model_signals[ROWS_REORDERED], 0, path, iter, new_order);
 }
 
 
@@ -1235,6 +1345,20 @@ static void gtk_tree_row_reference_unref_path (GtkTreePath  *path,
                                               gint          depth);
 
 
+GType
+gtk_tree_row_reference_get_type (void)
+{
+  static GType our_type = 0;
+  
+  if (our_type == 0)
+    our_type = g_boxed_type_register_static ("GtkTreeRowReference",
+                                            (GBoxedCopyFunc) gtk_tree_row_reference_copy,
+                                            (GBoxedFreeFunc) gtk_tree_row_reference_free);
+
+  return our_type;
+}
+
+
 #define ROW_REF_DATA_STRING "gtk-tree-row-refs"
 
 struct _GtkTreeRowReference
@@ -1368,7 +1492,14 @@ gtk_tree_row_ref_deleted_callback (GObject     *object,
          /* We know it affects us. */
          if (path->indices[i] == reference->path->indices[i])
            {
-             gtk_tree_row_reference_unref_path (reference->path, reference->model, reference->path->depth - 1);
+             if (reference->path->depth > path->depth)
+               /* some parent was deleted, trying to unref any node
+                * between the deleted parent and the node the reference
+                * is pointing to is bad, as those nodes are already gone.
+                */
+               gtk_tree_row_reference_unref_path (reference->path, reference->model, path->depth - 1);
+             else
+               gtk_tree_row_reference_unref_path (reference->path, reference->model, reference->path->depth - 1);
              gtk_tree_path_free (reference->path);
              reference->path = NULL;
            }
@@ -1438,17 +1569,17 @@ gtk_tree_row_ref_reordered_callback (GObject     *object,
 static void
 connect_ref_callbacks (GtkTreeModel *model)
 {
-  g_signal_connect (G_OBJECT (model),
+  g_signal_connect (model,
                    "row_inserted",
-                   (GCallback) gtk_tree_row_ref_inserted_callback,
+                   G_CALLBACK (gtk_tree_row_ref_inserted_callback),
                    model);
-  g_signal_connect (G_OBJECT (model),
+  g_signal_connect (model,
                    "row_deleted",
-                   (GCallback) gtk_tree_row_ref_deleted_callback,
+                   G_CALLBACK (gtk_tree_row_ref_deleted_callback),
                    model);
-  g_signal_connect (G_OBJECT (model),
+  g_signal_connect (model,
                    "rows_reordered",
-                   (GCallback) gtk_tree_row_ref_reordered_callback,
+                   G_CALLBACK (gtk_tree_row_ref_reordered_callback),
                    model);
 }
 
@@ -1489,20 +1620,20 @@ gtk_tree_row_reference_unref_path (GtkTreePath  *path,
 static void
 disconnect_ref_callbacks (GtkTreeModel *model)
 {
-  g_signal_handlers_disconnect_matched (G_OBJECT (model),
+  g_signal_handlers_disconnect_matched (model,
                                         G_SIGNAL_MATCH_FUNC,
                                         0, 0, NULL,
-                                       (gpointer) gtk_tree_row_ref_inserted_callback,
+                                       gtk_tree_row_ref_inserted_callback,
                                        NULL);
-  g_signal_handlers_disconnect_matched (G_OBJECT (model),
+  g_signal_handlers_disconnect_matched (model,
                                         G_SIGNAL_MATCH_FUNC,
                                         0, 0, NULL,
-                                       (gpointer) gtk_tree_row_ref_deleted_callback,
+                                       gtk_tree_row_ref_deleted_callback,
                                        NULL);
-  g_signal_handlers_disconnect_matched (G_OBJECT (model),
+  g_signal_handlers_disconnect_matched (model,
                                         G_SIGNAL_MATCH_FUNC,
                                         0, 0, NULL,
-                                       (gpointer) gtk_tree_row_ref_reordered_callback,
+                                       gtk_tree_row_ref_reordered_callback,
                                        NULL);
 }
 
@@ -1651,6 +1782,25 @@ gtk_tree_row_reference_valid (GtkTreeRowReference *reference)
   return TRUE;
 }
 
+
+/**
+ * gtk_tree_row_reference_copy:
+ * @reference: a #GtkTreeRowReference
+ * 
+ * Copies a #GtkTreeRowReference.
+ * 
+ * Return value: a copy of @reference.
+ *
+ * Since: 2.2
+ **/
+GtkTreeRowReference *
+gtk_tree_row_reference_copy (GtkTreeRowReference *reference)
+{
+  return gtk_tree_row_reference_new_proxy (reference->proxy,
+                                          reference->model,
+                                          reference->path);
+}
+
 /**
  * gtk_tree_row_reference_free:
  * @reference: A #GtkTreeRowReference, or NULL