Attachment 'gtk-tree-new-dnd-28oct2008.diff'

Download

   1 This is the latest patch of my GtkTreeView Drag and Drop rewrite that I
   2 have available. It is a work in progress and definitely not finished.
   3 Unfortunately, I noticed that testtreednd.c and gtktreemodelrowserializer.c
   4 are missing from the diff. It should not be hard to re-instantiate
   5 gtktreemodelrowserializer.c however.
   6 
   7 
   8 July 2012, Kristian Rietveld.
   9 
  10 diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
  11 index 8d13a99..fb3e6ce 100644
  12 --- a/gtk/gtk.symbols
  13 +++ b/gtk/gtk.symbols
  14 @@ -1830,8 +1830,10 @@ gtk_icon_view_set_spacing
  15  gtk_icon_view_set_text_column
  16  gtk_icon_view_unselect_all
  17  gtk_icon_view_unselect_path
  18 +#ifndef GTK_DISABLE_DEPRECATED
  19  gtk_icon_view_enable_model_drag_source
  20  gtk_icon_view_enable_model_drag_dest
  21 +#endif
  22  gtk_icon_view_unset_model_drag_source
  23  gtk_icon_view_unset_model_drag_dest
  24  gtk_icon_view_set_reorderable
  25 @@ -4509,10 +4511,8 @@ gtk_tree_view_set_tooltip_column
  26  gtk_tree_view_set_vadjustment
  27  #ifndef GTK_DISABLE_DEPRECATED
  28  gtk_tree_view_tree_to_widget_coords
  29 -#endif
  30  gtk_tree_view_unset_rows_drag_dest
  31  gtk_tree_view_unset_rows_drag_source
  32 -#ifndef GTK_DISABLE_DEPRECATED
  33  gtk_tree_view_widget_to_tree_coords
  34  #endif
  35  gtk_tree_view_columns_autosize
  36 diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c
  37 index 08c0c2f..18caf81 100644
  38 --- a/gtk/gtkfilechooserdefault.c
  39 +++ b/gtk/gtkfilechooserdefault.c
  40 @@ -3346,6 +3346,8 @@ shortcuts_drag_motion_cb (GtkWidget             *widget,
  41  
  42    g_signal_stop_emission_by_name (widget, "drag_motion");
  43  
  44 +  g_print ("action=%d\n", action);
  45 +
  46    if (action != 0)
  47      {
  48        gdk_drag_status (context, action, time_);
  49 diff --git a/gtk/gtkliststore.c b/gtk/gtkliststore.c
  50 index cb4c86d..fb2a9d7 100644
  51 --- a/gtk/gtkliststore.c
  52 +++ b/gtk/gtkliststore.c
  53 @@ -39,6 +39,7 @@ static void         gtk_list_store_drag_source_init(GtkTreeDragSourceIface *ifac
  54  static void         gtk_list_store_drag_dest_init  (GtkTreeDragDestIface   *iface);
  55  static void         gtk_list_store_sortable_init   (GtkTreeSortableIface   *iface);
  56  static void         gtk_list_store_buildable_init  (GtkBuildableIface      *iface);
  57 +static void         gtk_list_store_dnd_init        (GtkTreeModelDndIface   *iface);
  58  static void         gtk_list_store_finalize        (GObject           *object);
  59  static GtkTreeModelFlags gtk_list_store_get_flags  (GtkTreeModel      *tree_model);
  60  static gint         gtk_list_store_get_n_columns   (GtkTreeModel      *tree_model);
  61 @@ -132,6 +133,33 @@ static void     gtk_list_store_buildable_custom_tag_end (GtkBuildable *buildable
  62  							 const gchar  *tagname,
  63  							 gpointer     *data);
  64  
  65 +/* new drag and drop */
  66 +static void
  67 +gtk_list_store_dnd_add_serializer (GtkTreeModelDnd           *model_dnd,
  68 +                                   GtkTreeModelDndSerializer *serializer);
  69 +static void
  70 +gtk_list_store_dnd_remove_serializer (GtkTreeModelDnd           *model_dnd,
  71 +                                      GtkTreeModelDndSerializer *serializer);
  72 +static GtkTargetList *
  73 +gtk_list_store_dnd_get_targets (GtkTreeModelDnd *model_dnd);
  74 +static gboolean
  75 +gtk_list_store_dnd_serialize (GtkTreeModelDnd   *model_dnd,
  76 +                              GList             *row_refs,
  77 +                              GtkSelectionData  *selection_data);
  78 +static gboolean
  79 +gtk_list_store_dnd_deserialize (GtkTreeModelDnd         *model_dnd,
  80 +                                GtkTreePath             *path,
  81 +                                GtkTreeViewDropPosition  position,
  82 +                                GtkSelectionData        *selection_data);
  83 +static gboolean
  84 +gtk_list_store_dnd_delete_rows (GtkTreeModelDnd *model_dnd,
  85 +                                GList           *row_refs);
  86 +static gboolean
  87 +gtk_list_store_dnd_can_drop_rows (GtkTreeModelDnd         *model_dnd,
  88 +                                  GtkTreePath             *path,
  89 +                                  GtkTreeViewDropPosition  position);
  90 +
  91 +
  92  G_DEFINE_TYPE_WITH_CODE (GtkListStore, gtk_list_store, G_TYPE_OBJECT,
  93  			 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
  94  						gtk_list_store_tree_model_init)
  95 @@ -142,7 +170,9 @@ G_DEFINE_TYPE_WITH_CODE (GtkListStore, gtk_list_store, G_TYPE_OBJECT,
  96  			 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE,
  97  						gtk_list_store_sortable_init)
  98  			 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
  99 -						gtk_list_store_buildable_init))
 100 +						gtk_list_store_buildable_init)
 101 +                         G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL_DND,
 102 +                                                gtk_list_store_dnd_init))
 103  
 104  
 105  static void
 106 @@ -204,6 +234,18 @@ gtk_list_store_buildable_init (GtkBuildableIface *iface)
 107    iface->custom_tag_end = gtk_list_store_buildable_custom_tag_end;
 108  }
 109  
 110 +void
 111 +gtk_list_store_dnd_init (GtkTreeModelDndIface *iface)
 112 +{
 113 +  iface->add_serializer = gtk_list_store_dnd_add_serializer;
 114 +  iface->remove_serializer = gtk_list_store_dnd_remove_serializer;
 115 +  iface->get_targets = gtk_list_store_dnd_get_targets;
 116 +  iface->serialize = gtk_list_store_dnd_serialize;
 117 +  iface->deserialize = gtk_list_store_dnd_deserialize;
 118 +  iface->delete_rows = gtk_list_store_dnd_delete_rows;
 119 +  iface->can_drop_rows = gtk_list_store_dnd_can_drop_rows;
 120 +}
 121 +
 122  static void
 123  gtk_list_store_init (GtkListStore *list_store)
 124  {
 125 @@ -213,6 +255,7 @@ gtk_list_store_init (GtkListStore *list_store)
 126    list_store->sort_column_id = -2;
 127    list_store->columns_dirty = FALSE;
 128    list_store->length = 0;
 129 +  list_store->serializers = NULL;
 130  }
 131  
 132  /**
 133 @@ -2379,5 +2422,181 @@ gtk_list_store_buildable_custom_tag_end (GtkBuildable *buildable,
 134      g_warning ("Unknown custom list store tag: %s", tagname);
 135  }
 136  
 137 +
 138 +
 139 +
 140 +static void
 141 +gtk_list_store_dnd_add_serializer (GtkTreeModelDnd           *model_dnd,
 142 +                                   GtkTreeModelDndSerializer *serializer)
 143 +{
 144 +  GtkListStore *store;
 145 +
 146 +  /* FIXME: do proper ref counting */
 147 +  store = GTK_LIST_STORE (model_dnd);
 148 +  store->serializers = g_list_append (store->serializers, serializer);
 149 +}
 150 +
 151 +static void
 152 +gtk_list_store_dnd_remove_serializer (GtkTreeModelDnd           *model_dnd,
 153 +                                      GtkTreeModelDndSerializer *serializer)
 154 +{
 155 +  GtkListStore *store;
 156 +
 157 +  /* FIXME: do proper ref counting */
 158 +  store = GTK_LIST_STORE (model_dnd);
 159 +  store->serializers = g_list_remove (store->serializers, serializer);
 160 +}
 161 +
 162 +
 163 +static GtkTargetList *
 164 +gtk_list_store_dnd_get_targets (GtkTreeModelDnd *model_dnd)
 165 +{
 166 +  GList *list;
 167 +  GtkListStore *store;
 168 +  GtkTargetList *targets;
 169 +
 170 +  store = GTK_LIST_STORE (model_dnd);
 171 +
 172 +  targets = gtk_target_list_new (NULL, 0);
 173 +  for (list = store->serializers; list; list = list->next)
 174 +    gtk_tree_model_dnd_serializer_add_targets (list->data,
 175 +                                               model_dnd,
 176 +                                               targets);
 177 +
 178 +  return targets;
 179 +}
 180 +
 181 +static gboolean
 182 +gtk_list_store_dnd_serialize (GtkTreeModelDnd   *model_dnd,
 183 +                              GList             *row_refs,
 184 +                              GtkSelectionData  *selection_data)
 185 +{
 186 +  gboolean retval = FALSE;
 187 +  GList *list;
 188 +  GList *paths = NULL;
 189 +  GtkListStore *store;
 190 +  GtkTreeModelDndSerializer *serializer;
 191 +
 192 +  store = GTK_LIST_STORE (model_dnd);
 193 +
 194 +  serializer = gtk_tree_model_dnd_find_serializer (store->serializers,
 195 +                                                   selection_data->target);
 196 +  if (!serializer)
 197 +    return FALSE;
 198 +
 199 +  for (list = row_refs; list; list = list->next)
 200 +    {
 201 +      GtkTreePath *path;
 202 +
 203 +      path = gtk_tree_row_reference_get_path (list->data);
 204 +      paths = g_list_append (paths, path);
 205 +    }
 206 +
 207 +  retval = gtk_tree_model_dnd_serializer_serialize (serializer,
 208 +                                                    model_dnd,
 209 +                                                    selection_data,
 210 +                                                    paths);
 211 +
 212 +  g_list_foreach (paths, (GFunc)gtk_tree_path_free, NULL);
 213 +  g_list_free (paths);
 214 +
 215 +  return retval;
 216 +}
 217 +
 218 +static gboolean
 219 +gtk_list_store_dnd_deserialize (GtkTreeModelDnd         *model_dnd,
 220 +                                GtkTreePath             *path,
 221 +                                GtkTreeViewDropPosition  position,
 222 +                                GtkSelectionData        *selection_data)
 223 +{
 224 +  int i = 0;
 225 +  int count;
 226 +  GList *paths = NULL;
 227 +  gboolean retval = FALSE;
 228 +  GtkTreeIter iter;
 229 +  GtkListStore *store;
 230 +  GtkTreeModelDndSerializer *serializer;
 231 +
 232 +  store = GTK_LIST_STORE (model_dnd);
 233 +
 234 +  if (position == GTK_TREE_VIEW_DROP_INVALID)
 235 +    return FALSE;
 236 +
 237 +  serializer = gtk_tree_model_dnd_find_serializer (store->serializers,
 238 +                                                   selection_data->target);
 239 +  if (!serializer)
 240 +    return FALSE;
 241 +
 242 +  count = gtk_tree_model_dnd_serializer_get_count (serializer,
 243 +                                                   selection_data);
 244 +
 245 +  if (count < 0)
 246 +    return FALSE;
 247 +
 248 +  /* Build a list of destination paths */
 249 +  if (position != GTK_TREE_VIEW_DROP_EMPTY_SPACE)
 250 +    gtk_tree_model_get_iter (GTK_TREE_MODEL (model_dnd), &iter, path);
 251 +
 252 +  for (i = 0; i < count; i++)
 253 +    {
 254 +      GtkTreeIter new_iter;
 255 +      GtkTreePath *new_path;
 256 +
 257 +      if (position == GTK_TREE_VIEW_DROP_BEFORE && i == 0)
 258 +        gtk_list_store_insert_before (GTK_LIST_STORE (model_dnd),
 259 +                                      &new_iter, &iter);
 260 +      else if (position == GTK_TREE_VIEW_DROP_EMPTY_SPACE)
 261 +        gtk_list_store_append (GTK_LIST_STORE (model_dnd), &new_iter);
 262 +      else
 263 +        gtk_list_store_insert_after (GTK_LIST_STORE (model_dnd),
 264 +                                     &new_iter, &iter);
 265 +
 266 +      iter = new_iter;
 267 +
 268 +      new_path = gtk_tree_model_get_path (GTK_TREE_MODEL (model_dnd), &iter);
 269 +      paths = g_list_append (paths, new_path);
 270 +    }
 271 +
 272 +  retval = gtk_tree_model_dnd_serializer_deserialize (serializer,
 273 +                                                      model_dnd,
 274 +                                                      selection_data,
 275 +                                                      paths);
 276 +
 277 +  g_list_foreach (paths, (GFunc)gtk_tree_path_free, NULL);
 278 +  g_list_free (paths);
 279 +
 280 +  return retval;
 281 +}
 282 +
 283 +static gboolean
 284 +gtk_list_store_dnd_delete_rows (GtkTreeModelDnd *model_dnd,
 285 +                                GList           *row_refs)
 286 +{
 287 +  GList *list;
 288 +  GtkListStore *store = GTK_LIST_STORE (model_dnd);
 289 +
 290 +  for (list = row_refs; list; list = list->next)
 291 +    {
 292 +      GtkTreePath *path;
 293 +      GtkTreeIter iter;
 294 +
 295 +      path = gtk_tree_row_reference_get_path (list->data);
 296 +      gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
 297 +      gtk_list_store_remove (store, &iter);
 298 +      gtk_tree_path_free (path);
 299 +    }
 300 +
 301 +  return TRUE;
 302 +}
 303 +
 304 +static gboolean
 305 +gtk_list_store_dnd_can_drop_rows (GtkTreeModelDnd         *model_dnd,
 306 +                                  GtkTreePath             *path,
 307 +                                  GtkTreeViewDropPosition  position)
 308 +{
 309 +  return TRUE;
 310 +}
 311 +
 312 +
 313  #define __GTK_LIST_STORE_C__
 314  #include "gtkaliasdef.c"
 315 diff --git a/gtk/gtkliststore.h b/gtk/gtkliststore.h
 316 index 6de426e..7393d72 100644
 317 --- a/gtk/gtkliststore.h
 318 +++ b/gtk/gtkliststore.h
 319 @@ -60,6 +60,9 @@ struct _GtkListStore
 320    gpointer GSEAL (default_sort_data);
 321    GDestroyNotify GSEAL (default_sort_destroy);
 322    guint GSEAL (columns_dirty) : 1;
 323 +
 324 +  /* FIXME: I break ABI for now, fix this later */
 325 +  GList *serializers;
 326  };
 327  
 328  struct _GtkListStoreClass
 329 diff --git a/gtk/gtkmarshalers.list b/gtk/gtkmarshalers.list
 330 index f952bd1..e6b0b57 100644
 331 --- a/gtk/gtkmarshalers.list
 332 +++ b/gtk/gtkmarshalers.list
 333 @@ -33,6 +33,7 @@ BOOLEAN:OBJECT,INT,INT,UINT
 334  BOOLEAN:OBJECT,STRING,STRING,BOXED
 335  BOOLEAN:OBJECT,BOXED
 336  BOOLEAN:OBJECT,BOXED,BOXED
 337 +BOOLEAN:OBJECT,BOXED,ENUM,POINTER,POINTER
 338  BOOLEAN:OBJECT,OBJECT,OBJECT
 339  BOOLEAN:OBJECT,STRING,STRING
 340  BOOLEAN:OBJECT,ENUM
 341 @@ -45,6 +46,7 @@ BOOLEAN:VOID
 342  BOOLEAN:BOOLEAN
 343  BOOLEAN:NONE
 344  BOOLEAN:BOOLEAN,BOOLEAN,BOOLEAN
 345 +BOOLEAN:POINTER,INT,POINTER,POINTER
 346  BOOLEAN:STRING
 347  ENUM:ENUM
 348  ENUM:VOID
 349 diff --git a/gtk/gtktreednd.c b/gtk/gtktreednd.c
 350 index 7e07945..3aa77e4 100644
 351 --- a/gtk/gtktreednd.c
 352 +++ b/gtk/gtktreednd.c
 353 @@ -331,5 +331,247 @@ gtk_tree_get_row_drag_data (GtkSelectionData  *selection_data,
 354    return TRUE;
 355  }
 356  
 357 +
 358 +
 359 +
 360 +GType
 361 +gtk_tree_model_dnd_serializer_get_type (void)
 362 +{
 363 +  static GType our_type = 0;
 364 +
 365 +  if (!our_type)
 366 +    {
 367 +      const GTypeInfo our_info =
 368 +        {
 369 +          sizeof (GtkTreeModelDndSerializerIface), /* class_size */
 370 +          NULL,		/* base_init */
 371 +          NULL,		/* base_finalize */
 372 +          NULL,
 373 +          NULL,		/* class_finalize */
 374 +          NULL,		/* class_data */
 375 +          0,
 376 +          0,              /* n_preallocs */
 377 +          NULL
 378 +        };
 379 +
 380 +      our_type = g_type_register_static (G_TYPE_INTERFACE,
 381 +                                         I_("GtkTreeModelDndSerializer"),
 382 +                                         &our_info, 0);
 383 +    }
 384 +
 385 +  return our_type;
 386 +}
 387 +
 388 +
 389 +
 390 +void
 391 +gtk_tree_model_dnd_serializer_add_targets (GtkTreeModelDndSerializer *serializer,
 392 +                                           GtkTreeModelDnd           *model_dnd,
 393 +                                           GtkTargetList             *targets)
 394 +{
 395 +  GtkTreeModelDndSerializerIface *iface = GTK_TREE_MODEL_DND_SERIALIZER_GET_IFACE (serializer);
 396 +
 397 +  g_return_if_fail (GTK_IS_TREE_MODEL_DND_SERIALIZER (serializer));
 398 +  g_return_if_fail (GTK_IS_TREE_MODEL_DND (model_dnd));
 399 +  g_return_if_fail (iface->add_targets != NULL);
 400 +
 401 +  return (* iface->add_targets) (serializer, model_dnd, targets);
 402 +}
 403 +
 404 +gboolean
 405 +gtk_tree_model_dnd_serializer_supports_target (GtkTreeModelDndSerializer *serializer,
 406 +                                               GdkAtom                    target)
 407 +{
 408 +  GtkTreeModelDndSerializerIface *iface = GTK_TREE_MODEL_DND_SERIALIZER_GET_IFACE (serializer);
 409 +
 410 +  g_return_val_if_fail (GTK_IS_TREE_MODEL_DND_SERIALIZER (serializer), FALSE);
 411 +  g_return_val_if_fail (iface->supports_target != NULL, FALSE);
 412 +
 413 +  return (* iface->supports_target) (serializer, target);
 414 +}
 415 +
 416 +int
 417 +gtk_tree_model_dnd_serializer_get_count (GtkTreeModelDndSerializer *serializer,
 418 +                                         GtkSelectionData          *selection_data)
 419 +{
 420 +  GtkTreeModelDndSerializerIface *iface = GTK_TREE_MODEL_DND_SERIALIZER_GET_IFACE (serializer);
 421 +
 422 +  g_return_val_if_fail (GTK_IS_TREE_MODEL_DND_SERIALIZER (serializer), 0);
 423 +  g_return_val_if_fail (selection_data != NULL, 0);
 424 +  g_return_val_if_fail (iface->get_count != NULL, 0);
 425 +
 426 +  return (* iface->get_count) (serializer, selection_data);
 427 +}
 428 +
 429 +gboolean
 430 +gtk_tree_model_dnd_serializer_serialize (GtkTreeModelDndSerializer *serializer,
 431 +                                         GtkTreeModelDnd           *model_dnd,
 432 +                                         GtkSelectionData          *selection_data,
 433 +                                         GList                     *paths)
 434 +{
 435 +  GtkTreeModelDndSerializerIface *iface = GTK_TREE_MODEL_DND_SERIALIZER_GET_IFACE (serializer);
 436 +
 437 +  g_return_val_if_fail (GTK_IS_TREE_MODEL_DND_SERIALIZER (serializer), FALSE);
 438 +  g_return_val_if_fail (GTK_IS_TREE_MODEL_DND (model_dnd), FALSE);
 439 +  g_return_val_if_fail (selection_data != NULL, FALSE);
 440 +  g_return_val_if_fail (paths != NULL, FALSE);
 441 +  g_return_val_if_fail (iface->serialize != NULL, FALSE);
 442 +
 443 +  return (* iface->serialize) (serializer, model_dnd, selection_data, paths);
 444 +}
 445 +
 446 +gboolean
 447 +gtk_tree_model_dnd_serializer_deserialize (GtkTreeModelDndSerializer *serializer,
 448 +                                           GtkTreeModelDnd           *model_dnd,
 449 +                                           GtkSelectionData          *selection_data,
 450 +                                           GList                     *paths)
 451 +{
 452 +  GtkTreeModelDndSerializerIface *iface = GTK_TREE_MODEL_DND_SERIALIZER_GET_IFACE (serializer);
 453 +
 454 +  g_return_val_if_fail (GTK_IS_TREE_MODEL_DND_SERIALIZER (serializer), FALSE);
 455 +  g_return_val_if_fail (GTK_IS_TREE_MODEL_DND (model_dnd), FALSE);
 456 +  g_return_val_if_fail (selection_data != NULL, FALSE);
 457 +  g_return_val_if_fail (paths != NULL, FALSE);
 458 +  g_return_val_if_fail (iface->deserialize != NULL, FALSE);
 459 +
 460 +  return (* iface->deserialize) (serializer, model_dnd, selection_data, paths);
 461 +}
 462 +
 463 +GtkTreeModelDndSerializer *
 464 +gtk_tree_model_dnd_find_serializer (GList   *serializers,
 465 +                                    GdkAtom  target)
 466 +{
 467 +  GList *list;
 468 +
 469 +  for (list = serializers; list; list = list->next)
 470 +    if (gtk_tree_model_dnd_serializer_supports_target (list->data, target))
 471 +      return list->data;
 472 +
 473 +  return NULL;
 474 +}
 475 +
 476 +
 477 +
 478 +GType
 479 +gtk_tree_model_dnd_get_type (void)
 480 +{
 481 +  static GType our_type = 0;
 482 +
 483 +  if (!our_type)
 484 +    {
 485 +      const GTypeInfo our_info =
 486 +        {
 487 +          sizeof (GtkTreeModelDndIface), /* class_size */
 488 +          NULL,		/* base_init */
 489 +          NULL,		/* base_finalize */
 490 +          NULL,
 491 +          NULL,		/* class_finalize */
 492 +          NULL,		/* class_data */
 493 +          0,
 494 +          0,              /* n_preallocs */
 495 +          NULL
 496 +        };
 497 +
 498 +      our_type = g_type_register_static (G_TYPE_INTERFACE,
 499 +                                         I_("GtkTreeModelDnd"),
 500 +                                         &our_info, 0);
 501 +    }
 502 +
 503 +  return our_type;
 504 +}
 505 +
 506 +
 507 +void
 508 +gtk_tree_model_dnd_add_serializer (GtkTreeModelDnd           *model_dnd,
 509 +                                   GtkTreeModelDndSerializer *serializer)
 510 +{
 511 +  GtkTreeModelDndIface *iface = GTK_TREE_MODEL_DND_GET_IFACE (model_dnd);
 512 +
 513 +  g_return_if_fail (GTK_IS_TREE_MODEL_DND (model_dnd));
 514 +  g_return_if_fail (GTK_IS_TREE_MODEL_DND_SERIALIZER (serializer));
 515 +  g_return_if_fail (iface->add_serializer != NULL);
 516 +
 517 +  return (* iface->add_serializer) (model_dnd, serializer);
 518 +}
 519 +
 520 +void
 521 +gtk_tree_model_dnd_remove_serializer (GtkTreeModelDnd           *model_dnd,
 522 +                                      GtkTreeModelDndSerializer *serializer)
 523 +{
 524 +  GtkTreeModelDndIface *iface = GTK_TREE_MODEL_DND_GET_IFACE (model_dnd);
 525 +
 526 +  g_return_if_fail (GTK_IS_TREE_MODEL_DND (model_dnd));
 527 +  g_return_if_fail (GTK_IS_TREE_MODEL_DND_SERIALIZER (serializer));
 528 +  g_return_if_fail (iface->remove_serializer != NULL);
 529 +
 530 +  return (* iface->remove_serializer) (model_dnd, serializer);
 531 +}
 532 +
 533 +
 534 +GtkTargetList *
 535 +gtk_tree_model_dnd_get_targets (GtkTreeModelDnd *model_dnd)
 536 +{
 537 +  GtkTreeModelDndIface *iface = GTK_TREE_MODEL_DND_GET_IFACE (model_dnd);
 538 +
 539 +  g_return_val_if_fail (GTK_IS_TREE_MODEL_DND (model_dnd), NULL);
 540 +  g_return_val_if_fail (iface->get_targets != NULL, NULL);
 541 +
 542 +  return (* iface->get_targets) (model_dnd);
 543 +}
 544 +
 545 +gboolean
 546 +gtk_tree_model_dnd_serialize (GtkTreeModelDnd  *model_dnd,
 547 +                              GList            *row_refs,
 548 +                              GtkSelectionData *selection_data)
 549 +{
 550 +  GtkTreeModelDndIface *iface = GTK_TREE_MODEL_DND_GET_IFACE (model_dnd);
 551 +
 552 +  g_return_val_if_fail (GTK_IS_TREE_MODEL_DND (model_dnd), FALSE);
 553 +  g_return_val_if_fail (iface->serialize != NULL, FALSE);
 554 +
 555 +  return (* iface->serialize) (model_dnd, row_refs, selection_data);
 556 +}
 557 +
 558 +gboolean
 559 +gtk_tree_model_dnd_deserialize (GtkTreeModelDnd         *model_dnd,
 560 +                                GtkTreePath             *path,
 561 +                                GtkTreeViewDropPosition  position,
 562 +                                GtkSelectionData        *selection_data)
 563 +{
 564 +  GtkTreeModelDndIface *iface = GTK_TREE_MODEL_DND_GET_IFACE (model_dnd);
 565 +
 566 +  g_return_val_if_fail (GTK_IS_TREE_MODEL_DND (model_dnd), FALSE);
 567 +  g_return_val_if_fail (iface->deserialize != NULL, FALSE);
 568 +
 569 +  return (* iface->deserialize) (model_dnd, path, position, selection_data);
 570 +}
 571 +
 572 +
 573 +gboolean
 574 +gtk_tree_model_dnd_delete_rows (GtkTreeModelDnd  *model_dnd,
 575 +                                GList            *row_refs)
 576 +{
 577 +  GtkTreeModelDndIface *iface = GTK_TREE_MODEL_DND_GET_IFACE (model_dnd);
 578 +
 579 +  g_return_val_if_fail (GTK_IS_TREE_MODEL_DND (model_dnd), FALSE);
 580 +  g_return_val_if_fail (iface->delete_rows != NULL, FALSE);
 581 +
 582 +  return (* iface->delete_rows) (model_dnd, row_refs);
 583 +}
 584 +
 585 +gboolean
 586 +gtk_tree_model_dnd_can_drop_rows (GtkTreeModelDnd         *model_dnd,
 587 +                                  GtkTreePath             *path,
 588 +                                  GtkTreeViewDropPosition  position)
 589 +{
 590 +  GtkTreeModelDndIface *iface = GTK_TREE_MODEL_DND_GET_IFACE (model_dnd);
 591 +
 592 +  g_return_val_if_fail (GTK_IS_TREE_MODEL_DND (model_dnd), FALSE);
 593 +  g_return_val_if_fail (iface->can_drop_rows != NULL, FALSE);
 594 +
 595 +  return (* iface->can_drop_rows) (model_dnd, path, position);
 596 +}
 597 +
 598 +
 599  #define __GTK_TREE_DND_C__
 600  #include "gtkaliasdef.c"
 601 diff --git a/gtk/gtktreednd.h b/gtk/gtktreednd.h
 602 index 517ba50..85c6dc3 100644
 603 --- a/gtk/gtktreednd.h
 604 +++ b/gtk/gtktreednd.h
 605 @@ -26,6 +26,7 @@
 606  
 607  #include <gtk/gtktreemodel.h>
 608  #include <gtk/gtkdnd.h>
 609 +#include <gtk/gtktreeview.h>
 610  
 611  G_BEGIN_DECLS
 612  
 613 @@ -110,6 +111,135 @@ gboolean gtk_tree_drag_dest_row_drop_possible  (GtkTreeDragDest   *drag_dest,
 614  						GtkSelectionData  *selection_data);
 615  
 616  
 617 +/* New drag and drop interface */
 618 +
 619 +#define GTK_TYPE_TREE_MODEL_DND_SERIALIZER            (gtk_tree_model_dnd_serializer_get_type ())
 620 +#define GTK_TREE_MODEL_DND_SERIALIZER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_TREE_MODEL_DND_SERIALIZER, GtkTreeModelDndSerializer))
 621 +#define GTK_IS_TREE_MODEL_DND_SERIALIZER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_TREE_MODEL_DND_SERIALIZER))
 622 +#define GTK_TREE_MODEL_DND_SERIALIZER_GET_IFACE(obj)  (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GTK_TYPE_TREE_MODEL_DND_SERIALIZER, GtkTreeModelDndSerializerIface))
 623 +
 624 +typedef struct _GtkTreeModelDndSerializer      GtkTreeModelDndSerializer; /* Dummy typedef */
 625 +typedef struct _GtkTreeModelDndSerializerIface GtkTreeModelDndSerializerIface;
 626 +
 627 +
 628 +#define GTK_TYPE_TREE_MODEL_DND            (gtk_tree_model_dnd_get_type ())
 629 +#define GTK_TREE_MODEL_DND(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_TREE_MODEL_DND, GtkTreeModelDnd))
 630 +#define GTK_IS_TREE_MODEL_DND(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_TREE_MODEL_DND))
 631 +#define GTK_TREE_MODEL_DND_GET_IFACE(obj)  (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GTK_TYPE_TREE_MODEL_DND, GtkTreeModelDndIface))
 632 +
 633 +typedef struct _GtkTreeModelDnd      GtkTreeModelDnd; /* Dummy typedef */
 634 +typedef struct _GtkTreeModelDndIface GtkTreeModelDndIface;
 635 +
 636 +
 637 +struct _GtkTreeModelDndSerializerIface
 638 +{
 639 +  GTypeInterface g_iface;
 640 +
 641 +  void     (* add_targets)     (GtkTreeModelDndSerializer *serializer,
 642 +                                GtkTreeModelDnd           *model_dnd,
 643 +                                GtkTargetList             *targets);
 644 +
 645 +  gboolean (* supports_target) (GtkTreeModelDndSerializer *serializer,
 646 +                                GdkAtom                    target);
 647 +
 648 +  int      (* get_count)       (GtkTreeModelDndSerializer *serializer,
 649 +                                GtkSelectionData          *selection_data);
 650 +
 651 +  gboolean (* serialize)       (GtkTreeModelDndSerializer *serializer,
 652 +                                GtkTreeModelDnd           *model_dnd,
 653 +                                GtkSelectionData          *selection_data,
 654 +                                GList                     *paths);
 655 +
 656 +  gboolean (* deserialize)     (GtkTreeModelDndSerializer *serializer,
 657 +                                GtkTreeModelDnd           *model_dnd,
 658 +                                GtkSelectionData          *selection_data,
 659 +                                GList                     *paths);
 660 +};
 661 +
 662 +GType    gtk_tree_model_dnd_serializer_get_type        (void) G_GNUC_CONST;
 663 +
 664 +void     gtk_tree_model_dnd_serializer_add_targets     (GtkTreeModelDndSerializer *serializer,
 665 +                                                        GtkTreeModelDnd           *model_dnd,
 666 +                                                        GtkTargetList             *targets);
 667 +
 668 +gboolean gtk_tree_model_dnd_serializer_supports_target (GtkTreeModelDndSerializer *serializer,
 669 +                                                        GdkAtom                    target);
 670 +
 671 +int      gtk_tree_model_dnd_serializer_get_count       (GtkTreeModelDndSerializer *serializer,
 672 +                                                        GtkSelectionData          *selection_data);
 673 +
 674 +gboolean gtk_tree_model_dnd_serializer_serialize       (GtkTreeModelDndSerializer *serializer,
 675 +                                                        GtkTreeModelDnd           *model_dnd,
 676 +                                                        GtkSelectionData          *selection_data,
 677 +                                                        GList                     *paths);
 678 +
 679 +gboolean gtk_tree_model_dnd_serializer_deserialize     (GtkTreeModelDndSerializer *serializer,
 680 +                                                        GtkTreeModelDnd           *model_dnd,
 681 +                                                        GtkSelectionData          *selection_data,
 682 +                                                        GList                     *paths);
 683 +
 684 +GtkTreeModelDndSerializer *gtk_tree_model_dnd_find_serializer (GList   *serializers,
 685 +                                                               GdkAtom  target);
 686 +
 687 +
 688 +
 689 +struct _GtkTreeModelDndIface
 690 +{
 691 +  GTypeInterface g_iface;
 692 +
 693 +  /* VTable - not signals */
 694 +
 695 +  void (* add_serializer)    (GtkTreeModelDnd           *model_dnd,
 696 +                              GtkTreeModelDndSerializer *serializer);
 697 +  void (* remove_serializer) (GtkTreeModelDnd           *model_dnd,
 698 +                              GtkTreeModelDndSerializer *serializer);
 699 +
 700 +  /* FIXME: Distinguish between source/dest.  Delegate to object */
 701 +  GtkTargetList * (* get_targets) (GtkTreeModelDnd *model_dnd);
 702 +
 703 +  gboolean (* serialize) (GtkTreeModelDnd  *model_dnd,
 704 +                          GList            *row_refs,
 705 +                          GtkSelectionData *selection_data);
 706 +  gboolean (* deserialize) (GtkTreeModelDnd         *model_dnd,
 707 +                            GtkTreePath             *path,
 708 +                            GtkTreeViewDropPosition  position,
 709 +                            GtkSelectionData        *selection_data);
 710 +
 711 +  /* Doesn't need to be overridden */
 712 +  gboolean (* delete_rows) (GtkTreeModelDnd  *model_dnd,
 713 +                            GList            *row_refs);
 714 +
 715 +  /* Make this a signal */
 716 +  gboolean (* can_drop_rows) (GtkTreeModelDnd         *model_dnd,
 717 +                              GtkTreePath             *path,
 718 +                              GtkTreeViewDropPosition  position);
 719 +};
 720 +
 721 +GType           gtk_tree_model_dnd_get_type   (void) G_GNUC_CONST;
 722 +
 723 +void     gtk_tree_model_dnd_add_serializer    (GtkTreeModelDnd           *model_dnd,
 724 +                                               GtkTreeModelDndSerializer *serializer);
 725 +void     gtk_tree_model_dnd_remove_serializer (GtkTreeModelDnd           *model_dnd,
 726 +                                               GtkTreeModelDndSerializer *serializer);
 727 +
 728 +GtkTargetList  *gtk_tree_model_dnd_get_targets (GtkTreeModelDnd *model_dnd);
 729 +
 730 +gboolean gtk_tree_model_dnd_serialize (GtkTreeModelDnd  *model_dnd,
 731 +                                       GList            *row_refs,
 732 +                                       GtkSelectionData *selection_data);
 733 +gboolean gtk_tree_model_dnd_deserialize (GtkTreeModelDnd         *model_dnd,
 734 +                                         GtkTreePath             *path,
 735 +                                         GtkTreeViewDropPosition  position,
 736 +                                         GtkSelectionData        *selection_data);
 737 +
 738 +gboolean gtk_tree_model_dnd_delete_rows (GtkTreeModelDnd  *model_dnd,
 739 +                                         GList            *row_refs);
 740 +
 741 +gboolean gtk_tree_model_dnd_can_drop_rows (GtkTreeModelDnd         *model_dnd,
 742 +                                           GtkTreePath             *path,
 743 +                                           GtkTreeViewDropPosition  position);
 744 +
 745 +
 746  /* The selection data would normally have target type GTK_TREE_MODEL_ROW in this
 747   * case. If the target is wrong these functions return FALSE.
 748   */
 749 diff --git a/gtk/gtktreeprivate.h b/gtk/gtktreeprivate.h
 750 index 51bb951..cc36139 100644
 751 --- a/gtk/gtktreeprivate.h
 752 +++ b/gtk/gtktreeprivate.h
 753 @@ -236,6 +236,9 @@ struct _GtkTreeViewPrivate
 754  
 755    guint in_grab : 1;
 756  
 757 +  guint is_drag_source : 1;
 758 +  guint is_drag_dest : 1;
 759 +
 760  
 761    /* Auto expand/collapse timeout in hover mode */
 762    guint auto_expand_timeout;
 763 @@ -268,6 +271,9 @@ struct _GtkTreeViewPrivate
 764    GdkGC *tree_line_gc;
 765  
 766    gint tooltip_column;
 767 +
 768 +  guint last_button_press_event_state;
 769 +  gpointer serializer;
 770  };
 771  
 772  #ifdef __GNUC__
 773 diff --git a/gtk/gtktreestore.c b/gtk/gtktreestore.c
 774 index 4175d49..1637d1f 100644
 775 --- a/gtk/gtktreestore.c
 776 +++ b/gtk/gtktreestore.c
 777 @@ -37,6 +37,7 @@ static void         gtk_tree_store_drag_source_init(GtkTreeDragSourceIface *ifac
 778  static void         gtk_tree_store_drag_dest_init  (GtkTreeDragDestIface   *iface);
 779  static void         gtk_tree_store_sortable_init   (GtkTreeSortableIface   *iface);
 780  static void         gtk_tree_store_buildable_init  (GtkBuildableIface      *iface);
 781 +static void         gtk_tree_store_dnd_init        (GtkTreeModelDndIface   *iface);
 782  static void         gtk_tree_store_finalize        (GObject           *object);
 783  static GtkTreeModelFlags gtk_tree_store_get_flags  (GtkTreeModel      *tree_model);
 784  static gint         gtk_tree_store_get_n_columns   (GtkTreeModel      *tree_model);
 785 @@ -132,6 +133,31 @@ static void     gtk_tree_store_buildable_custom_finished (GtkBuildable 	 *builda
 786  							  const gchar  	 *tagname,
 787  							  gpointer     	  user_data);
 788  
 789 +/* new drag and drop */
 790 +static void gtk_tree_store_dnd_add_serializer (GtkTreeModelDnd           *model_dnd,
 791 +                                               GtkTreeModelDndSerializer *serializer);
 792 +static void gtk_tree_store_dnd_remove_serializer (GtkTreeModelDnd           *model_dnd,
 793 +                                                  GtkTreeModelDndSerializer *serializer);
 794 +static GtkTargetList *
 795 +gtk_tree_store_dnd_get_targets (GtkTreeModelDnd *model_dnd);
 796 +static gboolean
 797 +gtk_tree_store_dnd_serialize (GtkTreeModelDnd   *model_dnd,
 798 +                              GList             *row_refs,
 799 +                              GtkSelectionData  *selection_data);
 800 +static gboolean
 801 +gtk_tree_store_dnd_deserialize (GtkTreeModelDnd         *model_dnd,
 802 +                                GtkTreePath             *path,
 803 +                                GtkTreeViewDropPosition  position,
 804 +                                GtkSelectionData        *selection_data);
 805 +static gboolean
 806 +gtk_tree_store_dnd_delete_rows (GtkTreeModelDnd *model_dnd,
 807 +                                GList           *row_refs);
 808 +static gboolean
 809 +gtk_tree_store_dnd_can_drop_rows (GtkTreeModelDnd         *model_dnd,
 810 +                                  GtkTreePath             *path,
 811 +                                  GtkTreeViewDropPosition  position);
 812 +
 813 +
 814  static void     validate_gnode                         (GNode *node);
 815  
 816  static void     gtk_tree_store_move                    (GtkTreeStore           *tree_store,
 817 @@ -161,7 +187,9 @@ G_DEFINE_TYPE_WITH_CODE (GtkTreeStore, gtk_tree_store, G_TYPE_OBJECT,
 818  			 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE,
 819  						gtk_tree_store_sortable_init)
 820  			 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
 821 -						gtk_tree_store_buildable_init))
 822 +						gtk_tree_store_buildable_init)
 823 +                         G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL_DND,
 824 +                                                gtk_tree_store_dnd_init))
 825  
 826  static void
 827  gtk_tree_store_class_init (GtkTreeStoreClass *class)
 828 @@ -222,6 +250,18 @@ gtk_tree_store_buildable_init (GtkBuildableIface *iface)
 829    iface->custom_finished = gtk_tree_store_buildable_custom_finished;
 830  }
 831  
 832 +void
 833 +gtk_tree_store_dnd_init (GtkTreeModelDndIface *iface)
 834 +{
 835 +  iface->add_serializer = gtk_tree_store_dnd_add_serializer;
 836 +  iface->remove_serializer = gtk_tree_store_dnd_remove_serializer;
 837 +  iface->get_targets = gtk_tree_store_dnd_get_targets;
 838 +  iface->serialize = gtk_tree_store_dnd_serialize;
 839 +  iface->deserialize = gtk_tree_store_dnd_deserialize;
 840 +  iface->delete_rows = gtk_tree_store_dnd_delete_rows;
 841 +  iface->can_drop_rows = gtk_tree_store_dnd_can_drop_rows;
 842 +}
 843 +
 844  static void
 845  gtk_tree_store_init (GtkTreeStore *tree_store)
 846  {
 847 @@ -237,6 +277,7 @@ gtk_tree_store_init (GtkTreeStore *tree_store)
 848    tree_store->sort_list = NULL;
 849    tree_store->sort_column_id = -2;
 850    tree_store->columns_dirty = FALSE;
 851 +  tree_store->serializers = NULL;
 852  }
 853  
 854  /**
 855 @@ -3327,5 +3368,206 @@ gtk_tree_store_buildable_custom_finished (GtkBuildable *buildable,
 856    g_slice_free (GSListSubParserData, data);
 857  }
 858  
 859 +
 860 +
 861 +static void
 862 +gtk_tree_store_dnd_add_serializer (GtkTreeModelDnd           *model_dnd,
 863 +                                   GtkTreeModelDndSerializer *serializer)
 864 +{
 865 +  GtkTreeStore *store;
 866 +
 867 +  /* FIXME: do proper ref counting */
 868 +  store = GTK_TREE_STORE (model_dnd);
 869 +  store->serializers = g_list_append (store->serializers, serializer);
 870 +}
 871 +
 872 +static void
 873 +gtk_tree_store_dnd_remove_serializer (GtkTreeModelDnd           *model_dnd,
 874 +                                      GtkTreeModelDndSerializer *serializer)
 875 +{
 876 +  GtkTreeStore *store;
 877 +
 878 +  /* FIXME: do proper ref counting */
 879 +  store = GTK_TREE_STORE (model_dnd);
 880 +  store->serializers = g_list_remove (store->serializers, serializer);
 881 +}
 882 +
 883 +static GtkTargetList *
 884 +gtk_tree_store_dnd_get_targets (GtkTreeModelDnd *model_dnd)
 885 +{
 886 +  GList *list;
 887 +  GtkTreeStore *store;
 888 +  GtkTargetList *targets;
 889 +
 890 +  store = GTK_TREE_STORE (model_dnd);
 891 +
 892 +  targets = gtk_target_list_new (NULL, 0);
 893 +  for (list = store->serializers; list; list = list->next)
 894 +    gtk_tree_model_dnd_serializer_add_targets (list->data,
 895 +                                               model_dnd,
 896 +                                               targets);
 897 +
 898 +  return targets;
 899 +}
 900 +
 901 +static gboolean
 902 +gtk_tree_store_dnd_serialize (GtkTreeModelDnd   *model_dnd,
 903 +                              GList             *row_refs,
 904 +                              GtkSelectionData  *selection_data)
 905 +{
 906 +  gboolean retval = FALSE;
 907 +  GList *list;
 908 +  GList *paths = NULL;
 909 +  GtkTreeStore *store;
 910 +  GtkTreeModelDndSerializer *serializer;
 911 +
 912 +  store = GTK_TREE_STORE (model_dnd);
 913 +
 914 +  serializer = gtk_tree_model_dnd_find_serializer (store->serializers,
 915 +                                                   selection_data->target);
 916 +  if (!serializer)
 917 +    return FALSE;
 918 +
 919 +  for (list = row_refs; list; list = list->next)
 920 +    {
 921 +      GtkTreePath *path;
 922 +
 923 +      path = gtk_tree_row_reference_get_path (list->data);
 924 +      paths = g_list_append (paths, path);
 925 +    }
 926 +
 927 +  retval = gtk_tree_model_dnd_serializer_serialize (serializer,
 928 +                                                    model_dnd,
 929 +                                                    selection_data,
 930 +                                                    paths);
 931 +
 932 +  g_list_foreach (paths, (GFunc)gtk_tree_path_free, NULL);
 933 +  g_list_free (paths);
 934 +
 935 +  return retval;
 936 +}
 937 +
 938 +static gboolean
 939 +gtk_tree_store_dnd_deserialize (GtkTreeModelDnd         *model_dnd,
 940 +                                GtkTreePath             *path,
 941 +                                GtkTreeViewDropPosition  position,
 942 +                                GtkSelectionData        *selection_data)
 943 +{
 944 +  int i = 0;
 945 +  int count;
 946 +  gboolean retval = FALSE;
 947 +  GList *paths = NULL;
 948 +  GtkTreeIter iter;
 949 +  GtkTreeStore *store;
 950 +  GtkTreePath *parent_path;
 951 +  GtkTreeIter parent_iter;
 952 +  GtkTreeModelDndSerializer *serializer;
 953 +
 954 +  store = GTK_TREE_STORE (model_dnd);
 955 +
 956 +  if (position == GTK_TREE_VIEW_DROP_INVALID)
 957 +    return FALSE;
 958 +
 959 +  serializer = gtk_tree_model_dnd_find_serializer (store->serializers,
 960 +                                                   selection_data->target);
 961 +  if (!serializer)
 962 +    return FALSE;
 963 +
 964 +  count = gtk_tree_model_dnd_serializer_get_count (serializer,
 965 +                                                   selection_data);
 966 +
 967 +  if (count < 0)
 968 +    return FALSE;
 969 +
 970 +  /* Build a list of destination paths */
 971 +  if (position != GTK_TREE_VIEW_DROP_EMPTY_SPACE)
 972 +    gtk_tree_model_get_iter (GTK_TREE_MODEL (model_dnd), &iter, path);
 973 +
 974 +  parent_path = gtk_tree_path_copy (path);
 975 +  if (position != GTK_TREE_VIEW_DROP_INTO_OR_BEFORE
 976 +      && position != GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
 977 +    gtk_tree_path_up (parent_path);
 978 +  if (gtk_tree_path_get_depth (parent_path) > 0)
 979 +    gtk_tree_model_get_iter (GTK_TREE_MODEL (model_dnd),
 980 +                             &parent_iter, parent_path);
 981 +  else
 982 +    parent_iter.stamp = 0;
 983 +  gtk_tree_path_free (parent_path);
 984 +
 985 +  for (i = 0; i < count; i++)
 986 +    {
 987 +      GtkTreeIter new_iter;
 988 +      GtkTreePath *new_path;
 989 +
 990 +      if (position == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE
 991 +          || position == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
 992 +        gtk_tree_store_append (store, &new_iter,
 993 +                               parent_iter.stamp ? &parent_iter : NULL);
 994 +      else if (position == GTK_TREE_VIEW_DROP_BEFORE && i == 0)
 995 +        gtk_tree_store_insert_before (store,
 996 +                                      &new_iter,
 997 +                                      parent_iter.stamp ? &parent_iter : NULL,
 998 +                                      &iter);
 999 +      else if (position == GTK_TREE_VIEW_DROP_EMPTY_SPACE)
1000 +        gtk_tree_store_append (store, &new_iter, NULL);
1001 +      else
1002 +        gtk_tree_store_insert_after (store,
1003 +                                     &new_iter,
1004 +                                     parent_iter.stamp ? &parent_iter : NULL,
1005 +                                     &iter);
1006 +
1007 +      iter = new_iter;
1008 +
1009 +      new_path = gtk_tree_model_get_path (GTK_TREE_MODEL (model_dnd), &iter);
1010 +      paths = g_list_append (paths, new_path);
1011 +    }
1012 +
1013 +  retval = gtk_tree_model_dnd_serializer_deserialize (serializer,
1014 +                                                      model_dnd,
1015 +                                                      selection_data,
1016 +                                                      paths);
1017 +
1018 +  g_list_foreach (paths, (GFunc)gtk_tree_path_free, NULL);
1019 +  g_list_free (paths);
1020 +
1021 +  return retval;
1022 +}
1023 +
1024 +static gboolean
1025 +gtk_tree_store_dnd_delete_rows (GtkTreeModelDnd *model_dnd,
1026 +                                GList           *row_refs)
1027 +{
1028 +  GList *list;
1029 +  GtkTreeStore *store = GTK_TREE_STORE (model_dnd);
1030 +
1031 +  for (list = row_refs; list; list = list->next)
1032 +    {
1033 +      GtkTreePath *path;
1034 +      GtkTreeIter iter;
1035 +
1036 +      path = gtk_tree_row_reference_get_path (list->data);
1037 +      if (!path)
1038 +        /* In trees, the parent could have been removed,
1039 +         * taking child nodes with it.
1040 +         */
1041 +        continue;
1042 +
1043 +      gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
1044 +      gtk_tree_store_remove (store, &iter);
1045 +      gtk_tree_path_free (path);
1046 +    }
1047 +
1048 +  return TRUE;
1049 +}
1050 +
1051 +static gboolean
1052 +gtk_tree_store_dnd_can_drop_rows (GtkTreeModelDnd         *model_dnd,
1053 +                                  GtkTreePath             *path,
1054 +                                  GtkTreeViewDropPosition  position)
1055 +{
1056 +  return TRUE;
1057 +}
1058 +
1059 +
1060  #define __GTK_TREE_STORE_C__
1061  #include "gtkaliasdef.c"
1062 diff --git a/gtk/gtktreestore.h b/gtk/gtktreestore.h
1063 index b47b1ec..5c85ff2 100644
1064 --- a/gtk/gtktreestore.h
1065 +++ b/gtk/gtktreestore.h
1066 @@ -59,6 +59,9 @@ struct _GtkTreeStore
1067    gpointer GSEAL (default_sort_data);
1068    GDestroyNotify GSEAL (default_sort_destroy);
1069    guint GSEAL (columns_dirty) : 1;
1070 +
1071 +  /* FIXME: I break ABI for now, fix this later */
1072 +  GList *serializers;
1073  };
1074  
1075  struct _GtkTreeStoreClass
1076 diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
1077 index c6bd79e..ee35dba 100644
1078 --- a/gtk/gtktreeview.c
1079 +++ b/gtk/gtktreeview.c
1080 @@ -46,6 +46,11 @@
1081  #include "gtkprivate.h"
1082  #include "gtkalias.h"
1083  
1084 +/* XXX: temporary eeew */
1085 +#include "gtktreemodelrowserializer.c"
1086 +
1087 +
1088 +
1089  #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
1090  #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
1091  #define GTK_TREE_VIEW_NUM_ROWS_PER_IDLE 500
1092 @@ -88,6 +93,7 @@ struct _GtkTreeViewChild
1093  };
1094  
1095  
1096 +#if 0
1097  typedef struct _TreeViewDragInfo TreeViewDragInfo;
1098  struct _TreeViewDragInfo
1099  {
1100 @@ -100,6 +106,7 @@ struct _TreeViewDragInfo
1101    guint source_set : 1;
1102    guint dest_set : 1;
1103  };
1104 +#endif
1105  
1106  
1107  /* Signals */
1108 @@ -120,6 +127,8 @@ enum
1109    EXPAND_COLLAPSE_CURSOR_ROW,
1110    SELECT_CURSOR_PARENT,
1111    START_INTERACTIVE_SEARCH,
1112 +  TEST_START_DRAG,
1113 +  TEST_DROP_DRAG,
1114    LAST_SIGNAL
1115  };
1116  
1117 @@ -215,6 +224,11 @@ static void     gtk_tree_view_forall               (GtkContainer     *container,
1118  						    gpointer          callback_data);
1119  
1120  /* Source side drag signals */
1121 +static gboolean gtk_tree_view_real_test_start_drag (GtkTreeView   *tree_view,
1122 +                                                    GList         *selection,
1123 +                                                    gint           button,
1124 +                                                    GdkDragAction *action,
1125 +                                                    gboolean      *start_drag);
1126  static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
1127                                              GdkDragContext   *context);
1128  static void gtk_tree_view_drag_end         (GtkWidget        *widget,
1129 @@ -228,6 +242,13 @@ static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
1130                                              GdkDragContext   *context);
1131  
1132  /* Target side drag signals */
1133 +static gboolean gtk_tree_view_real_test_drop_drag (GtkTreeView             *tree_view,
1134 +                                                   GdkDragContext          *context,
1135 +                                                   GtkTreePath             *destination_path,
1136 +                                                   GtkTreeViewDropPosition  position,
1137 +                                                   GdkDragAction           *suggested_action,
1138 +                                                   gboolean                *drop_drag);
1139 +
1140  static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
1141                                                    GdkDragContext   *context,
1142                                                    guint             time);
1143 @@ -469,6 +490,13 @@ static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree
1144  							 GtkTreeViewColumn *column,
1145  							 gint               drop_position);
1146  
1147 +static GdkPixmap *gtk_tree_view_create_dnd_icon_from_list (GtkTreeView *tree_view,
1148 +                                                           GList       *rows);
1149 +static void       gtk_tree_view_calculate_dnd_icon_size   (GtkTreeView *tree_view,
1150 +                                                           GList       *rows,
1151 +                                                           int         *width,
1152 +                                                           int         *height);
1153 +
1154  /* GtkBuildable */
1155  static void gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1156  					       GtkBuilder  *builder,
1157 @@ -561,6 +589,8 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
1158    class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
1159    class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
1160    class->start_interactive_search = gtk_tree_view_start_interactive_search;
1161 +  class->test_start_drag = gtk_tree_view_real_test_start_drag;
1162 +  class->test_drop_drag = gtk_tree_view_real_test_drop_drag;
1163  
1164    /* Properties */
1165  
1166 @@ -1096,6 +1126,45 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
1167  		  _gtk_marshal_BOOLEAN__NONE,
1168  		  G_TYPE_BOOLEAN, 0);
1169  
1170 +  /**
1171 +   * GtkTreeView::test-start-drag:
1172 +   *
1173 +   * Returns: %TRUE to stop other handlers from being invoked,
1174 +   *   %FALSE to propogate the event further.
1175 +   */
1176 +  tree_view_signals[TEST_START_DRAG] =
1177 +    g_signal_new (I_("test-start-drag"),
1178 +                  G_TYPE_FROM_CLASS (o_class),
1179 +                  G_SIGNAL_RUN_LAST,
1180 +                  G_STRUCT_OFFSET (GtkTreeViewClass, test_start_drag),
1181 +                  _gtk_boolean_handled_accumulator, NULL,
1182 +                  _gtk_marshal_BOOLEAN__POINTER_INT_POINTER_POINTER,
1183 +                  G_TYPE_BOOLEAN, 4,
1184 +                  G_TYPE_POINTER,
1185 +                  G_TYPE_INT,
1186 +                  G_TYPE_POINTER,
1187 +                  G_TYPE_POINTER);
1188 +
1189 +  /**
1190 +   * GtkTreeView::test-drop-drag:
1191 +   *
1192 +   * Returns: %TRUE to stop other handlers from being invoked,
1193 +   *   %FALSE to propogate the event further.
1194 +   */
1195 +  tree_view_signals[TEST_DROP_DRAG] =
1196 +    g_signal_new (I_("test-drop-drag"),
1197 +                  G_TYPE_FROM_CLASS (o_class),
1198 +                  G_SIGNAL_RUN_LAST,
1199 +                  G_STRUCT_OFFSET (GtkTreeViewClass, test_drop_drag),
1200 +                  _gtk_boolean_handled_accumulator, NULL,
1201 +                  _gtk_marshal_BOOLEAN__OBJECT_BOXED_ENUM_POINTER_POINTER,
1202 +                  G_TYPE_BOOLEAN, 5,
1203 +                  GDK_TYPE_DRAG_CONTEXT,
1204 +                  GTK_TYPE_TREE_PATH,
1205 +                  GTK_TYPE_TREE_VIEW_DROP_POSITION,
1206 +                  G_TYPE_POINTER,
1207 +                  G_TYPE_POINTER);
1208 +
1209    /* Key bindings */
1210    gtk_tree_view_add_move_binding (binding_set, GDK_Up, 0, TRUE,
1211  				  GTK_MOVEMENT_DISPLAY_LINES, -1);
1212 @@ -2674,6 +2743,8 @@ gtk_tree_view_button_press (GtkWidget      *widget,
1213            if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
1214              tree_view->priv->shift_pressed = TRUE;
1215  
1216 +          tree_view->priv->last_button_press_event_state = event->state;
1217 +
1218            focus_cell = _gtk_tree_view_column_get_cell_at_pos (column, event->x - background_area.x);
1219            if (focus_cell)
1220              gtk_tree_view_column_focus_cell (column, focus_cell);
1221 @@ -2690,7 +2761,7 @@ gtk_tree_view_button_press (GtkWidget      *widget,
1222              }
1223            else
1224              {
1225 -              gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
1226 +              gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
1227              }
1228  
1229            tree_view->priv->ctrl_pressed = FALSE;
1230 @@ -2947,7 +3018,27 @@ gtk_tree_view_button_release (GtkWidget      *widget,
1231      gtk_tree_view_stop_rubber_band (tree_view);
1232  
1233    if (tree_view->priv->pressed_button == event->button)
1234 -    tree_view->priv->pressed_button = -1;
1235 +    {
1236 +      GtkTreePath *path = NULL;
1237 +      guint state = tree_view->priv->last_button_press_event_state;
1238 +
1239 +      /* We didn't drag; so select the cursor. */
1240 +      path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
1241 +
1242 +      if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
1243 +        tree_view->priv->ctrl_pressed = TRUE;
1244 +      if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
1245 +        tree_view->priv->shift_pressed = TRUE;
1246 +
1247 +      gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
1248 +
1249 +      tree_view->priv->ctrl_pressed = FALSE;
1250 +      tree_view->priv->shift_pressed = FALSE;
1251 +
1252 +      tree_view->priv->pressed_button = -1;
1253 +
1254 +      gtk_tree_path_free (path);
1255 +    }
1256  
1257    if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
1258      return gtk_tree_view_button_release_column_resize (widget, event);
1259 @@ -4729,6 +4820,14 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
1260  				 width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
1261  				 - focus_line_width + 1);
1262                break;
1263 +
1264 +            case GTK_TREE_VIEW_DROP_EMPTY_SPACE:
1265 +              /* FIXME: make up some highlight for this. */
1266 +              break;
1267 +
1268 +            case GTK_TREE_VIEW_DROP_INVALID:
1269 +              /* Do nothing (silence compiler) */
1270 +              break;
1271              }
1272  
1273            if (highlight_y >= 0)
1274 @@ -6411,216 +6510,152 @@ _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
1275    gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1276  }
1277  
1278 -/* Drag-and-drop */
1279 -
1280 -static void
1281 -set_source_row (GdkDragContext *context,
1282 -                GtkTreeModel   *model,
1283 -                GtkTreePath    *source_row)
1284 -{
1285 -  g_object_set_data_full (G_OBJECT (context),
1286 -                          I_("gtk-tree-view-source-row"),
1287 -                          source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
1288 -                          (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
1289 -}
1290 -
1291 -static GtkTreePath*
1292 -get_source_row (GdkDragContext *context)
1293 -{
1294 -  GtkTreeRowReference *ref =
1295 -    g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
1296 -
1297 -  if (ref)
1298 -    return gtk_tree_row_reference_get_path (ref);
1299 -  else
1300 -    return NULL;
1301 -}
1302 +/*
1303 + * Default drag-and-drop implementation.
1304 + */
1305  
1306 +/* DnD helpers */
1307  typedef struct
1308  {
1309 -  GtkTreeRowReference *dest_row;
1310 -  guint                path_down_mode   : 1;
1311 -  guint                empty_view_drop  : 1;
1312 -  guint                drop_append_mode : 1;
1313 +  GList *selection;
1314 +  GtkTreeModel *model;
1315  }
1316 -DestRow;
1317 +GtkTreeViewSourceInfo;
1318 +
1319 +#define GTK_TREE_VIEW_SOURCE_INFO "gtk-tree-view-source-info"
1320  
1321  static void
1322 -dest_row_free (gpointer data)
1323 +gtk_tree_view_drag_context_free_source_info (GtkTreeViewSourceInfo *source_info)
1324  {
1325 -  DestRow *dr = (DestRow *)data;
1326 +  g_list_foreach (source_info->selection,
1327 +                  (GFunc)gtk_tree_row_reference_free,
1328 +                  NULL);
1329 +  g_list_free (source_info->selection);
1330  
1331 -  gtk_tree_row_reference_free (dr->dest_row);
1332 -  g_slice_free (DestRow, dr);
1333 +  g_free (source_info);
1334  }
1335  
1336  static void
1337 -set_dest_row (GdkDragContext *context,
1338 -              GtkTreeModel   *model,
1339 -              GtkTreePath    *dest_row,
1340 -              gboolean        path_down_mode,
1341 -              gboolean        empty_view_drop,
1342 -              gboolean        drop_append_mode)
1343 +gtk_tree_view_drag_context_set_source_info (GdkDragContext *context,
1344 +                                            GtkTreeModel   *model,
1345 +                                            GList          *selection)
1346  {
1347 -  DestRow *dr;
1348 +  GList *list;
1349 +  GtkTreeViewSourceInfo *source_info;
1350  
1351 -  if (!dest_row)
1352 +  if (!model)
1353      {
1354 -      g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
1355 -                              NULL, NULL);
1356 +      g_object_set_data (G_OBJECT (context),
1357 +                         GTK_TREE_VIEW_SOURCE_INFO, NULL);
1358        return;
1359      }
1360  
1361 -  dr = g_slice_new (DestRow);
1362 -
1363 -  dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
1364 -  dr->path_down_mode = path_down_mode != FALSE;
1365 -  dr->empty_view_drop = empty_view_drop != FALSE;
1366 -  dr->drop_append_mode = drop_append_mode != FALSE;
1367 +  source_info = g_new (GtkTreeViewSourceInfo, 1);
1368 +  source_info->model = model;
1369 +  source_info->selection = NULL;
1370  
1371 -  g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
1372 -                          dr, (GDestroyNotify) dest_row_free);
1373 -}
1374 -
1375 -static GtkTreePath*
1376 -get_dest_row (GdkDragContext *context,
1377 -              gboolean       *path_down_mode)
1378 -{
1379 -  DestRow *dr =
1380 -    g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
1381 -
1382 -  if (dr)
1383 +  for (list = selection; list; list = list->next)
1384      {
1385 -      GtkTreePath *path = NULL;
1386 -
1387 -      if (path_down_mode)
1388 -        *path_down_mode = dr->path_down_mode;
1389 -
1390 -      if (dr->dest_row)
1391 -        path = gtk_tree_row_reference_get_path (dr->dest_row);
1392 -      else if (dr->empty_view_drop)
1393 -        path = gtk_tree_path_new_from_indices (0, -1);
1394 -      else
1395 -        path = NULL;
1396 +      GtkTreeRowReference *ref;
1397  
1398 -      if (path && dr->drop_append_mode)
1399 -        gtk_tree_path_next (path);
1400 -
1401 -      return path;
1402 +      ref = gtk_tree_row_reference_new (model, list->data);
1403 +      source_info->selection = g_list_append (source_info->selection, ref);
1404      }
1405 -  else
1406 -    return NULL;
1407 -}
1408  
1409 -/* Get/set whether drag_motion requested the drag data and
1410 - * drag_data_received should thus not actually insert the data,
1411 - * since the data doesn't result from a drop.
1412 - */
1413 -static void
1414 -set_status_pending (GdkDragContext *context,
1415 -                    GdkDragAction   suggested_action)
1416 -{
1417 -  g_object_set_data (G_OBJECT (context),
1418 -                     I_("gtk-tree-view-status-pending"),
1419 -                     GINT_TO_POINTER (suggested_action));
1420 +  g_object_set_data_full (G_OBJECT (context),
1421 +                          GTK_TREE_VIEW_SOURCE_INFO,
1422 +                          source_info,
1423 +                          (GDestroyNotify) gtk_tree_view_drag_context_free_source_info);
1424  }
1425  
1426 -static GdkDragAction
1427 -get_status_pending (GdkDragContext *context)
1428 +static GtkTreeViewSourceInfo *
1429 +gtk_tree_view_drag_context_get_source_info (GdkDragContext *context)
1430  {
1431 -  return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
1432 -                                             "gtk-tree-view-status-pending"));
1433 +  return g_object_get_data (G_OBJECT (context), GTK_TREE_VIEW_SOURCE_INFO);
1434  }
1435  
1436 -static TreeViewDragInfo*
1437 -get_info (GtkTreeView *tree_view)
1438 +typedef struct
1439  {
1440 -  return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
1441 +  GtkTreePath *path;
1442 +  GtkTreeViewDropPosition position;
1443 +  GdkDragAction suggested_action;
1444 +
1445 +  guint receive_for_drop : 1;
1446  }
1447 +GtkTreeViewDestInfo;
1448 +
1449 +#define GTK_TREE_VIEW_DEST_INFO "gtk-tree-view-dest-info"
1450  
1451  static void
1452 -destroy_info (TreeViewDragInfo *di)
1453 +gtk_tree_view_drag_context_free_dest_info (GtkTreeViewDestInfo *dest_info)
1454  {
1455 -  g_slice_free (TreeViewDragInfo, di);
1456 +  gtk_tree_path_free (dest_info->path);
1457 +
1458 +  g_free (dest_info);
1459  }
1460  
1461 -static TreeViewDragInfo*
1462 -ensure_info (GtkTreeView *tree_view)
1463 +static GtkTreeViewDestInfo *
1464 +gtk_tree_view_drag_context_get_dest_info (GdkDragContext *context)
1465  {
1466 -  TreeViewDragInfo *di;
1467 -
1468 -  di = get_info (tree_view);
1469 +  return g_object_get_data (G_OBJECT (context), GTK_TREE_VIEW_DEST_INFO);
1470 +}
1471  
1472 -  if (di == NULL)
1473 -    {
1474 -      di = g_slice_new0 (TreeViewDragInfo);
1475 +static GtkTreeViewDestInfo *
1476 +gtk_tree_view_drag_context_get_or_create_dest_info (GdkDragContext *context)
1477 +{
1478 +  GtkTreeViewDestInfo *dest_info;
1479  
1480 -      g_object_set_data_full (G_OBJECT (tree_view),
1481 -                              I_("gtk-tree-view-drag-info"),
1482 -                              di,
1483 -                              (GDestroyNotify) destroy_info);
1484 -    }
1485 +  dest_info = gtk_tree_view_drag_context_get_dest_info (context);
1486 +  if (dest_info)
1487 +    return dest_info;
1488  
1489 -  return di;
1490 +  dest_info = g_new0 (GtkTreeViewDestInfo, 1);
1491 +  g_object_set_data_full (G_OBJECT (context),
1492 +                          GTK_TREE_VIEW_DEST_INFO,
1493 +                          dest_info,
1494 +                          (GDestroyNotify) gtk_tree_view_drag_context_free_dest_info);
1495 +  return dest_info;
1496  }
1497  
1498  static void
1499 -remove_info (GtkTreeView *tree_view)
1500 -{
1501 -  g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
1502 -}
1503 -
1504 -#if 0
1505 -static gint
1506 -drag_scan_timeout (gpointer data)
1507 +gtk_tree_view_drag_context_set_dest_info (GdkDragContext          *context,
1508 +                                          GtkTreePath             *path,
1509 +                                          GtkTreeViewDropPosition  pos)
1510  {
1511 -  GtkTreeView *tree_view;
1512 -  gint x, y;
1513 -  GdkModifierType state;
1514 -  GtkTreePath *path = NULL;
1515 -  GtkTreeViewColumn *column = NULL;
1516 -  GdkRectangle visible_rect;
1517 +  GtkTreeViewDestInfo *dest_info;
1518  
1519 -  GDK_THREADS_ENTER ();
1520 +  if (!path)
1521 +    {
1522 +      g_object_set_data (G_OBJECT (context),
1523 +                         GTK_TREE_VIEW_DEST_INFO, NULL);
1524 +      return;
1525 +    }
1526  
1527 -  tree_view = GTK_TREE_VIEW (data);
1528 +  dest_info = gtk_tree_view_drag_context_get_or_create_dest_info (context);
1529  
1530 -  gdk_window_get_pointer (tree_view->priv->bin_window,
1531 -                          &x, &y, &state);
1532 +  if (dest_info->path)
1533 +    gtk_tree_path_free (dest_info->path);
1534  
1535 -  gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
1536 +  dest_info->path = gtk_tree_path_copy (path);
1537 +  dest_info->position = pos;
1538 +}
1539  
1540 -  /* See if we are near the edge. */
1541 -  if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
1542 -      (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
1543 -      (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
1544 -      (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
1545 -    {
1546 -      gtk_tree_view_get_path_at_pos (tree_view,
1547 -                                     tree_view->priv->bin_window,
1548 -                                     x, y,
1549 -                                     &path,
1550 -                                     &column,
1551 -                                     NULL,
1552 -                                     NULL);
1553 +static gboolean
1554 +scroll_row_timeout (gpointer data)
1555 +{
1556 +  GtkTreeView *tree_view = data;
1557  
1558 -      if (path != NULL)
1559 -        {
1560 -          gtk_tree_view_scroll_to_cell (tree_view,
1561 -                                        path,
1562 -                                        column,
1563 -					TRUE,
1564 -                                        0.5, 0.5);
1565 +  gtk_tree_view_vertical_autoscroll (tree_view);
1566  
1567 -          gtk_tree_path_free (path);
1568 -        }
1569 -    }
1570 +  /* FIXME: want to run another drag-motion so the drop location
1571 +   * is updated.
1572 +   */
1573  
1574 -  GDK_THREADS_LEAVE ();
1575 +  if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
1576 +    gtk_tree_view_update_rubber_band (tree_view);
1577  
1578    return TRUE;
1579  }
1580 -#endif /* 0 */
1581  
1582  static void
1583  add_scroll_timeout (GtkTreeView *tree_view)
1584 @@ -6666,16 +6701,6 @@ check_model_dnd (GtkTreeModel *model,
1585      return TRUE;
1586  }
1587  
1588 -static void
1589 -remove_open_timeout (GtkTreeView *tree_view)
1590 -{
1591 -  if (tree_view->priv->open_dest_timeout != 0)
1592 -    {
1593 -      g_source_remove (tree_view->priv->open_dest_timeout);
1594 -      tree_view->priv->open_dest_timeout = 0;
1595 -    }
1596 -}
1597 -
1598  
1599  static gint
1600  open_row_timeout (gpointer data)
1601 @@ -6709,331 +6734,191 @@ open_row_timeout (gpointer data)
1602    return result;
1603  }
1604  
1605 -static gboolean
1606 -scroll_row_timeout (gpointer data)
1607 -{
1608 -  GtkTreeView *tree_view = data;
1609 -
1610 -  gtk_tree_view_vertical_autoscroll (tree_view);
1611 -
1612 -  if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
1613 -    gtk_tree_view_update_rubber_band (tree_view);
1614 -
1615 -  return TRUE;
1616 -}
1617 -
1618 -/* Returns TRUE if event should not be propagated to parent widgets */
1619 -static gboolean
1620 -set_destination_row (GtkTreeView    *tree_view,
1621 -                     GdkDragContext *context,
1622 -                     /* coordinates relative to the widget */
1623 -                     gint            x,
1624 -                     gint            y,
1625 -                     GdkDragAction  *suggested_action,
1626 -                     GdkAtom        *target)
1627 +static void
1628 +add_open_timeout (GtkTreeView *tree_view)
1629  {
1630 -  GtkTreePath *path = NULL;
1631 -  GtkTreeViewDropPosition pos;
1632 -  GtkTreeViewDropPosition old_pos;
1633 -  TreeViewDragInfo *di;
1634 -  GtkWidget *widget;
1635 -  GtkTreePath *old_dest_path = NULL;
1636 -  gboolean can_drop = FALSE;
1637 -
1638 -  *suggested_action = 0;
1639 -  *target = GDK_NONE;
1640 -
1641 -  widget = GTK_WIDGET (tree_view);
1642 -
1643 -  di = get_info (tree_view);
1644 -
1645 -  if (di == NULL || y - TREE_VIEW_HEADER_HEIGHT (tree_view) < 0)
1646 -    {
1647 -      /* someone unset us as a drag dest, note that if
1648 -       * we return FALSE drag_leave isn't called
1649 -       */
1650 -
1651 -      gtk_tree_view_set_drag_dest_row (tree_view,
1652 -                                       NULL,
1653 -                                       GTK_TREE_VIEW_DROP_BEFORE);
1654 -
1655 -      remove_scroll_timeout (GTK_TREE_VIEW (widget));
1656 -      remove_open_timeout (GTK_TREE_VIEW (widget));
1657 -
1658 -      return FALSE; /* no longer a drop site */
1659 -    }
1660 -
1661 -  *target = gtk_drag_dest_find_target (widget, context,
1662 -                                       gtk_drag_dest_get_target_list (widget));
1663 -  if (*target == GDK_NONE)
1664 +  if (tree_view->priv->open_dest_timeout == 0)
1665      {
1666 -      return FALSE;
1667 +      tree_view->priv->open_dest_timeout =
1668 +	gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT,
1669 +                                 open_row_timeout, tree_view);
1670      }
1671 +}
1672  
1673 -  if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
1674 -                                          x, y,
1675 -                                          &path,
1676 -                                          &pos))
1677 -    {
1678 -      gint n_children;
1679 -      GtkTreeModel *model;
1680 -
1681 -      remove_open_timeout (tree_view);
1682 -
1683 -      /* the row got dropped on empty space, let's setup a special case
1684 -       */
1685 -
1686 -      if (path)
1687 -	gtk_tree_path_free (path);
1688 -
1689 -      model = gtk_tree_view_get_model (tree_view);
1690 -
1691 -      n_children = gtk_tree_model_iter_n_children (model, NULL);
1692 -      if (n_children)
1693 -        {
1694 -          pos = GTK_TREE_VIEW_DROP_AFTER;
1695 -          path = gtk_tree_path_new_from_indices (n_children - 1, -1);
1696 -        }
1697 -      else
1698 -        {
1699 -          pos = GTK_TREE_VIEW_DROP_BEFORE;
1700 -          path = gtk_tree_path_new_from_indices (0, -1);
1701 -        }
1702 -
1703 -      can_drop = TRUE;
1704 -
1705 -      goto out;
1706 -    }
1707 -
1708 -  g_assert (path);
1709 -
1710 -  /* If we left the current row's "open" zone, unset the timeout for
1711 -   * opening the row
1712 -   */
1713 -  gtk_tree_view_get_drag_dest_row (tree_view,
1714 -                                   &old_dest_path,
1715 -                                   &old_pos);
1716 -
1717 -  if (old_dest_path &&
1718 -      (gtk_tree_path_compare (path, old_dest_path) != 0 ||
1719 -       !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
1720 -         pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
1721 -    remove_open_timeout (tree_view);
1722 -
1723 -  if (old_dest_path)
1724 -    gtk_tree_path_free (old_dest_path);
1725 -
1726 -  if (TRUE /* FIXME if the location droppable predicate */)
1727 -    {
1728 -      can_drop = TRUE;
1729 -    }
1730 -
1731 -out:
1732 -  if (can_drop)
1733 -    {
1734 -      GtkWidget *source_widget;
1735 -
1736 -      *suggested_action = context->suggested_action;
1737 -      source_widget = gtk_drag_get_source_widget (context);
1738 -
1739 -      if (source_widget == widget)
1740 -        {
1741 -          /* Default to MOVE, unless the user has
1742 -           * pressed ctrl or shift to affect available actions
1743 -           */
1744 -          if ((context->actions & GDK_ACTION_MOVE) != 0)
1745 -            *suggested_action = GDK_ACTION_MOVE;
1746 -        }
1747 -
1748 -      gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
1749 -                                       path, pos);
1750 -    }
1751 -  else
1752 +static void
1753 +remove_open_timeout (GtkTreeView *tree_view)
1754 +{
1755 +  if (tree_view->priv->open_dest_timeout != 0)
1756      {
1757 -      /* can't drop here */
1758 -      remove_open_timeout (tree_view);
1759 -
1760 -      gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
1761 -                                       NULL,
1762 -                                       GTK_TREE_VIEW_DROP_BEFORE);
1763 +      g_source_remove (tree_view->priv->open_dest_timeout);
1764 +      tree_view->priv->open_dest_timeout = 0;
1765      }
1766 -
1767 -  if (path)
1768 -    gtk_tree_path_free (path);
1769 -
1770 -  return TRUE;
1771  }
1772  
1773 -static GtkTreePath*
1774 -get_logical_dest_row (GtkTreeView *tree_view,
1775 -                      gboolean    *path_down_mode,
1776 -                      gboolean    *drop_append_mode)
1777 -{
1778 -  /* adjust path to point to the row the drop goes in front of */
1779 -  GtkTreePath *path = NULL;
1780 -  GtkTreeViewDropPosition pos;
1781 -
1782 -  g_return_val_if_fail (path_down_mode != NULL, NULL);
1783 -  g_return_val_if_fail (drop_append_mode != NULL, NULL);
1784 +/* DnD source side */
1785  
1786 -  *path_down_mode = FALSE;
1787 -  *drop_append_mode = 0;
1788 -
1789 -  gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
1790 -
1791 -  if (path == NULL)
1792 -    return NULL;
1793 -
1794 -  if (pos == GTK_TREE_VIEW_DROP_BEFORE)
1795 -    ; /* do nothing */
1796 -  else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
1797 -           pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
1798 -    *path_down_mode = TRUE;
1799 +static gboolean
1800 +gtk_tree_view_real_test_start_drag (GtkTreeView   *tree_view,
1801 +                                    GList         *selection,
1802 +                                    gint           button,
1803 +                                    GdkDragAction *action,
1804 +                                    gboolean      *start_drag)
1805 +{
1806 +  if (button != 1)
1807 +    *start_drag = FALSE;
1808    else
1809 -    {
1810 -      GtkTreeIter iter;
1811 -      GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
1812 +    *start_drag = TRUE;
1813  
1814 -      g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
1815 +  *action = GDK_ACTION_COPY | GDK_ACTION_MOVE;
1816  
1817 -      if (!gtk_tree_model_get_iter (model, &iter, path) ||
1818 -          !gtk_tree_model_iter_next (model, &iter))
1819 -        *drop_append_mode = 1;
1820 -      else
1821 -        {
1822 -          *drop_append_mode = 0;
1823 -          gtk_tree_path_next (path);
1824 -        }
1825 -    }
1826 -
1827 -  return path;
1828 +  return TRUE;
1829  }
1830  
1831 +/* This function is called from a motion event with the button
1832 + * down, so we can decide whether or not to begin a drag and drop
1833 + * operation.
1834 + */
1835  static gboolean
1836  gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
1837                                          GdkEventMotion   *event)
1838  {
1839    GtkWidget *widget = GTK_WIDGET (tree_view);
1840    GdkDragContext *context;
1841 -  TreeViewDragInfo *di;
1842    GtkTreePath *path = NULL;
1843    gint button;
1844 -  gint cell_x, cell_y;
1845 -  GtkTreeModel *model;
1846 -  gboolean retval = FALSE;
1847 -
1848 -  di = get_info (tree_view);
1849 -
1850 -  if (di == NULL || !di->source_set)
1851 -    goto out;
1852 +  GList *selection;
1853 +  gboolean handled;
1854 +  gboolean start_drag = TRUE;
1855 +  GdkDragAction action = GDK_ACTION_DEFAULT;
1856 +
1857 +  /* Preliminary checks */
1858 +  if (!tree_view->priv->model
1859 +      || !tree_view->priv->is_drag_source
1860 +      || tree_view->priv->pressed_button < 0
1861 +      || !gtk_drag_check_threshold (widget,
1862 +                                    tree_view->priv->press_start_x,
1863 +                                    tree_view->priv->press_start_y,
1864 +                                    event->x, event->y))
1865 +    return FALSE;
1866  
1867 -  if (tree_view->priv->pressed_button < 0)
1868 -    goto out;
1869 +  /* Mark DnD decision as made, so we won't be called again for this
1870 +   * drag.
1871 +   */
1872 +  button = tree_view->priv->pressed_button;
1873 +  tree_view->priv->pressed_button = -1;
1874  
1875 -  if (!gtk_drag_check_threshold (widget,
1876 -                                 tree_view->priv->press_start_x,
1877 -                                 tree_view->priv->press_start_y,
1878 -                                 event->x, event->y))
1879 -    goto out;
1880 +  g_signal_emit (tree_view, tree_view_signals[TEST_START_DRAG], 0,
1881 +                 selection, button, &action, &start_drag, &handled);
1882  
1883 -  model = gtk_tree_view_get_model (tree_view);
1884 +  /* FIXME: do we also want the model to have a say whether those
1885 +   * rows can actually be dragged?  If yes, do we position this
1886 +   * before the check on the tree view?
1887 +   */
1888  
1889 -  if (model == NULL)
1890 -    goto out;
1891 +  /* FIXME: we might want to block dragging multiple rows if the
1892 +   * underlying interfaces don't support it.
1893 +   */
1894  
1895 -  button = tree_view->priv->pressed_button;
1896 -  tree_view->priv->pressed_button = -1;
1897 +  /* We ignore the value in handled, because our default handler
1898 +   * returns TRUE anyway.
1899 +   */
1900 +  if (!start_drag)
1901 +    return FALSE;
1902  
1903 +  /* Determine which rows and if it is okay to drag those */
1904    gtk_tree_view_get_path_at_pos (tree_view,
1905                                   tree_view->priv->press_start_x,
1906                                   tree_view->priv->press_start_y,
1907                                   &path,
1908 -                                 NULL,
1909 -                                 &cell_x,
1910 -                                 &cell_y);
1911 +                                 NULL, NULL, NULL);
1912  
1913 -  if (path == NULL)
1914 -    goto out;
1915 +  if (!path)
1916 +    return FALSE;
1917  
1918 -  if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
1919 -      !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
1920 -					   path))
1921 -    goto out;
1922 +  /* The path we want to drag must be selected.
1923 +   * FIXME: is this maybe already checked?
1924 +   */
1925 +  if (!gtk_tree_selection_path_is_selected (tree_view->priv->selection, path))
1926 +    {
1927 +      gtk_tree_path_free (path);
1928 +      return FALSE;
1929 +    }
1930  
1931 -  if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
1932 -    goto out;
1933 +  selection = gtk_tree_selection_get_selected_rows (tree_view->priv->selection,
1934 +                                                    NULL);
1935  
1936    /* Now we can begin the drag */
1937 -
1938 -  retval = TRUE;
1939 -
1940    context = gtk_drag_begin (widget,
1941                              gtk_drag_source_get_target_list (widget),
1942 -                            di->source_actions,
1943 +                            action,
1944                              button,
1945                              (GdkEvent*)event);
1946  
1947 -  set_source_row (context, model, path);
1948 +  /* Save a list of all row refs that make up the selection */
1949 +  gtk_tree_view_drag_context_set_source_info (context,
1950 +                                              tree_view->priv->model,
1951 +                                              selection);
1952  
1953 - out:
1954 -  if (path)
1955 -    gtk_tree_path_free (path);
1956 +  gtk_tree_path_free (path);
1957  
1958 -  return retval;
1959 +  return TRUE;
1960  }
1961  
1962 -
1963 +/* Default signal handlers for source side */
1964  static void
1965  gtk_tree_view_drag_begin (GtkWidget      *widget,
1966                            GdkDragContext *context)
1967  {
1968    GtkTreeView *tree_view;
1969 -  GtkTreePath *path = NULL;
1970 -  gint cell_x, cell_y;
1971 +  int width, height;
1972    GdkPixmap *row_pix;
1973 -  TreeViewDragInfo *di;
1974 +  GList *selection;
1975  
1976    tree_view = GTK_TREE_VIEW (widget);
1977  
1978    /* if the user uses a custom DND source impl, we don't set the icon here */
1979 -  di = get_info (tree_view);
1980 -
1981 -  if (di == NULL || !di->source_set)
1982 +  if (!tree_view->priv->is_drag_source)
1983      return;
1984  
1985 -  gtk_tree_view_get_path_at_pos (tree_view,
1986 -                                 tree_view->priv->press_start_x,
1987 -                                 tree_view->priv->press_start_y,
1988 -                                 &path,
1989 -                                 NULL,
1990 -                                 &cell_x,
1991 -                                 &cell_y);
1992 +  /* We need to decide whether to show a rendering of the selected
1993 +   * rows, or the normal drag icon.  As a rule of thumb we will show
1994 +   * a rendering of the rows if that is smaller than 1/4 of the
1995 +   * root display.
1996 +   */
1997 +  selection = gtk_tree_selection_get_selected_rows (tree_view->priv->selection,
1998 +                                                    NULL);
1999  
2000 -  g_return_if_fail (path != NULL);
2001 +  gtk_tree_view_calculate_dnd_icon_size (tree_view, selection,
2002 +                                         &width, &height);
2003  
2004 -  row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
2005 -                                                path);
2006 +  if (width > 0.25 * gdk_screen_width ()
2007 +      || height > 0.25 * gdk_screen_height ())
2008 +    gtk_drag_set_icon_default (context);
2009 +  else
2010 +    {
2011 +      row_pix = gtk_tree_view_create_dnd_icon_from_list (tree_view,
2012 +                                                         selection);
2013  
2014 -  gtk_drag_set_icon_pixmap (context,
2015 -                            gdk_drawable_get_colormap (row_pix),
2016 -                            row_pix,
2017 -                            NULL,
2018 -                            /* the + 1 is for the black border in the icon */
2019 -                            tree_view->priv->press_start_x + 1,
2020 -                            cell_y + 1);
2021 +      gtk_drag_set_icon_pixmap (context,
2022 +                                gdk_drawable_get_colormap (row_pix),
2023 +                                row_pix,
2024 +                                NULL,
2025 +                                -2, -2);
2026  
2027 -  g_object_unref (row_pix);
2028 -  gtk_tree_path_free (path);
2029 +      g_object_unref (row_pix);
2030 +    }
2031 +
2032 +  g_list_foreach (selection, (GFunc)gtk_tree_path_free, NULL);
2033 +  g_list_free (selection);
2034  }
2035  
2036  static void
2037  gtk_tree_view_drag_end (GtkWidget      *widget,
2038                          GdkDragContext *context)
2039  {
2040 -  /* do nothing */
2041 +  gtk_tree_view_drag_context_set_source_info (context, NULL, NULL);
2042  }
2043  
2044 -/* Default signal implementations for the drag signals */
2045  static void
2046  gtk_tree_view_drag_data_get (GtkWidget        *widget,
2047                               GdkDragContext   *context,
2048 @@ -7043,26 +6928,33 @@ gtk_tree_view_drag_data_get (GtkWidget        *widget,
2049  {
2050    GtkTreeView *tree_view;
2051    GtkTreeModel *model;
2052 -  TreeViewDragInfo *di;
2053    GtkTreePath *source_row;
2054 +  GtkTreeViewSourceInfo *source_info;
2055  
2056    tree_view = GTK_TREE_VIEW (widget);
2057 -
2058    model = gtk_tree_view_get_model (tree_view);
2059  
2060 -  if (model == NULL)
2061 +  if (!tree_view->priv->is_drag_source)
2062      return;
2063  
2064 -  di = get_info (GTK_TREE_VIEW (widget));
2065 -
2066 -  if (di == NULL)
2067 +  source_info = gtk_tree_view_drag_context_get_source_info (context);
2068 +  if (!source_info)
2069      return;
2070  
2071 -  source_row = get_source_row (context);
2072 +  /* Convert data to requested target */
2073  
2074 -  if (source_row == NULL)
2075 +  /* Try the new interfaces first */
2076 +  if (GTK_IS_TREE_MODEL_DND (model)
2077 +      && gtk_tree_model_dnd_serialize (GTK_TREE_MODEL_DND (model),
2078 +                                       source_info->selection,
2079 +                                       selection_data))
2080      return;
2081  
2082 +  /* Otherwise we fall back on the old methods.
2083 +   * For source_row, we take the first in a series of path.
2084 +  */
2085 +  source_row = gtk_tree_row_reference_get_path (source_info->selection->data);
2086 +
2087    /* We can implement the GTK_TREE_MODEL_ROW target generically for
2088     * any model; for DragSource models there are some other targets
2089     * we also support.
2090 @@ -7072,54 +6964,68 @@ gtk_tree_view_drag_data_get (GtkWidget        *widget,
2091        gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
2092                                            source_row,
2093                                            selection_data))
2094 -    goto done;
2095 +    {
2096 +      gtk_tree_path_free (source_row);
2097 +      return;
2098 +    }
2099  
2100    /* If drag_data_get does nothing, try providing row data. */
2101    if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
2102      {
2103        gtk_tree_set_row_drag_data (selection_data,
2104 -				  model,
2105 +				  tree_view->priv->model,
2106  				  source_row);
2107      }
2108  
2109 - done:
2110    gtk_tree_path_free (source_row);
2111  }
2112  
2113 -
2114  static void
2115  gtk_tree_view_drag_data_delete (GtkWidget      *widget,
2116                                  GdkDragContext *context)
2117  {
2118 -  TreeViewDragInfo *di;
2119    GtkTreeModel *model;
2120    GtkTreeView *tree_view;
2121    GtkTreePath *source_row;
2122 +  GtkTreeViewSourceInfo *source_info;
2123  
2124    tree_view = GTK_TREE_VIEW (widget);
2125    model = gtk_tree_view_get_model (tree_view);
2126  
2127 -  if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
2128 +  source_info = gtk_tree_view_drag_context_get_source_info (context);
2129 +  if (!source_info)
2130      return;
2131  
2132 -  di = get_info (tree_view);
2133 -
2134 -  if (di == NULL)
2135 -    return;
2136 +  /* Remove the rows making up the selection from the model */
2137  
2138 -  source_row = get_source_row (context);
2139 +  /* We need to send a request to the model to remove the given
2140 +   * list of paths
2141 +   */
2142 +  if (GTK_IS_TREE_MODEL_DND (model)
2143 +      && gtk_tree_model_dnd_delete_rows (GTK_TREE_MODEL_DND (model),
2144 +                                         source_info->selection))
2145 +    {
2146 +      gtk_tree_view_drag_context_set_source_info (context, NULL, NULL);
2147 +      return;
2148 +    }
2149  
2150 -  if (source_row == NULL)
2151 +  /* Fallback on old interfaces
2152 +   * For source_row, we take the first in a series of path.
2153 +   */
2154 +  if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
2155      return;
2156  
2157 +  source_row = gtk_tree_row_reference_get_path (source_info->selection->data);
2158 +
2159    gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
2160                                           source_row);
2161  
2162    gtk_tree_path_free (source_row);
2163 -
2164 -  set_source_row (context, NULL, NULL);
2165 +  gtk_tree_view_drag_context_set_source_info (context, NULL, NULL);
2166  }
2167  
2168 +
2169 +/* Default signal handlers for destination side */
2170  static void
2171  gtk_tree_view_drag_leave (GtkWidget      *widget,
2172                            GdkDragContext *context,
2173 @@ -7134,6 +7040,19 @@ gtk_tree_view_drag_leave (GtkWidget      *widget,
2174    remove_open_timeout (GTK_TREE_VIEW (widget));
2175  }
2176  
2177 +static gboolean
2178 +gtk_tree_view_real_test_drop_drag (GtkTreeView             *tree_view,
2179 +                                   GdkDragContext          *context,
2180 +                                   GtkTreePath             *destination_path,
2181 +                                   GtkTreeViewDropPosition  position,
2182 +                                   GdkDragAction           *suggested_action,
2183 +                                   gboolean                *drop_drag)
2184 +{
2185 +  *drop_drag = TRUE;
2186 +  *suggested_action = GDK_ACTION_MOVE;
2187 +
2188 +  return TRUE;
2189 +}
2190  
2191  static gboolean
2192  gtk_tree_view_drag_motion (GtkWidget        *widget,
2193 @@ -7143,64 +7062,132 @@ gtk_tree_view_drag_motion (GtkWidget        *widget,
2194                             gint              y,
2195                             guint             time)
2196  {
2197 -  gboolean empty;
2198    GtkTreePath *path = NULL;
2199    GtkTreeViewDropPosition pos;
2200    GtkTreeView *tree_view;
2201 -  GdkDragAction suggested_action = 0;
2202 +  GtkTreeModel *model;
2203 +  GdkDragAction suggested_action;
2204    GdkAtom target;
2205 +  gboolean handled;
2206 +  gboolean drop_drag = TRUE;
2207  
2208    tree_view = GTK_TREE_VIEW (widget);
2209 +  model = gtk_tree_view_get_model (tree_view);
2210 +
2211 +  gtk_tree_view_set_drag_dest_row (tree_view, NULL, GTK_TREE_VIEW_DROP_INVALID);
2212  
2213 -  if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
2214 +  if (!tree_view->priv->is_drag_dest)
2215      return FALSE;
2216  
2217 -  gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
2218 +  /* Verify whether or not we can drop at this location */
2219 +  target = gtk_drag_dest_find_target (widget, context,
2220 +                                      gtk_drag_dest_get_target_list (widget));
2221 +  if (target == GDK_NONE)
2222 +    return FALSE;
2223 +
2224 +  /* Where is the cursor located ? */
2225 +  if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
2226 +                                          x, y,
2227 +                                          &path, &pos))
2228 +    {
2229 +      int length;
2230 +
2231 +      /* The cursor is not above a row */
2232 +      length = gtk_tree_model_iter_n_children (model, NULL);
2233 +
2234 +      /* FIXME: doesn't handle trees, need another trick here */
2235 +      path = gtk_tree_path_new_from_indices (length, -1);
2236 +      pos = GTK_TREE_VIEW_DROP_EMPTY_SPACE;
2237 +
2238 +
2239 +      remove_open_timeout (tree_view);
2240 +    }
2241  
2242 -  /* we only know this *after* set_desination_row */
2243 -  empty = tree_view->priv->empty_view_drop;
2244 +  /* Default suggested action */
2245 +  suggested_action = context->suggested_action;
2246 +  if (gtk_drag_get_source_widget (context) == widget)
2247 +    {
2248 +      /* Default to MOVE, unless the user has
2249 +       * pressed ctrl or shift to affect available actions
2250 +       */
2251 +      if ((context->actions & GDK_ACTION_MOVE) != 0)
2252 +        suggested_action = GDK_ACTION_MOVE;
2253 +    }
2254  
2255 -  if (path == NULL && !empty)
2256 +  if (GTK_IS_TREE_MODEL_DND (model))
2257      {
2258 -      /* Can't drop here. */
2259 +      g_signal_emit (tree_view, tree_view_signals[TEST_DROP_DRAG], 0,
2260 +                     context, path, pos, &suggested_action, &drop_drag, &handled);
2261 +
2262 +      /* We ignore the handled parameter as our default signal handler
2263 +       * returns TRUE anyway.
2264 +       */
2265 +      if (!drop_drag)
2266 +        {
2267 +          gtk_tree_path_free (path);
2268 +
2269 +          return FALSE;
2270 +        }
2271 +
2272 +      if (!gtk_tree_model_dnd_can_drop_rows (GTK_TREE_MODEL_DND (model),
2273 +                                             path, pos))
2274 +        {
2275 +          gtk_tree_path_free (path);
2276 +
2277 +          return FALSE;
2278 +        }
2279 +    }
2280 +
2281 +  /* FIXME: check old drag dest, possibly unset open timeout */
2282 +
2283 +  gtk_tree_view_set_drag_dest_row (tree_view, path, pos);
2284 +  gtk_tree_view_drag_context_set_dest_info (context, path, pos);
2285 +
2286 +  /* Update the drag status whether or not we can drop */
2287 +  if (!path && pos != GTK_TREE_VIEW_DROP_EMPTY_SPACE)
2288 +    {
2289 +      /* The cursor is not on a valid drop site */
2290        gdk_drag_status (context, 0, time);
2291      }
2292    else
2293      {
2294 -      if (tree_view->priv->open_dest_timeout == 0 &&
2295 -          (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
2296 -           pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
2297 +      GtkTreeViewDestInfo *dest_info;
2298 +
2299 +      if (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
2300 +          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)
2301          {
2302 -          tree_view->priv->open_dest_timeout =
2303 -            gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
2304 +          /* We can drop inside this path, so open it */
2305 +          add_open_timeout (tree_view);
2306          }
2307        else
2308          {
2309 -	  add_scroll_timeout (tree_view);
2310 -	}
2311 +          add_scroll_timeout (tree_view);
2312 +        }
2313 +
2314 +      dest_info = gtk_tree_view_drag_context_get_or_create_dest_info (context);
2315 +      dest_info->suggested_action = suggested_action;
2316  
2317        if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
2318          {
2319 -          /* Request data so we can use the source row when
2320 -           * determining whether to accept the drop
2321 +          /* For the old API, we use the source row to determine
2322 +           * whether to accept the drop.  For this we need the selection-data
2323 +           * and this is further handled in drag-data-received.
2324             */
2325 -          set_status_pending (context, suggested_action);
2326 +          dest_info->receive_for_drop = FALSE;
2327            gtk_drag_get_data (widget, context, target, time);
2328          }
2329        else
2330          {
2331 -          set_status_pending (context, 0);
2332 +          dest_info->receive_for_drop = TRUE;
2333            gdk_drag_status (context, suggested_action, time);
2334          }
2335      }
2336  
2337 -  if (path)
2338 -    gtk_tree_path_free (path);
2339 +  gtk_tree_path_free (path);
2340  
2341    return TRUE;
2342  }
2343  
2344 -
2345  static gboolean
2346  gtk_tree_view_drag_drop (GtkWidget        *widget,
2347                           GdkDragContext   *context,
2348 @@ -7209,61 +7196,170 @@ gtk_tree_view_drag_drop (GtkWidget        *widget,
2349                           gint              y,
2350                           guint             time)
2351  {
2352 +  GtkTreeModel *model;
2353    GtkTreeView *tree_view;
2354    GtkTreePath *path;
2355    GdkDragAction suggested_action = 0;
2356 +  gboolean drop_drag = TRUE;
2357    GdkAtom target = GDK_NONE;
2358 -  TreeViewDragInfo *di;
2359 -  GtkTreeModel *model;
2360 -  gboolean path_down_mode;
2361 -  gboolean drop_append_mode;
2362 +  gboolean handled;
2363 +  GtkTreeViewDropPosition pos;
2364 +  GtkTreeViewDestInfo *dest_info;
2365  
2366    tree_view = GTK_TREE_VIEW (widget);
2367 -
2368    model = gtk_tree_view_get_model (tree_view);
2369  
2370 -  remove_scroll_timeout (GTK_TREE_VIEW (widget));
2371 -  remove_open_timeout (GTK_TREE_VIEW (widget));
2372 +  if (!tree_view->priv->is_drag_dest)
2373 +    return FALSE;
2374  
2375 -  di = get_info (tree_view);
2376 +  remove_scroll_timeout (tree_view);
2377 +  remove_open_timeout (tree_view);
2378  
2379 -  if (di == NULL)
2380 +  /* Verify whether or not we can drop at this location */
2381 +  target = gtk_drag_dest_find_target (widget, context,
2382 +                                      gtk_drag_dest_get_target_list (widget));
2383 +  if (target == GDK_NONE)
2384      return FALSE;
2385  
2386 -  if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
2387 -    return FALSE;
2388 +  /* Where is the cursor located ? */
2389 +  if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
2390 +                                          x, y,
2391 +                                          &path, &pos))
2392 +    {
2393 +      int length;
2394  
2395 -  if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
2396 -    return FALSE;
2397 +      /* The cursor is not above a row */
2398 +      length = gtk_tree_model_iter_n_children (model, NULL);
2399  
2400 -  path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
2401 +      /* FIXME: doesn't handle trees, need another trick here */
2402 +      path = gtk_tree_path_new_from_indices (length, -1);
2403 +      pos = GTK_TREE_VIEW_DROP_EMPTY_SPACE;
2404 +
2405 +      /* FIXME: this might need compat foo, as EMPTY_SPACE did
2406 +       * not exist in the old API.
2407 +       */
2408 +    }
2409  
2410 -  if (target != GDK_NONE && path != NULL)
2411 +  /* Default suggested action */
2412 +  suggested_action = context->suggested_action;
2413 +  if (gtk_drag_get_source_widget (context) == widget)
2414      {
2415 -      /* in case a motion had requested drag data, change things so we
2416 -       * treat drag data receives as a drop.
2417 +      /* Default to MOVE, unless the user has
2418 +       * pressed ctrl or shift to affect available actions
2419         */
2420 -      set_status_pending (context, 0);
2421 -      set_dest_row (context, model, path,
2422 -                    path_down_mode, tree_view->priv->empty_view_drop,
2423 -                    drop_append_mode);
2424 +      if ((context->actions & GDK_ACTION_MOVE) != 0)
2425 +        suggested_action = GDK_ACTION_MOVE;
2426      }
2427  
2428 -  if (path)
2429 -    gtk_tree_path_free (path);
2430 +  if (GTK_IS_TREE_MODEL_DND (model))
2431 +    {
2432 +      g_signal_emit (tree_view, tree_view_signals[TEST_DROP_DRAG], 0,
2433 +                     context, path, pos, &suggested_action, &drop_drag, &handled);
2434  
2435 -  /* Unset this thing */
2436 -  gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
2437 -                                   NULL,
2438 -                                   GTK_TREE_VIEW_DROP_BEFORE);
2439 +      if (!drop_drag)
2440 +        {
2441 +          gtk_tree_path_free (path);
2442 +          return FALSE;
2443 +        }
2444 +
2445 +      if (!gtk_tree_model_dnd_can_drop_rows (GTK_TREE_MODEL_DND (model),
2446 +                                             path, pos))
2447 +        {
2448 +          gtk_tree_path_free (path);
2449 +
2450 +          return FALSE;
2451 +        }
2452 +    }
2453 +  else
2454 +    {
2455 +      if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
2456 +        return FALSE;
2457 +    }
2458 +
2459 +
2460 +  /* Save path, pos as drop location */
2461 +  gtk_tree_view_drag_context_set_dest_info (context, path, pos);
2462 +  dest_info = gtk_tree_view_drag_context_get_or_create_dest_info (context);
2463 +  dest_info->receive_for_drop = TRUE;
2464 +
2465 +  /* Unset destination marker */
2466 +  gtk_tree_view_set_drag_dest_row (tree_view, NULL,
2467 +                                   GTK_TREE_VIEW_DROP_INVALID);
2468 +
2469 +  gtk_tree_path_free (path);
2470  
2471    if (target != GDK_NONE)
2472      {
2473        gtk_drag_get_data (widget, context, target, time);
2474        return TRUE;
2475      }
2476 +
2477 +  return FALSE;
2478 +}
2479 +
2480 +static void
2481 +gtk_tree_view_drag_motion_drag_data_received (GtkTreeView      *tree_view,
2482 +                                              GdkDragContext   *context,
2483 +                                              GtkSelectionData *selection_data,
2484 +                                              guint             time)
2485 +{
2486 +  GtkTreePath *path;
2487 +  GtkTreeModel *model;
2488 +  GtkTreeViewDestInfo *dest_info;
2489 +  GdkDragAction suggested_action;
2490 +  gboolean path_down_mode;
2491 +
2492 +  model = gtk_tree_view_get_model (tree_view);
2493 +  dest_info = gtk_tree_view_drag_context_get_dest_info (context);
2494 +
2495 +  suggested_action = dest_info->suggested_action;
2496 +
2497 +  /* Where is the cursor located? */
2498 +  if (dest_info->path)
2499 +    path = gtk_tree_path_copy (dest_info->path);
2500 +  else if (dest_info->position == GTK_TREE_VIEW_DROP_EMPTY_SPACE)
2501 +    path = gtk_tree_path_new_from_indices (0, -1);
2502    else
2503 -    return FALSE;
2504 +    path = NULL;
2505 +
2506 +  /* FIXME: might need compat foo. */
2507 +  path_down_mode = FALSE;
2508 +
2509 +  if (!path)
2510 +    suggested_action = 0;
2511 +  else if (path_down_mode)
2512 +    gtk_tree_path_down (path);
2513 +
2514 +  if (suggested_action)
2515 +    {
2516 +      if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
2517 +                                                 path,
2518 +                                                 selection_data))
2519 +        {
2520 +          if (path_down_mode)
2521 +            {
2522 +              path_down_mode = FALSE;
2523 +              gtk_tree_path_up (path);
2524 +
2525 +              if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
2526 +                                                         path,
2527 +                                                         selection_data))
2528 +                suggested_action = 0;
2529 +            }
2530 +          else
2531 +            suggested_action = 0;
2532 +        }
2533 +    }
2534 +
2535 +  gdk_drag_status (context, suggested_action, time);
2536 +
2537 +  if (path)
2538 +    gtk_tree_path_free (path);
2539 +
2540 +  /* If you can't drop, remove user drop indicator until the next motion */
2541 +  if (suggested_action == 0)
2542 +    gtk_tree_view_set_drag_dest_row (tree_view,
2543 +                                     NULL, GTK_TREE_VIEW_DROP_BEFORE);
2544  }
2545  
2546  static void
2547 @@ -7276,102 +7372,80 @@ gtk_tree_view_drag_data_received (GtkWidget        *widget,
2548                                    guint             info,
2549                                    guint             time)
2550  {
2551 -  GtkTreePath *path;
2552 -  TreeViewDragInfo *di;
2553    gboolean accepted = FALSE;
2554    GtkTreeModel *model;
2555    GtkTreeView *tree_view;
2556    GtkTreePath *dest_row;
2557 -  GdkDragAction suggested_action;
2558    gboolean path_down_mode;
2559 -  gboolean drop_append_mode;
2560 +  GtkTreeViewDestInfo *dest_info;
2561  
2562    tree_view = GTK_TREE_VIEW (widget);
2563 -
2564    model = gtk_tree_view_get_model (tree_view);
2565  
2566 -  if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
2567 +  if (!tree_view->priv->is_drag_dest)
2568      return;
2569  
2570 -  di = get_info (tree_view);
2571 +  dest_info = gtk_tree_view_drag_context_get_dest_info (context);
2572  
2573 -  if (di == NULL)
2574 -    return;
2575 -
2576 -  suggested_action = get_status_pending (context);
2577 -
2578 -  if (suggested_action)
2579 +  if (!dest_info->receive_for_drop)
2580      {
2581 -      /* We are getting this data due to a request in drag_motion,
2582 -       * rather than due to a request in drag_drop, so we are just
2583 -       * supposed to call drag_status, not actually paste in the
2584 -       * data.
2585 +      /* drag_data_received was called by drag_motion to figure out
2586 +       * the correct value to pass to drag_status.
2587         */
2588 -      path = get_logical_dest_row (tree_view, &path_down_mode,
2589 -                                   &drop_append_mode);
2590 -
2591 -      if (path == NULL)
2592 -        suggested_action = 0;
2593 -      else if (path_down_mode)
2594 -        gtk_tree_path_down (path);
2595  
2596 -      if (suggested_action)
2597 -        {
2598 -	  if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
2599 -						     path,
2600 -						     selection_data))
2601 -            {
2602 -              if (path_down_mode)
2603 -                {
2604 -                  path_down_mode = FALSE;
2605 -                  gtk_tree_path_up (path);
2606 -
2607 -                  if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
2608 -                                                             path,
2609 -                                                             selection_data))
2610 -                    suggested_action = 0;
2611 -                }
2612 -              else
2613 -	        suggested_action = 0;
2614 -            }
2615 -        }
2616 -
2617 -      gdk_drag_status (context, suggested_action, time);
2618 -
2619 -      if (path)
2620 -        gtk_tree_path_free (path);
2621 -
2622 -      /* If you can't drop, remove user drop indicator until the next motion */
2623 -      if (suggested_action == 0)
2624 -        gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
2625 -                                         NULL,
2626 -                                         GTK_TREE_VIEW_DROP_BEFORE);
2627 +      if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST,
2628 +                            "drag_data_received"))
2629 +        return;
2630  
2631 +      gtk_tree_view_drag_motion_drag_data_received (tree_view,
2632 +                                                    context,
2633 +                                                    selection_data,
2634 +                                                    time);
2635        return;
2636      }
2637  
2638 -  dest_row = get_dest_row (context, &path_down_mode);
2639 -
2640 -  if (dest_row == NULL)
2641 -    return;
2642 -
2643 -  if (selection_data->length >= 0)
2644 +  /* Get destination row that was previously saved */
2645 +  if (GTK_IS_TREE_MODEL_DND (model))
2646      {
2647 -      if (path_down_mode)
2648 +      if (selection_data->length >= 0)
2649          {
2650 -          gtk_tree_path_down (dest_row);
2651 -          if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
2652 -                                                     dest_row, selection_data))
2653 -            gtk_tree_path_up (dest_row);
2654 +          accepted = gtk_tree_model_dnd_deserialize (GTK_TREE_MODEL_DND (model),
2655 +                                                     dest_info->path,
2656 +                                                     dest_info->position,
2657 +                                                     selection_data);
2658          }
2659      }
2660  
2661 -  if (selection_data->length >= 0)
2662 +  if (!accepted)
2663      {
2664 -      if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
2665 -                                                 dest_row,
2666 -                                                 selection_data))
2667 -        accepted = TRUE;
2668 +      if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST,
2669 +                            "drag_data_received"))
2670 +        return;
2671 +
2672 +      /* FIXME: might need compat. foo */
2673 +      dest_row = dest_info->path;
2674 +      if (dest_row == NULL)
2675 +        return;
2676 +
2677 +      path_down_mode = FALSE;
2678 +      if (selection_data->length >= 0)
2679 +        {
2680 +          if (path_down_mode)
2681 +            {
2682 +              gtk_tree_path_down (dest_row);
2683 +              if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
2684 +                                                         dest_row, selection_data))
2685 +                gtk_tree_path_up (dest_row);
2686 +            }
2687 +        }
2688 +
2689 +      if (selection_data->length >= 0)
2690 +        {
2691 +          if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
2692 +                                                     dest_row,
2693 +                                                     selection_data))
2694 +            accepted = TRUE;
2695 +        }
2696      }
2697  
2698    gtk_drag_finish (context,
2699 @@ -7379,18 +7453,21 @@ gtk_tree_view_drag_data_received (GtkWidget        *widget,
2700                     (context->action == GDK_ACTION_MOVE),
2701                     time);
2702  
2703 -  if (gtk_tree_path_get_depth (dest_row) == 1
2704 -      && gtk_tree_path_get_indices (dest_row)[0] == 0)
2705 +  /* When reordering in the same model, we should explicitly scroll to
2706 +   * row 0 if we dropped there.
2707 +   */
2708 +  /* FIXME: needs to be multi-row aware */
2709 +  if (gtk_tree_path_get_depth (dest_info->path) == 1
2710 +      && gtk_tree_path_get_indices (dest_info->path)[0] == 0)
2711      {
2712        /* special special case drag to "0", scroll to first item */
2713        if (!tree_view->priv->scroll_to_path)
2714 -        gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
2715 +        gtk_tree_view_scroll_to_cell (tree_view, dest_info->path,
2716 +                                      NULL, FALSE, 0.0, 0.0);
2717      }
2718  
2719 -  gtk_tree_path_free (dest_row);
2720 -
2721 -  /* drop dest_row */
2722 -  set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
2723 +  /* Clear saved destination row */
2724 +  gtk_tree_view_drag_context_set_dest_info (context, NULL, 0);
2725  }
2726  
2727  
2728 @@ -7398,7 +7475,6 @@ gtk_tree_view_drag_data_received (GtkWidget        *widget,
2729  /* GtkContainer Methods
2730   */
2731  
2732 -
2733  static void
2734  gtk_tree_view_remove (GtkContainer *container,
2735  		      GtkWidget    *widget)
2736 @@ -10655,6 +10731,13 @@ gtk_tree_view_set_model (GtkTreeView  *tree_view,
2737  					    gtk_tree_view_rows_reordered,
2738  					    tree_view);
2739  
2740 +      if (tree_view->priv->serializer
2741 +          && GTK_IS_TREE_MODEL_DND (tree_view->priv->model))
2742 +        {
2743 +          gtk_tree_model_dnd_remove_serializer (GTK_TREE_MODEL_DND (tree_view->priv->model),
2744 +                                                tree_view->priv->serializer);
2745 +        }
2746 +
2747        for (; tmplist; tmplist = tmplist->next)
2748  	_gtk_tree_view_column_unset_model (tmplist->data,
2749  					   tree_view->priv->model);
2750 @@ -10732,6 +10815,13 @@ gtk_tree_view_set_model (GtkTreeView  *tree_view,
2751  			G_CALLBACK (gtk_tree_view_rows_reordered),
2752  			tree_view);
2753  
2754 +      if (tree_view->priv->serializer
2755 +          && GTK_IS_TREE_MODEL_DND (tree_view->priv->model))
2756 +        {
2757 +          gtk_tree_model_dnd_add_serializer (GTK_TREE_MODEL_DND (tree_view->priv->model),
2758 +                                             tree_view->priv->serializer);
2759 +        }
2760 +
2761        flags = gtk_tree_model_get_flags (tree_view->priv->model);
2762        if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
2763          GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
2764 @@ -12410,26 +12500,21 @@ gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
2765    if (tree_view->priv->reorderable == reorderable)
2766      return;
2767  
2768 +  /* Handle source target list first */
2769    if (reorderable)
2770 -    {
2771 -      const GtkTargetEntry row_targets[] = {
2772 -        { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
2773 -      };
2774 +   {
2775 +      /* FIXME: start button mask should be button 1
2776 +       * and the only supported action move.
2777 +       */
2778  
2779 -      gtk_tree_view_enable_model_drag_source (tree_view,
2780 -					      GDK_BUTTON1_MASK,
2781 -					      row_targets,
2782 -					      G_N_ELEMENTS (row_targets),
2783 -					      GDK_ACTION_MOVE);
2784 -      gtk_tree_view_enable_model_drag_dest (tree_view,
2785 -					    row_targets,
2786 -					    G_N_ELEMENTS (row_targets),
2787 -					    GDK_ACTION_MOVE);
2788 +     gtk_tree_view_set_is_drag_source (tree_view, TRUE);
2789 +     gtk_tree_view_set_is_drag_dest (tree_view, TRUE);
2790      }
2791    else
2792      {
2793 -      gtk_tree_view_unset_rows_drag_source (tree_view);
2794 -      gtk_tree_view_unset_rows_drag_dest (tree_view);
2795 +      /* FIXME: does this remove the target from the list? */
2796 +      gtk_tree_view_set_is_drag_source (tree_view, FALSE);
2797 +      gtk_tree_view_set_is_drag_dest (tree_view, FALSE);
2798      }
2799  
2800    tree_view->priv->reorderable = reorderable;
2801 @@ -13258,6 +13343,7 @@ gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
2802    return retval;
2803  }
2804  
2805 +#if 0
2806  static void
2807  unset_reorderable (GtkTreeView *tree_view)
2808  {
2809 @@ -13267,6 +13353,65 @@ unset_reorderable (GtkTreeView *tree_view)
2810        g_object_notify (G_OBJECT (tree_view), "reorderable");
2811      }
2812  }
2813 +#endif
2814 +
2815 +void
2816 +gtk_tree_view_set_is_drag_source (GtkTreeView *tree_view,
2817 +                                  gboolean     is_drag_source)
2818 +{
2819 +  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
2820 +
2821 +  if (tree_view->priv->is_drag_source == !!is_drag_source)
2822 +    return;
2823 +
2824 +  if (is_drag_source)
2825 +    {
2826 +      GtkTargetList *targets;
2827 +
2828 +      g_return_if_fail (GTK_IS_TREE_DRAG_SOURCE (tree_view->priv->model));
2829 +
2830 +      /* FIXME: what to do with the action? */
2831 +      gtk_drag_source_set (GTK_WIDGET (tree_view),
2832 +                           0,
2833 +                           NULL, 0,
2834 +                           GDK_ACTION_MOVE);
2835 +
2836 +      targets = gtk_tree_model_dnd_get_targets (GTK_TREE_MODEL_DND (tree_view->priv->model));
2837 +      gtk_drag_source_set_target_list (GTK_WIDGET (tree_view), targets);
2838 +    }
2839 +  else
2840 +    gtk_drag_source_unset (GTK_WIDGET (tree_view));
2841 +
2842 +  tree_view->priv->is_drag_source = is_drag_source;
2843 +}
2844 +
2845 +void
2846 +gtk_tree_view_set_is_drag_dest (GtkTreeView *tree_view,
2847 +                                gboolean     is_drag_dest)
2848 +{
2849 +  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
2850 +
2851 +  if (tree_view->priv->is_drag_dest == !!is_drag_dest)
2852 +    return;
2853 +
2854 +  if (is_drag_dest)
2855 +    {
2856 +      GtkTargetList *targets;
2857 +
2858 +      /* FIXME: what to do with the action? */
2859 +      gtk_drag_dest_set (GTK_WIDGET (tree_view),
2860 +                         0,
2861 +                         NULL, 0,
2862 +                         GDK_ACTION_MOVE);
2863 +
2864 +      targets = gtk_tree_model_dnd_get_targets (GTK_TREE_MODEL_DND (tree_view->priv->model));
2865 +      gtk_drag_dest_set_target_list (GTK_WIDGET (tree_view), targets);
2866 +    }
2867 +  else
2868 +    gtk_drag_dest_unset (GTK_WIDGET (tree_view));
2869 +
2870 +  tree_view->priv->is_drag_dest = is_drag_dest;
2871 +}
2872  
2873  /**
2874   * gtk_tree_view_enable_model_drag_source:
2875 @@ -13278,6 +13423,8 @@ unset_reorderable (GtkTreeView *tree_view)
2876   *    widget
2877   * 
2878   * Turns @tree_view into a drag source for automatic DND.
2879 + *
2880 + * Deprecated
2881   **/
2882  void
2883  gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
2884 @@ -13286,8 +13433,6 @@ gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
2885  					gint                      n_targets,
2886  					GdkDragAction             actions)
2887  {
2888 -  TreeViewDragInfo *di;
2889 -
2890    g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
2891  
2892    gtk_drag_source_set (GTK_WIDGET (tree_view),
2893 @@ -13296,13 +13441,19 @@ gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
2894  		       n_targets,
2895  		       actions);
2896  
2897 -  di = ensure_info (tree_view);
2898 +  tree_view->priv->is_drag_source = TRUE;
2899  
2900 -  di->start_button_mask = start_button_mask;
2901 -  di->source_actions = actions;
2902 -  di->source_set = TRUE;
2903 +  if (!tree_view->priv->serializer)
2904 +    tree_view->priv->serializer = g_object_new (GTK_TYPE_TREE_MODEL_ROW_SERIALIZER, 0);
2905 +  else
2906 +    g_object_ref (tree_view->priv->serializer);
2907  
2908 -  unset_reorderable (tree_view);
2909 +  /* FIXME: we should check if model is one of the models internal
2910 +   * to GTK+, only those implement GTK_TREE_MODEL_ROW
2911 +   */
2912 +  if (GTK_IS_TREE_MODEL_DND (tree_view->priv->model))
2913 +    gtk_tree_model_dnd_add_serializer (GTK_TREE_MODEL_DND (tree_view->priv->model),
2914 +                                       tree_view->priv->serializer);
2915  }
2916  
2917  /**
2918 @@ -13314,6 +13465,8 @@ gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
2919   *    widget
2920   * 
2921   * Turns @tree_view into a drop destination for automatic DND.
2922 + *
2923 + * Deprecated
2924   **/
2925  void
2926  gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
2927 @@ -13321,8 +13474,6 @@ gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
2928  				      gint                      n_targets,
2929  				      GdkDragAction             actions)
2930  {
2931 -  TreeViewDragInfo *di;
2932 -
2933    g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
2934  
2935    gtk_drag_dest_set (GTK_WIDGET (tree_view),
2936 @@ -13331,10 +13482,16 @@ gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
2937                       n_targets,
2938                       actions);
2939  
2940 -  di = ensure_info (tree_view);
2941 -  di->dest_set = TRUE;
2942 +  tree_view->priv->is_drag_dest = TRUE;
2943  
2944 -  unset_reorderable (tree_view);
2945 +  if (!tree_view->priv->serializer)
2946 +    tree_view->priv->serializer = g_object_new (GTK_TYPE_TREE_MODEL_ROW_SERIALIZER, 0);
2947 +  else
2948 +    g_object_ref (tree_view->priv->serializer);
2949 +
2950 +  if (GTK_IS_TREE_MODEL_DND (tree_view->priv->model))
2951 +    gtk_tree_model_dnd_add_serializer (GTK_TREE_MODEL_DND (tree_view->priv->model),
2952 +                                       tree_view->priv->serializer);
2953  }
2954  
2955  /**
2956 @@ -13342,29 +13499,21 @@ gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
2957   * @tree_view: a #GtkTreeView
2958   * 
2959   * Undoes the effect of gtk_tree_view_enable_model_drag_source().
2960 + *
2961 + * Deprecated
2962   **/
2963  void
2964  gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
2965  {
2966 -  TreeViewDragInfo *di;
2967 -
2968    g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
2969  
2970 -  di = get_info (tree_view);
2971 +  if (GTK_IS_TREE_MODEL_DND (tree_view->priv->model))
2972 +    gtk_tree_model_dnd_remove_serializer (GTK_TREE_MODEL_DND (tree_view->priv->model),
2973 +                                          tree_view->priv->serializer);
2974  
2975 -  if (di)
2976 -    {
2977 -      if (di->source_set)
2978 -        {
2979 -          gtk_drag_source_unset (GTK_WIDGET (tree_view));
2980 -          di->source_set = FALSE;
2981 -        }
2982 +  g_object_unref (tree_view->priv->serializer);
2983  
2984 -      if (!di->dest_set && !di->source_set)
2985 -        remove_info (tree_view);
2986 -    }
2987 -  
2988 -  unset_reorderable (tree_view);
2989 +  gtk_tree_view_set_is_drag_source (tree_view, FALSE);
2990  }
2991  
2992  /**
2993 @@ -13372,29 +13521,21 @@ gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
2994   * @tree_view: a #GtkTreeView
2995   * 
2996   * Undoes the effect of gtk_tree_view_enable_model_drag_dest().
2997 + *
2998 + * Deprecated
2999   **/
3000  void
3001  gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
3002  {
3003 -  TreeViewDragInfo *di;
3004 -
3005    g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
3006  
3007 -  di = get_info (tree_view);
3008 +  if (GTK_IS_TREE_MODEL_DND (tree_view->priv->model))
3009 +    gtk_tree_model_dnd_remove_serializer (GTK_TREE_MODEL_DND (tree_view->priv->model),
3010 +                                          tree_view->priv->serializer);
3011  
3012 -  if (di)
3013 -    {
3014 -      if (di->dest_set)
3015 -        {
3016 -          gtk_drag_dest_unset (GTK_WIDGET (tree_view));
3017 -          di->dest_set = FALSE;
3018 -        }
3019 +  g_object_unref (tree_view->priv->serializer);
3020  
3021 -      if (!di->dest_set && !di->source_set)
3022 -        remove_info (tree_view);
3023 -    }
3024 -
3025 -  unset_reorderable (tree_view);
3026 +  gtk_tree_view_set_is_drag_dest (tree_view, FALSE);
3027  }
3028  
3029  /**
3030 @@ -13607,6 +13748,190 @@ gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
3031  
3032  
3033  /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
3034 +static void
3035 +gtk_tree_view_calculate_dnd_icon_size (GtkTreeView *tree_view,
3036 +                                       GList       *rows,
3037 +                                       int         *width,
3038 +                                       int         *height)
3039 +{
3040 +  if (width)
3041 +    *width = tree_view->priv->hadjustment->upper;
3042 +
3043 +  if (height)
3044 +    {
3045 +      GList *list;
3046 +
3047 +      *height = 0;
3048 +
3049 +      for (list = rows; list; list = list->next)
3050 +        {
3051 +          GtkRBTree *tree;
3052 +          GtkRBNode *node;
3053 +
3054 +          _gtk_tree_view_find_node (tree_view, list->data,
3055 +                                    &tree, &node);
3056 +
3057 +          *height += ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
3058 +        }
3059 +    }
3060 +}
3061 +
3062 +/* This is one evil copy from
3063 + * gtk_tree_view_create_row_drag_icon() since that is public API
3064 + * and cant chance ...
3065 + */
3066 +static GdkPixmap *
3067 +gtk_tree_view_create_dnd_icon_from_list (GtkTreeView *tree_view,
3068 +                                         GList       *rows)
3069 +{
3070 +  GtkTreeIter iter;
3071 +  GtkRBTree *tree;
3072 +  GtkRBNode *node;
3073 +  gint cell_offset;
3074 +  GList *list;
3075 +  GdkRectangle background_area;
3076 +  GdkRectangle expose_area;
3077 +  GtkWidget *widget;
3078 +  gint depth;
3079 +  /* start drawing inside the black outline */
3080 +  gint x = 1, y = 1;
3081 +  GdkDrawable *drawable;
3082 +  gint bin_window_width;
3083 +  gboolean is_separator = FALSE;
3084 +  gboolean rtl;
3085 +  int width, height;
3086 +  GList *rlist;
3087 +
3088 +  widget = GTK_WIDGET (tree_view);
3089 +
3090 +  if (!GTK_WIDGET_REALIZED (tree_view))
3091 +    return NULL;
3092 +
3093 +  gtk_tree_view_calculate_dnd_icon_size (tree_view, rows, &width, &height);
3094 +
3095 +  drawable = gdk_pixmap_new (tree_view->priv->bin_window,
3096 +                             width + 2, height + 2, -1);
3097 +
3098 +  for (rlist = rows; rlist; rlist = rlist->next)
3099 +    {
3100 +      GtkTreePath *path = rlist->data;
3101 +
3102 +      depth = gtk_tree_path_get_depth (path);
3103 +
3104 +      _gtk_tree_view_find_node (tree_view,
3105 +                                path,
3106 +                                &tree,
3107 +                                &node);
3108 +
3109 +
3110 +      if (!gtk_tree_model_get_iter (tree_view->priv->model,
3111 +                                    &iter,
3112 +                                    path))
3113 +        return NULL;
3114 +
3115 +      is_separator = row_is_separator (tree_view, &iter, NULL);
3116 +
3117 +      cell_offset = x;
3118 +
3119 +      background_area.y = y;
3120 +      background_area.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
3121 +
3122 +      gdk_drawable_get_size (tree_view->priv->bin_window,
3123 +                             &bin_window_width, NULL);
3124 +
3125 +      expose_area.x = 0;
3126 +      expose_area.y = y;
3127 +      expose_area.width = width + 2;
3128 +      expose_area.height = background_area.height + 2;
3129 +
3130 +      gdk_draw_rectangle (drawable,
3131 +                          widget->style->base_gc [GTK_WIDGET_STATE (widget)],
3132 +                          TRUE,
3133 +                          0, y,
3134 +                          bin_window_width + 2,
3135 +                          background_area.height + 2);
3136 +
3137 +      rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
3138 +
3139 +      for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
3140 +           list;
3141 +           list = (rtl ? list->prev : list->next))
3142 +        {
3143 +          GtkTreeViewColumn *column = list->data;
3144 +          GdkRectangle cell_area;
3145 +          gint vertical_separator;
3146 +
3147 +          if (!column->visible)
3148 +            continue;
3149 +
3150 +          gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
3151 +                                                   GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
3152 +                                                   node->children?TRUE:FALSE);
3153 +
3154 +          background_area.x = cell_offset;
3155 +          background_area.width = column->width;
3156 +
3157 +          gtk_widget_style_get (widget,
3158 +                                "vertical-separator", &vertical_separator,
3159 +                                NULL);
3160 +
3161 +          cell_area = background_area;
3162 +
3163 +          cell_area.y += vertical_separator / 2;
3164 +          cell_area.height -= vertical_separator;
3165 +
3166 +          if (gtk_tree_view_is_expander_column (tree_view, column))
3167 +            {
3168 +              if (!rtl)
3169 +                cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
3170 +              cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
3171 +
3172 +              if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
3173 +                {
3174 +                  if (!rtl)
3175 +                    cell_area.x += depth * tree_view->priv->expander_size;
3176 +                  cell_area.width -= depth * tree_view->priv->expander_size;
3177 +                }
3178 +            }
3179 +
3180 +          if (gtk_tree_view_column_cell_is_visible (column))
3181 +            {
3182 +              if (is_separator)
3183 +                gtk_paint_hline (widget->style,
3184 +                                 drawable,
3185 +                                 GTK_STATE_NORMAL,
3186 +                                 &cell_area,
3187 +                                 widget,
3188 +                                 NULL,
3189 +                                 cell_area.x,
3190 +                                 cell_area.x + cell_area.width,
3191 +                                 cell_area.y + cell_area.height / 2);
3192 +              else
3193 +                _gtk_tree_view_column_cell_render (column,
3194 +                                                   drawable,
3195 +                                                   &background_area,
3196 +                                                   &cell_area,
3197 +                                                   &expose_area,
3198 +                                                   0);
3199 +            }
3200 +
3201 +          cell_offset += column->width;
3202 +        }
3203 +
3204 +      y += background_area.height;
3205 +    }
3206 +
3207 +  gdk_draw_rectangle (drawable,
3208 +                      widget->style->black_gc,
3209 +                      FALSE,
3210 +                      0, 0,
3211 +                      width + 1,
3212 +                      height + 1);
3213 +
3214 +  return drawable;
3215 +
3216 +}
3217 +
3218  /**
3219   * gtk_tree_view_create_row_drag_icon:
3220   * @tree_view: a #GtkTreeView
3221 diff --git a/gtk/gtktreeview.h b/gtk/gtktreeview.h
3222 index 098ab5c..2eab171 100644
3223 --- a/gtk/gtktreeview.h
3224 +++ b/gtk/gtktreeview.h
3225 @@ -42,7 +42,9 @@ typedef enum
3226     * if into is not possible)
3227     */
3228    GTK_TREE_VIEW_DROP_INTO_OR_BEFORE,
3229 -  GTK_TREE_VIEW_DROP_INTO_OR_AFTER
3230 +  GTK_TREE_VIEW_DROP_INTO_OR_AFTER,
3231 +  GTK_TREE_VIEW_DROP_EMPTY_SPACE,
3232 +  GTK_TREE_VIEW_DROP_INVALID
3233  } GtkTreeViewDropPosition;
3234  
3235  #define GTK_TYPE_TREE_VIEW		(gtk_tree_view_get_type ())
3236 @@ -106,9 +108,20 @@ struct _GtkTreeViewClass
3237    gboolean (* select_cursor_parent)       (GtkTreeView       *tree_view);
3238    gboolean (* start_interactive_search)   (GtkTreeView       *tree_view);
3239  
3240 +  /* New drag and drop API */
3241 +  gboolean (* test_start_drag)            (GtkTreeView             *tree_view,
3242 +                                           GList                   *selection,
3243 +                                           gint                     button,
3244 +                                           GdkDragAction           *action,
3245 +                                           gboolean                *start_drag);
3246 +  gboolean (* test_drop_drag)             (GtkTreeView             *tree_view,
3247 +                                           GdkDragContext          *context,
3248 +                                           GtkTreePath             *destination_path,
3249 +                                           GtkTreeViewDropPosition  position,
3250 +                                           GdkDragAction           *suggested_action,
3251 +                                           gboolean                *drop_drag);
3252 +
3253    /* Padding for future expansion */
3254 -  void (*_gtk_reserved0) (void);
3255 -  void (*_gtk_reserved1) (void);
3256    void (*_gtk_reserved2) (void);
3257    void (*_gtk_reserved3) (void);
3258    void (*_gtk_reserved4) (void);
3259 @@ -278,6 +291,11 @@ gboolean               gtk_tree_view_get_visible_range             (GtkTreeView
3260  								    GtkTreePath              **end_path);
3261  
3262  /* Drag-and-Drop support */
3263 +void gtk_tree_view_set_is_drag_source (GtkTreeView *tree_view,
3264 +                                       gboolean     drag_source);
3265 +void gtk_tree_view_set_is_drag_dest   (GtkTreeView *tree_view,
3266 +                                       gboolean     drag_dest);
3267 +
3268  void                   gtk_tree_view_enable_model_drag_source      (GtkTreeView               *tree_view,
3269  								    GdkModifierType            start_button_mask,
3270  								    const GtkTargetEntry      *targets,
3271 diff --git a/tests/Makefile.am b/tests/Makefile.am
3272 index edd18b0..270361c 100644
3273 --- a/tests/Makefile.am
3274 +++ b/tests/Makefile.am
3275 @@ -66,6 +66,7 @@ noinst_PROGRAMS =  $(TEST_PROGS)	\
3276  	testtext			\
3277  	testtoolbar			\
3278  	stresstest-toolbar		\
3279 +	testtreednd			\
3280  	testtreeedit			\
3281  	testtreemodel			\
3282  	testtreeview			\
3283 @@ -139,6 +140,7 @@ testsocket_child_DEPENDENCIES = $(DEPS)
3284  testspinbutton_DEPENDENCIES = $(TEST_DEPS)
3285  teststatusicon_DEPENDENCIES = $(TEST_DEPS)
3286  testtext_DEPENDENCIES = $(TEST_DEPS)
3287 +testtreednd_DEPENDENCIES = $(DEPS)
3288  testtreeedit_DEPENDENCIES = $(DEPS)
3289  testtreemodel_DEPENDENCIES = $(DEPS)
3290  testtreeview_DEPENDENCIES = $(DEPS)
3291 @@ -194,6 +196,7 @@ testspinbutton_LDADD = $(LDADDS)
3292  teststatusicon_LDADD = $(LDADDS)
3293  testtoolbar_LDADD = $(LDADDS)
3294  stresstest_toolbar_LDADD = $(LDADDS)
3295 +testtreednd_LDADD = $(LDADDS)
3296  testtreeedit_LDADD = $(LDADDS)
3297  testtreemodel_LDADD = $(LDADDS)
3298  testtreeview_LDADD = $(LDADDS)
3299 @@ -232,6 +235,9 @@ testgtk_SOURCES =	\
3300  	prop-editor.c   \
3301  	testgtk.c 	
3302  
3303 +testtreednd_SOURCES = 	\
3304 +	testtreednd.c
3305 +
3306  testtreeedit_SOURCES = 	\
3307  	testtreeedit.c
3308  
3309 diff --git a/tests/treestoretest.c b/tests/treestoretest.c
3310 index 080bc41..4ac6bdd 100644
3311 --- a/tests/treestoretest.c
3312 +++ b/tests/treestoretest.c
3313 @@ -326,6 +326,9 @@ make_window (gint view_type)
3314        break;
3315      }
3316  
3317 +  gtk_tree_view_set_is_drag_source (GTK_TREE_VIEW (tree_view), TRUE);
3318 +  gtk_tree_view_set_is_drag_dest (GTK_TREE_VIEW (tree_view), TRUE);
3319 +
3320    gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (tree_view), TRUE);
3321    selection = G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)));
3322    gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection), GTK_SELECTION_SINGLE);

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2021-02-25 09:59:00, 9.1 KB) [[attachment:gtk-simple-list-01-handle-toggle-renderers.diff]]
  • [get | view] (2021-02-25 09:59:00, 1.7 KB) [[attachment:gtk-simple-list-02-remove-set-cell-renderer-stub.diff]]
  • [get | view] (2021-02-25 09:59:00, 2.2 KB) [[attachment:gtk-simple-list-03-add-new-with-titles-constructor.diff]]
  • [get | view] (2021-02-25 09:59:00, 34.7 KB) [[attachment:gtk-simple-list-20sep2008.diff]]
  • [get | view] (2021-02-25 09:59:00, 50.1 KB) [[attachment:gtk-tree-extra-space-API-jul2008.tar.gz]]
  • [get | view] (2021-02-25 09:59:00, 111.2 KB) [[attachment:gtk-tree-new-dnd-28oct2008.diff]]
  • [get | view] (2021-02-25 09:59:00, 26.2 KB) [[attachment:gtk-tree-no-validation-jul2008.diff]]
  • [get | view] (2021-02-25 09:59:00, 17.3 KB) [[attachment:gtk-tree-refactor-dec2009.tar.gz]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.