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.You are not allowed to attach a file to this page.