Bug Summary

File:libbaul-private/baul-icon-dnd.c
Warning:line 627, column 5
Value stored to 'result' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name baul-icon-dnd.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/libbaul-private -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I .. -I .. -I .. -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/cafe-desktop-2.0 -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/startup-notification-1.0 -I /usr/include/dconf -I /usr/include/cail-3.0 -I /usr/include/libxml2 -D G_DISABLE_DEPRECATED -D GDK_PIXBUF_DISABLE_DEPRECATED -D DATADIR="/usr/share" -D SYSCONFDIR="/usr/etc" -D BAUL_DATADIR="/usr/share/baul" -D BAUL_EXTENSIONDIR="/usr/lib/baul/extensions-2.0" -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/libbaul-private -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-07-10-202347-28295-1 -x c baul-icon-dnd.c
1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3/* baul-icon-dnd.c - Drag & drop handling for the icon container widget.
4
5 Copyright (C) 1999, 2000 Free Software Foundation
6 Copyright (C) 2000 Eazel, Inc.
7
8 The Cafe Library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
12
13 The Cafe Library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public
19 License along with the Cafe Library; see the file COPYING.LIB. If not,
20 write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21 Boston, MA 02110-1301, USA.
22
23 Authors: Ettore Perazzoli <ettore@gnu.org>,
24 Darin Adler <darin@bentspoon.com>,
25 Andy Hertzfeld <andy@eazel.com>
26 Pavel Cisler <pavel@eazel.com>
27
28
29 XDS support: Benedikt Meurer <benny@xfce.org> (adapted by Amos Brocco <amos.brocco@unifr.ch>)
30
31*/
32
33
34#include <config.h>
35#include <math.h>
36#include <stdio.h>
37#include <string.h>
38
39#include <cdk/cdkkeysyms.h>
40#include <cdk/cdkx.h>
41#include <ctk/ctk.h>
42#include <glib/gi18n.h>
43
44#include <eel/eel-background.h>
45#include <eel/eel-gdk-pixbuf-extensions.h>
46#include <eel/eel-glib-extensions.h>
47#include <eel/eel-cafe-extensions.h>
48#include <eel/eel-graphic-effects.h>
49#include <eel/eel-ctk-extensions.h>
50#include <eel/eel-ctk-macros.h>
51#include <eel/eel-stock-dialogs.h>
52#include <eel/eel-string.h>
53#include <eel/eel-vfs-extensions.h>
54#include <eel/eel-canvas-rect-ellipse.h>
55
56#include "baul-icon-dnd.h"
57#include "baul-debug-log.h"
58#include "baul-file-dnd.h"
59#include "baul-icon-private.h"
60#include "baul-link.h"
61#include "baul-metadata.h"
62#include "baul-file-utilities.h"
63#include "baul-file-changes-queue.h"
64
65static const CtkTargetEntry drag_types [] =
66{
67 { BAUL_ICON_DND_CAFE_ICON_LIST_TYPE"x-special/cafe-icon-list", 0, BAUL_ICON_DND_CAFE_ICON_LIST },
68 { BAUL_ICON_DND_URI_LIST_TYPE"text/uri-list", 0, BAUL_ICON_DND_URI_LIST },
69};
70
71static const CtkTargetEntry drop_types [] =
72{
73 { BAUL_ICON_DND_CAFE_ICON_LIST_TYPE"x-special/cafe-icon-list", 0, BAUL_ICON_DND_CAFE_ICON_LIST },
74 /* prefer "_NETSCAPE_URL" over "text/uri-list" to satisfy web browsers. */
75 { BAUL_ICON_DND_NETSCAPE_URL_TYPE"_NETSCAPE_URL", 0, BAUL_ICON_DND_NETSCAPE_URL },
76 { BAUL_ICON_DND_URI_LIST_TYPE"text/uri-list", 0, BAUL_ICON_DND_URI_LIST },
77 { BAUL_ICON_DND_COLOR_TYPE"application/x-color", 0, BAUL_ICON_DND_COLOR },
78 { BAUL_ICON_DND_BGIMAGE_TYPE"property/bgimage", 0, BAUL_ICON_DND_BGIMAGE },
79 { BAUL_ICON_DND_KEYWORD_TYPE"property/keyword", 0, BAUL_ICON_DND_KEYWORD },
80 { BAUL_ICON_DND_RESET_BACKGROUND_TYPE"x-special/cafe-reset-background", 0, BAUL_ICON_DND_RESET_BACKGROUND },
81 { BAUL_ICON_DND_XDNDDIRECTSAVE_TYPE"XdndDirectSave0", 0, BAUL_ICON_DND_XDNDDIRECTSAVE }, /* XDS Protocol Type */
82 { BAUL_ICON_DND_RAW_TYPE"application/octet-stream", 0, BAUL_ICON_DND_RAW },
83 /* Must be last: */
84 { BAUL_ICON_DND_ROOTWINDOW_DROP_TYPE"application/x-rootwindow-drop", 0, BAUL_ICON_DND_ROOTWINDOW_DROP }
85};
86static void stop_dnd_highlight (CtkWidget *widget);
87static void dnd_highlight_queue_redraw (CtkWidget *widget);
88
89static CtkTargetList *drop_types_list = NULL((void*)0);
90static CtkTargetList *drop_types_list_root = NULL((void*)0);
91
92static char * baul_icon_container_find_drop_target (BaulIconContainer *container,
93 CdkDragContext *context,
94 int x, int y, gboolean *icon_hit,
95 gboolean rewrite_desktop);
96
97static EelCanvasItem *
98create_selection_shadow (BaulIconContainer *container,
99 GList *list)
100{
101 EelCanvasGroup *group;
102 EelCanvas *canvas;
103 int max_x, max_y;
104 int min_x, min_y;
105 GList *p;
106 CtkAllocation allocation;
107
108 if (list == NULL((void*)0))
109 {
110 return NULL((void*)0);
111 }
112
113 /* if we're only dragging a single item, don't worry about the shadow */
114 if (list->next == NULL((void*)0))
115 {
116 return NULL((void*)0);
117 }
118
119 canvas = EEL_CANVAS (container)((((EelCanvas*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((eel_canvas_get_type ()))))))
;
120 ctk_widget_get_allocation (CTK_WIDGET (container)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_widget_get_type ()))))))
, &allocation);
121
122 /* Creating a big set of rectangles in the canvas can be expensive, so
123 we try to be smart and only create the maximum number of rectangles
124 that we will need, in the vertical/horizontal directions. */
125
126 max_x = allocation.width;
127 min_x = -max_x;
128
129 max_y = allocation.height;
130 min_y = -max_y;
131
132 /* Create a group, so that it's easier to move all the items around at
133 once. */
134 group = EEL_CANVAS_GROUP((((EelCanvasGroup*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((eel_canvas_item_new (((((EelCanvasGroup*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((canvas->root)), ((eel_canvas_group_get_type
())))))), eel_canvas_group_get_type (), ((void*)0)))), ((eel_canvas_group_get_type
()))))))
135 (eel_canvas_item_new (EEL_CANVAS_GROUP (canvas->root),((((EelCanvasGroup*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((eel_canvas_item_new (((((EelCanvasGroup*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((canvas->root)), ((eel_canvas_group_get_type
())))))), eel_canvas_group_get_type (), ((void*)0)))), ((eel_canvas_group_get_type
()))))))
136 eel_canvas_group_get_type (),((((EelCanvasGroup*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((eel_canvas_item_new (((((EelCanvasGroup*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((canvas->root)), ((eel_canvas_group_get_type
())))))), eel_canvas_group_get_type (), ((void*)0)))), ((eel_canvas_group_get_type
()))))))
137 NULL))((((EelCanvasGroup*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((eel_canvas_item_new (((((EelCanvasGroup*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((canvas->root)), ((eel_canvas_group_get_type
())))))), eel_canvas_group_get_type (), ((void*)0)))), ((eel_canvas_group_get_type
()))))))
;
138
139 for (p = list; p != NULL((void*)0); p = p->next)
140 {
141 BaulDragSelectionItem *item;
142 int x1, y1, x2, y2;
143 CdkRGBA black = { 0, 0, 0, 1 };
144
145 item = p->data;
146
147 if (!item->got_icon_position)
148 {
149 continue;
150 }
151
152 x1 = item->icon_x;
153 y1 = item->icon_y;
154 x2 = x1 + item->icon_width;
155 y2 = y1 + item->icon_height;
156
157 if (x2 >= min_x && x1 <= max_x && y2 >= min_y && y1 <= max_y)
158 eel_canvas_item_new
159 (group,
160 eel_canvas_rect_get_type (),
161 "x1", (double) x1,
162 "y1", (double) y1,
163 "x2", (double) x2,
164 "y2", (double) y2,
165 "outline-color-rgba", &black,
166 "outline-stippling", TRUE(!(0)),
167 "width_pixels", 1,
168 NULL((void*)0));
169 }
170
171 return EEL_CANVAS_ITEM (group)((((EelCanvasItem*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((group)), ((eel_canvas_item_get_type ()))))))
;
172}
173
174/* Set the affine instead of the x and y position.
175 * Simple, and setting x and y was broken at one point.
176 */
177static void
178set_shadow_position (EelCanvasItem *shadow,
179 double x, double y)
180{
181 eel_canvas_item_set (shadow,
182 "x", x, "y", y,
183 NULL((void*)0));
184}
185
186
187/* Source-side handling of the drag. */
188
189/* iteration glue struct */
190typedef struct
191{
192 gpointer iterator_context;
193 BaulDragEachSelectedItemDataGet iteratee;
194 gpointer iteratee_data;
195} IconGetDataBinderContext;
196
197static void
198canvas_rect_world_to_widget (EelCanvas *canvas,
199 EelDRect *world_rect,
200 EelIRect *widget_rect)
201{
202 EelDRect window_rect;
203 CtkAdjustment *hadj, *vadj;
204
205 hadj = ctk_scrollable_get_hadjustment (CTK_SCROLLABLE (canvas)((((CtkScrollable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((canvas)), ((ctk_scrollable_get_type ()))))))
);
206 vadj = ctk_scrollable_get_vadjustment (CTK_SCROLLABLE (canvas)((((CtkScrollable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((canvas)), ((ctk_scrollable_get_type ()))))))
);
207
208 eel_canvas_world_to_window (canvas,
209 world_rect->x0, world_rect->y0,
210 &window_rect.x0, &window_rect.y0);
211 eel_canvas_world_to_window (canvas,
212 world_rect->x1, world_rect->y1,
213 &window_rect.x1, &window_rect.y1);
214 widget_rect->x0 = (int) window_rect.x0 - ctk_adjustment_get_value (hadj);
215 widget_rect->y0 = (int) window_rect.y0 - ctk_adjustment_get_value (vadj);
216 widget_rect->x1 = (int) window_rect.x1 - ctk_adjustment_get_value (hadj);
217 widget_rect->y1 = (int) window_rect.y1 - ctk_adjustment_get_value (vadj);
218}
219
220static void
221canvas_widget_to_world (EelCanvas *canvas,
222 double widget_x, double widget_y,
223 double *world_x, double *world_y)
224{
225 eel_canvas_window_to_world (canvas,
226 widget_x + ctk_adjustment_get_value (ctk_scrollable_get_hadjustment (CTK_SCROLLABLE (canvas)((((CtkScrollable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((canvas)), ((ctk_scrollable_get_type ()))))))
)),
227 widget_y + ctk_adjustment_get_value (ctk_scrollable_get_vadjustment (CTK_SCROLLABLE (canvas)((((CtkScrollable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((canvas)), ((ctk_scrollable_get_type ()))))))
)),
228 world_x, world_y);
229}
230
231static gboolean
232icon_get_data_binder (BaulIcon *icon, gpointer data)
233{
234 IconGetDataBinderContext *context;
235 EelDRect world_rect;
236 EelIRect widget_rect;
237 char *uri;
238 BaulIconContainer *container;
239
240 context = (IconGetDataBinderContext *)data;
241
242 g_assert (BAUL_IS_ICON_CONTAINER (context->iterator_context))do { if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((context->iterator_context)); GType __t = (baul_icon_container_get_type
()); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))) ; else g_assertion_message_expr (((gchar*) 0), "baul-icon-dnd.c"
, 242, ((const char*) (__func__)), "BAUL_IS_ICON_CONTAINER (context->iterator_context)"
); } while (0)
;
243
244 container = BAUL_ICON_CONTAINER (context->iterator_context)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((context->iterator_context)), (baul_icon_container_get_type
())))))
;
245
246 world_rect = baul_icon_canvas_item_get_icon_rectangle (icon->item);
247
248 canvas_rect_world_to_widget (EEL_CANVAS (container)((((EelCanvas*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((eel_canvas_get_type ()))))))
, &world_rect, &widget_rect);
249
250 uri = baul_icon_container_get_icon_uri (container, icon);
251 if (uri == NULL((void*)0))
252 {
253 g_warning ("no URI for one of the iterated icons");
254 return TRUE(!(0));
255 }
256
257 widget_rect = eel_irect_offset_by (widget_rect,
258 - container->details->dnd_info->drag_info.start_x,
259 - container->details->dnd_info->drag_info.start_y);
260
261 widget_rect = eel_irect_scale_by (widget_rect,
262 1 / EEL_CANVAS (container)((((EelCanvas*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((eel_canvas_get_type ()))))))
->pixels_per_unit);
263
264 /* pass the uri, mouse-relative x/y and icon width/height */
265 context->iteratee (uri,
266 (int) widget_rect.x0,
267 (int) widget_rect.y0,
268 widget_rect.x1 - widget_rect.x0,
269 widget_rect.y1 - widget_rect.y0,
270 context->iteratee_data);
271
272 g_free (uri);
273
274 return TRUE(!(0));
275}
276
277/* Iterate over each selected icon in a BaulIconContainer,
278 * calling each_function on each.
279 */
280static void
281baul_icon_container_each_selected_icon (BaulIconContainer *container,
282 gboolean (*each_function) (BaulIcon *, gpointer), gpointer data)
283{
284 GList *p;
285 BaulIcon *icon = NULL((void*)0);
286
287 for (p = container->details->icons; p != NULL((void*)0); p = p->next)
288 {
289 icon = p->data;
290 if (!icon->is_selected)
291 {
292 continue;
293 }
294 if (!each_function (icon, data))
295 {
296 return;
297 }
298 }
299}
300
301/* Adaptor function used with baul_icon_container_each_selected_icon
302 * to help iterate over all selected items, passing uris, x, y, w and h
303 * values to the iteratee
304 */
305static void
306each_icon_get_data_binder (BaulDragEachSelectedItemDataGet iteratee,
307 gpointer iterator_context, gpointer data)
308{
309 IconGetDataBinderContext context;
310 BaulIconContainer *container;
311
312 g_assert (BAUL_IS_ICON_CONTAINER (iterator_context))do { if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((iterator_context)); GType __t = (baul_icon_container_get_type
()); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))) ; else g_assertion_message_expr (((gchar*) 0), "baul-icon-dnd.c"
, 312, ((const char*) (__func__)), "BAUL_IS_ICON_CONTAINER (iterator_context)"
); } while (0)
;
313 container = BAUL_ICON_CONTAINER (iterator_context)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((iterator_context)), (baul_icon_container_get_type
())))))
;
314
315 context.iterator_context = iterator_context;
316 context.iteratee = iteratee;
317 context.iteratee_data = data;
318 baul_icon_container_each_selected_icon (container, icon_get_data_binder, &context);
319}
320
321/* Called when the data for drag&drop is needed */
322static void
323drag_data_get_callback (CtkWidget *widget,
324 CdkDragContext *context,
325 CtkSelectionData *selection_data,
326 guint info,
327 guint32 time,
328 gpointer data)
329{
330 g_assert (widget != NULL)do { if (widget != ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "baul-icon-dnd.c", 330, ((const char*) (__func__
)), "widget != NULL"); } while (0)
;
331 g_assert (BAUL_IS_ICON_CONTAINER (widget))do { if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((widget)); GType __t = (baul_icon_container_get_type()); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))) ; else
g_assertion_message_expr (((gchar*) 0), "baul-icon-dnd.c", 331
, ((const char*) (__func__)), "BAUL_IS_ICON_CONTAINER (widget)"
); } while (0)
;
332 g_return_if_fail (context != NULL)do { if ((context != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "context != NULL"
); return; } } while (0)
;
333
334 /* Call common function from baul-drag that set's up
335 * the selection data in the right format. Pass it means to
336 * iterate all the selected icons.
337 */
338 baul_drag_drag_data_get (widget, context, selection_data,
339 info, time, widget, each_icon_get_data_binder);
340}
341
342
343/* Target-side handling of the drag. */
344
345static void
346baul_icon_container_position_shadow (BaulIconContainer *container,
347 int x, int y)
348{
349 EelCanvasItem *shadow;
350 double world_x, world_y;
351
352 shadow = container->details->dnd_info->shadow;
353 if (shadow == NULL((void*)0))
354 {
355 return;
356 }
357
358 canvas_widget_to_world (EEL_CANVAS (container)((((EelCanvas*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((eel_canvas_get_type ()))))))
, x, y,
359 &world_x, &world_y);
360
361 set_shadow_position (shadow, world_x, world_y);
362 eel_canvas_item_show (shadow);
363}
364
365static void
366baul_icon_container_dropped_icon_feedback (CtkWidget *widget,
367 CtkSelectionData *data,
368 int x, int y)
369{
370 BaulIconContainer *container;
371 BaulIconDndInfo *dnd_info;
372
373 container = BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
;
374 dnd_info = container->details->dnd_info;
375
376 /* Delete old selection list. */
377 baul_drag_destroy_selection_list (dnd_info->drag_info.selection_list);
378 dnd_info->drag_info.selection_list = NULL((void*)0);
379
380 /* Delete old shadow if any. */
381 if (dnd_info->shadow != NULL((void*)0))
382 {
383 /* FIXME bugzilla.gnome.org 42484:
384 * Is a destroy really sufficient here? Who does the unref? */
385 eel_canvas_item_destroy (dnd_info->shadow);
386 }
387
388 /* Build the selection list and the shadow. */
389 dnd_info->drag_info.selection_list = baul_drag_build_selection_list (data);
390 dnd_info->shadow = create_selection_shadow (container, dnd_info->drag_info.selection_list);
391 baul_icon_container_position_shadow (container, x, y);
392}
393
394static char *
395get_direct_save_filename (CdkDragContext *context)
396{
397 guchar *prop_text;
398 gint prop_len;
399
400 if (!cdk_property_get (cdk_drag_context_get_source_window (context), cdk_atom_intern (BAUL_ICON_DND_XDNDDIRECTSAVE_TYPE"XdndDirectSave0", FALSE(0)),
401 cdk_atom_intern ("text/plain", FALSE(0)), 0, 1024, FALSE(0), NULL((void*)0), NULL((void*)0),
402 &prop_len, &prop_text))
403 {
404 return NULL((void*)0);
405 }
406
407 /* Zero-terminate the string */
408 prop_text = g_realloc (prop_text, prop_len + 1);
409 prop_text[prop_len] = '\0';
410
411 /* Verify that the file name provided by the source is valid */
412 if (*prop_text == '\0' ||
413 strchr ((const gchar *) prop_text, G_DIR_SEPARATOR'/') != NULL((void*)0))
414 {
415 baul_debug_log (FALSE(0), BAUL_DEBUG_LOG_DOMAIN_USER"USER",
416 "Invalid filename provided by XDS drag site");
417 g_free (prop_text);
418 return NULL((void*)0);
419 }
420
421 return prop_text;
422}
423
424static void
425set_direct_save_uri (CtkWidget *widget, CdkDragContext *context, BaulDragInfo *drag_info, int x, int y)
426{
427 char *filename, *drop_target;
428 gchar *uri;
429
430 drag_info->got_drop_data_type = TRUE(!(0));
431 drag_info->data_type = BAUL_ICON_DND_XDNDDIRECTSAVE;
432
433 uri = NULL((void*)0);
434
435 filename = get_direct_save_filename (context);
436 drop_target = baul_icon_container_find_drop_target (BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
,
437 context, x, y, NULL((void*)0), TRUE(!(0)));
438
439 if (drop_target && eel_uri_is_trash (drop_target))
440 {
441 g_free (drop_target);
442 drop_target = NULL((void*)0); /* Cannot save to trash ...*/
443 }
444
445 if (filename != NULL((void*)0) && drop_target != NULL((void*)0))
446 {
447 GFile *base, *child;
448
449 /* Resolve relative path */
450 base = g_file_new_for_uri (drop_target);
451 child = g_file_get_child (base, filename);
452 uri = g_file_get_uri (child);
453 g_object_unref (base);
454 g_object_unref (child);
455
456 /* Change the uri property */
457 cdk_property_change (cdk_drag_context_get_source_window (context),
458 cdk_atom_intern (BAUL_ICON_DND_XDNDDIRECTSAVE_TYPE"XdndDirectSave0", FALSE(0)),
459 cdk_atom_intern ("text/plain", FALSE(0)), 8,
460 CDK_PROP_MODE_REPLACE, (const guchar *) uri,
461 strlen (uri));
462
463 drag_info->direct_save_uri = uri;
464 }
465
466 g_free (filename);
467 g_free (drop_target);
468}
469
470/* FIXME bugzilla.gnome.org 47445: Needs to become a shared function */
471static void
472get_data_on_first_target_we_support (CtkWidget *widget, CdkDragContext *context, guint32 time, int x, int y)
473{
474 CtkTargetList *list;
475 CdkAtom target;
476
477 if (drop_types_list == NULL((void*)0))
478 {
479 drop_types_list = ctk_target_list_new (drop_types,
480 G_N_ELEMENTS (drop_types)(sizeof (drop_types) / sizeof ((drop_types)[0])) - 1);
481 ctk_target_list_add_text_targets (drop_types_list, BAUL_ICON_DND_TEXT);
482 }
483 if (drop_types_list_root == NULL((void*)0))
484 {
485 drop_types_list_root = ctk_target_list_new (drop_types,
486 G_N_ELEMENTS (drop_types)(sizeof (drop_types) / sizeof ((drop_types)[0])));
487 ctk_target_list_add_text_targets (drop_types_list_root, BAUL_ICON_DND_TEXT);
488 }
489
490 if (baul_icon_container_get_is_desktop (BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
))
491 {
492 list = drop_types_list_root;
493 }
494 else
495 {
496 list = drop_types_list;
497 }
498
499 target = ctk_drag_dest_find_target (widget, context, list);
500 if (target != CDK_NONE((CdkAtom)((gpointer) (gulong) (0))))
501 {
502 guint info;
503 BaulDragInfo *drag_info;
504 gboolean found;
505
506 drag_info = &(BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
->details->dnd_info->drag_info);
507
508 found = ctk_target_list_find (list, target, &info);
509 g_assert (found)do { if (found) ; else g_assertion_message_expr (((gchar*) 0)
, "baul-icon-dnd.c", 509, ((const char*) (__func__)), "found"
); } while (0)
;
510
511 /* Don't get_data for destructive ops */
512 if ((info == BAUL_ICON_DND_ROOTWINDOW_DROP ||
513 info == BAUL_ICON_DND_XDNDDIRECTSAVE) &&
514 !drag_info->drop_occured)
515 {
516 /* We can't call get_data here, because that would
517 make the source execute the rootwin action or the direct save */
518 drag_info->got_drop_data_type = TRUE(!(0));
519 drag_info->data_type = info;
520 }
521 else
522 {
523 if (info == BAUL_ICON_DND_XDNDDIRECTSAVE)
524 {
525 set_direct_save_uri (widget, context, drag_info, x, y);
526 }
527 ctk_drag_get_data (CTK_WIDGET (widget)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_widget_get_type ()))))))
, context,
528 target, time);
529 }
530 }
531}
532
533static void
534baul_icon_container_ensure_drag_data (BaulIconContainer *container,
535 CdkDragContext *context,
536 guint32 time)
537{
538 BaulIconDndInfo *dnd_info;
539
540 dnd_info = container->details->dnd_info;
541
542 if (!dnd_info->drag_info.got_drop_data_type)
543 {
544 get_data_on_first_target_we_support (CTK_WIDGET (container)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_widget_get_type ()))))))
, context, time, 0, 0);
545 }
546}
547
548static void
549drag_end_callback (CtkWidget *widget,
550 CdkDragContext *context,
551 gpointer data)
552{
553 BaulIconContainer *container;
554 BaulIconDndInfo *dnd_info;
555
556 container = BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
;
557 dnd_info = container->details->dnd_info;
558
559 baul_drag_destroy_selection_list (dnd_info->drag_info.selection_list);
560 dnd_info->drag_info.selection_list = NULL((void*)0);
561}
562
563static BaulIcon *
564baul_icon_container_item_at (BaulIconContainer *container,
565 int x, int y)
566{
567 GList *p;
568 int size;
569 EelDRect point;
570 EelIRect canvas_point;
571
572 /* build the hit-test rectangle. Base the size on the scale factor to ensure that it is
573 * non-empty even at the smallest scale factor
574 */
575
576 size = MAX (1, 1 + (1 / EEL_CANVAS (container)->pixels_per_unit))(((1) > (1 + (1 / ((((EelCanvas*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((container)), ((eel_canvas_get_type ())))
)))->pixels_per_unit))) ? (1) : (1 + (1 / ((((EelCanvas*) (
void *) g_type_check_instance_cast ((GTypeInstance*) ((container
)), ((eel_canvas_get_type ()))))))->pixels_per_unit)))
;
577 point.x0 = x;
578 point.y0 = y;
579 point.x1 = x + size;
580 point.y1 = y + size;
581
582 for (p = container->details->icons; p != NULL((void*)0); p = p->next)
583 {
584 BaulIcon *icon;
585 icon = p->data;
586
587 eel_canvas_w2c (EEL_CANVAS (container)((((EelCanvas*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((eel_canvas_get_type ()))))))
,
588 point.x0,
589 point.y0,
590 &canvas_point.x0,
591 &canvas_point.y0);
592 eel_canvas_w2c (EEL_CANVAS (container)((((EelCanvas*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((eel_canvas_get_type ()))))))
,
593 point.x1,
594 point.y1,
595 &canvas_point.x1,
596 &canvas_point.y1);
597 if (baul_icon_canvas_item_hit_test_rectangle (icon->item, canvas_point))
598 {
599 return icon;
600 }
601 }
602
603 return NULL((void*)0);
604}
605
606static char *
607get_container_uri (BaulIconContainer *container)
608{
609 char *uri;
610
611 /* get the URI associated with the container */
612 uri = NULL((void*)0);
613 g_signal_emit_by_name (container, "get_container_uri", &uri);
614 return uri;
615}
616
617static gboolean
618baul_icon_container_selection_items_local (BaulIconContainer *container,
619 GList *items)
620{
621 char *container_uri_string;
622 gboolean result;
623
624 /* must have at least one item */
625 g_assert (items)do { if (items) ; else g_assertion_message_expr (((gchar*) 0)
, "baul-icon-dnd.c", 625, ((const char*) (__func__)), "items"
); } while (0)
;
626
627 result = FALSE(0);
Value stored to 'result' is never read
628
629 /* get the URI associated with the container */
630 container_uri_string = get_container_uri (container);
631
632 if (eel_uri_is_desktop (container_uri_string))
633 {
634 result = baul_drag_items_on_desktop (items);
635 }
636 else
637 {
638 result = baul_drag_items_local (container_uri_string, items);
639 }
640 g_free (container_uri_string);
641
642 return result;
643}
644
645static CdkDragAction
646get_background_drag_action (BaulIconContainer *container,
647 CdkDragAction action)
648{
649 /* FIXME: This function is very FMDirectoryView specific, and
650 * should be moved out of baul-icon-dnd.c */
651 CdkDragAction valid_actions;
652
653 if (action == CDK_ACTION_ASK)
654 {
655 valid_actions = BAUL_DND_ACTION_SET_AS_FOLDER_BACKGROUND;
656 if (!eel_background_is_desktop (eel_get_widget_background (CTK_WIDGET (container)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_widget_get_type ()))))))
)))
657 {
658 valid_actions |= BAUL_DND_ACTION_SET_AS_GLOBAL_BACKGROUND;
659 }
660
661 action = baul_drag_drop_background_ask
662 (CTK_WIDGET (container)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_widget_get_type ()))))))
, valid_actions);
663 }
664
665 return action;
666}
667
668static void
669receive_dropped_color (BaulIconContainer *container,
670 int x, int y,
671 CdkDragAction action,
672 CtkSelectionData *data)
673{
674 action = get_background_drag_action (container, action);
675
676 if (action > 0)
677 {
678 char *uri;
679
680 uri = get_container_uri (container);
681 baul_debug_log (FALSE(0), BAUL_DEBUG_LOG_DOMAIN_USER"USER",
682 "dropped color on icon container displaying %s", uri);
683 g_free (uri);
684
685 eel_background_set_dropped_color (eel_get_widget_background (CTK_WIDGET (container)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_widget_get_type ()))))))
),
686 CTK_WIDGET (container)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_widget_get_type ()))))))
,
687 action, x, y, data);
688 }
689}
690
691/* handle dropped tile images */
692static void
693receive_dropped_tile_image (BaulIconContainer *container, CdkDragAction action, CtkSelectionData *data)
694{
695 g_assert (data != NULL)do { if (data != ((void*)0)) ; else g_assertion_message_expr (
((gchar*) 0), "baul-icon-dnd.c", 695, ((const char*) (__func__
)), "data != NULL"); } while (0)
;
696
697 action = get_background_drag_action (container, action);
698
699 if (action > 0)
700 {
701 char *uri;
702
703 uri = get_container_uri (container);
704 baul_debug_log (FALSE(0), BAUL_DEBUG_LOG_DOMAIN_USER"USER",
705 "dropped tile image on icon container displaying %s", uri);
706 g_free (uri);
707
708 eel_background_set_dropped_image (eel_get_widget_background (CTK_WIDGET (container)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_widget_get_type ()))))))
),
709 action, ctk_selection_data_get_data (data));
710 }
711}
712
713/* handle dropped keywords */
714static void
715receive_dropped_keyword (BaulIconContainer *container, const char *keyword, int x, int y)
716{
717 char *uri;
718 double world_x, world_y;
719
720 BaulIcon *drop_target_icon;
721 BaulFile *file;
722
723 g_assert (keyword != NULL)do { if (keyword != ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "baul-icon-dnd.c", 723, ((const char*) (__func__
)), "keyword != NULL"); } while (0)
;
724
725 /* find the item we hit with our drop, if any */
726 canvas_widget_to_world (EEL_CANVAS (container)((((EelCanvas*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((eel_canvas_get_type ()))))))
, x, y, &world_x, &world_y);
727 drop_target_icon = baul_icon_container_item_at (container, world_x, world_y);
728 if (drop_target_icon == NULL((void*)0))
729 {
730 return;
731 }
732
733 /* FIXME bugzilla.gnome.org 42485:
734 * This does not belong in the icon code.
735 * It has to be in the file manager.
736 * The icon code has no right to deal with the file directly.
737 * But luckily there's no issue of not getting a file object,
738 * so we don't have to worry about async. issues here.
739 */
740 uri = baul_icon_container_get_icon_uri (container, drop_target_icon);
741
742 baul_debug_log (FALSE(0), BAUL_DEBUG_LOG_DOMAIN_USER"USER",
743 "dropped emblem '%s' on icon container URI: %s",
744 keyword, uri);
745
746 file = baul_file_get_by_uri (uri);
747 g_free (uri);
748
749 baul_drag_file_receive_dropped_keyword (file, keyword);
750
751 baul_file_unref (file);
752 baul_icon_container_update_icon (container, drop_target_icon);
753}
754
755/* handle dropped url */
756static void
757receive_dropped_netscape_url (BaulIconContainer *container, const char *encoded_url, CdkDragContext *context, int x, int y)
758{
759 char *drop_target;
760
761 if (encoded_url == NULL((void*)0))
762 {
763 return;
764 }
765
766 drop_target = baul_icon_container_find_drop_target (container, context, x, y, NULL((void*)0), TRUE(!(0)));
767
768 g_signal_emit_by_name (container, "handle_netscape_url",
769 encoded_url,
770 drop_target,
771 cdk_drag_context_get_selected_action (context),
772 x, y);
773
774 g_free (drop_target);
775}
776
777/* handle dropped uri list */
778static void
779receive_dropped_uri_list (BaulIconContainer *container, const char *uri_list, CdkDragContext *context, int x, int y)
780{
781 char *drop_target;
782
783 if (uri_list == NULL((void*)0))
784 {
785 return;
786 }
787
788 drop_target = baul_icon_container_find_drop_target (container, context, x, y, NULL((void*)0), TRUE(!(0)));
789
790 g_signal_emit_by_name (container, "handle_uri_list",
791 uri_list,
792 drop_target,
793 cdk_drag_context_get_selected_action (context),
794 x, y);
795
796 g_free (drop_target);
797}
798
799/* handle dropped text */
800static void
801receive_dropped_text (BaulIconContainer *container, const char *text, CdkDragContext *context, int x, int y)
802{
803 char *drop_target;
804
805 if (text == NULL((void*)0))
806 {
807 return;
808 }
809
810 drop_target = baul_icon_container_find_drop_target (container, context, x, y, NULL((void*)0), TRUE(!(0)));
811
812 g_signal_emit_by_name (container, "handle_text",
813 text,
814 drop_target,
815 cdk_drag_context_get_selected_action (context),
816 x, y);
817
818 g_free (drop_target);
819}
820
821/* handle dropped raw data */
822static void
823receive_dropped_raw (BaulIconContainer *container, const char *raw_data, int length, const char *direct_save_uri, CdkDragContext *context, int x, int y)
824{
825 char *drop_target;
826
827 if (raw_data == NULL((void*)0))
828 {
829 return;
830 }
831
832 drop_target = baul_icon_container_find_drop_target (container, context, x, y, NULL((void*)0), TRUE(!(0)));
833
834 g_signal_emit_by_name (container, "handle_raw",
835 raw_data,
836 length,
837 drop_target,
838 direct_save_uri,
839 cdk_drag_context_get_selected_action (context),
840 x, y);
841
842 g_free (drop_target);
843}
844
845static int
846auto_scroll_timeout_callback (gpointer data)
847{
848 BaulIconContainer *container;
849 CtkWidget *widget;
850 float x_scroll_delta, y_scroll_delta;
851 CdkRectangle exposed_area;
852 CtkAllocation allocation;
853
854 g_assert (BAUL_IS_ICON_CONTAINER (data))do { if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((data)); GType __t = (baul_icon_container_get_type()); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))) ; else
g_assertion_message_expr (((gchar*) 0), "baul-icon-dnd.c", 854
, ((const char*) (__func__)), "BAUL_IS_ICON_CONTAINER (data)"
); } while (0)
;
855 widget = CTK_WIDGET (data)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((ctk_widget_get_type ()))))))
;
856 container = BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
;
857
858 if (container->details->dnd_info->drag_info.waiting_to_autoscroll
859 && container->details->dnd_info->drag_info.start_auto_scroll_in > g_get_monotonic_time())
860 {
861 /* not yet */
862 return TRUE(!(0));
863 }
864
865 container->details->dnd_info->drag_info.waiting_to_autoscroll = FALSE(0);
866
867 baul_drag_autoscroll_calculate_delta (widget, &x_scroll_delta, &y_scroll_delta);
868 if (x_scroll_delta == 0 && y_scroll_delta == 0)
869 {
870 /* no work */
871 return TRUE(!(0));
872 }
873
874 /* Clear the old dnd highlight frame */
875 dnd_highlight_queue_redraw (widget);
876
877 if (!baul_icon_container_scroll (container, (int)x_scroll_delta, (int)y_scroll_delta))
878 {
879 /* the scroll value got pinned to a min or max adjustment value,
880 * we ended up not scrolling
881 */
882 return TRUE(!(0));
883 }
884
885 /* Make sure the dnd highlight frame is redrawn */
886 dnd_highlight_queue_redraw (widget);
887
888 /* update cached drag start offsets */
889 container->details->dnd_info->drag_info.start_x -= x_scroll_delta;
890 container->details->dnd_info->drag_info.start_y -= y_scroll_delta;
891
892 /* Due to a glitch in CtkLayout, whe need to do an explicit draw of the exposed
893 * area.
894 * Calculate the size of the area we need to draw
895 */
896 ctk_widget_get_allocation (widget, &allocation);
897 exposed_area.x = allocation.x;
898 exposed_area.y = allocation.y;
899 exposed_area.width = allocation.width;
900 exposed_area.height = allocation.height;
901
902 if (x_scroll_delta > 0)
903 {
904 exposed_area.x = exposed_area.width - x_scroll_delta;
905 }
906 else if (x_scroll_delta < 0)
907 {
908 exposed_area.width = -x_scroll_delta;
909 }
910
911 if (y_scroll_delta > 0)
912 {
913 exposed_area.y = exposed_area.height - y_scroll_delta;
914 }
915 else if (y_scroll_delta < 0)
916 {
917 exposed_area.height = -y_scroll_delta;
918 }
919
920 /* offset it to 0, 0 */
921 exposed_area.x -= allocation.x;
922 exposed_area.y -= allocation.y;
923
924 ctk_widget_queue_draw_area (widget,
925 exposed_area.x,
926 exposed_area.y,
927 exposed_area.width,
928 exposed_area.height);
929
930 return TRUE(!(0));
931}
932
933static void
934set_up_auto_scroll_if_needed (BaulIconContainer *container)
935{
936 baul_drag_autoscroll_start (&container->details->dnd_info->drag_info,
937 CTK_WIDGET (container)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_widget_get_type ()))))))
,
938 auto_scroll_timeout_callback,
939 container);
940}
941
942static void
943stop_auto_scroll (BaulIconContainer *container)
944{
945 baul_drag_autoscroll_stop (&container->details->dnd_info->drag_info);
946}
947
948static void
949handle_local_move (BaulIconContainer *container,
950 double world_x, double world_y)
951{
952 GList *moved_icons, *p;
953 BaulFile *file;
954 char screen_string[32];
955 CdkScreen *screen;
956 time_t now;
957 BaulDragSelectionItem *item = NULL((void*)0);
958 BaulIcon *icon = NULL((void*)0);
959
960 if (container->details->auto_layout)
961 {
962 return;
963 }
964
965 time (&now);
966
967 /* Move and select the icons. */
968 moved_icons = NULL((void*)0);
969 for (p = container->details->dnd_info->drag_info.selection_list; p != NULL((void*)0); p = p->next)
970 {
971 item = p->data;
972
973 icon = baul_icon_container_get_icon_by_uri
974 (container, item->uri);
975
976 if (icon == NULL((void*)0))
977 {
978 /* probably dragged from another screen. Add it to
979 * this screen
980 */
981
982 file = baul_file_get_by_uri (item->uri);
983
984 screen = ctk_widget_get_screen (CTK_WIDGET (container)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_widget_get_type ()))))))
);
985 g_snprintf (screen_string, sizeof (screen_string), "%d",
986 cdk_x11_screen_get_screen_number (screen));
987 baul_file_set_metadata (file,
988 BAUL_METADATA_KEY_SCREEN"screen",
989 NULL((void*)0), screen_string);
990 baul_file_set_time_metadata (file,
991 BAUL_METADATA_KEY_ICON_POSITION_TIMESTAMP"baul-icon-position-timestamp", now);
992
993 baul_icon_container_add (container, BAUL_ICON_CONTAINER_ICON_DATA (file)((BaulIconData *) (file)));
994
995 icon = baul_icon_container_get_icon_by_uri
996 (container, item->uri);
997 }
998
999 if (item->got_icon_position)
1000 {
1001 baul_icon_container_move_icon
1002 (container, icon,
1003 world_x + item->icon_x, world_y + item->icon_y,
1004 icon->scale,
1005 TRUE(!(0)), TRUE(!(0)), TRUE(!(0)));
1006 }
1007 moved_icons = g_list_prepend (moved_icons, icon);
1008 }
1009 baul_icon_container_select_list_unselect_others
1010 (container, moved_icons);
1011 /* Might have been moved in a way that requires adjusting scroll region. */
1012 baul_icon_container_update_scroll_region (container);
1013 g_list_free (moved_icons);
1014}
1015
1016static void
1017handle_nonlocal_move (BaulIconContainer *container,
1018 CdkDragAction action,
1019 int x, int y,
1020 const char *target_uri,
1021 gboolean icon_hit)
1022{
1023 GList *source_uris, *p;
1024 GArray *source_item_locations;
1025 gboolean free_target_uri, is_rtl;
1026 CtkAllocation allocation;
1027
1028 if (container->details->dnd_info->drag_info.selection_list == NULL((void*)0))
1029 {
1030 return;
1031 }
1032
1033 source_uris = NULL((void*)0);
1034 for (p = container->details->dnd_info->drag_info.selection_list; p != NULL((void*)0); p = p->next)
1035 {
1036 /* do a shallow copy of all the uri strings of the copied files */
1037 source_uris = g_list_prepend (source_uris, ((BaulDragSelectionItem *)p->data)->uri);
1038 }
1039 source_uris = g_list_reverse (source_uris);
1040
1041 is_rtl = baul_icon_container_is_layout_rtl (container);
1042
1043 source_item_locations = g_array_new (FALSE(0), TRUE(!(0)), sizeof (CdkPoint));
1044 if (!icon_hit)
1045 {
1046 int index;
1047
1048 /* Drop onto a container. Pass along the item points to allow placing
1049 * the items in their same relative positions in the new container.
1050 */
1051 source_item_locations = g_array_set_size (source_item_locations,
1052 g_list_length (container->details->dnd_info->drag_info.selection_list));
1053
1054 for (index = 0, p = container->details->dnd_info->drag_info.selection_list;
1055 p != NULL((void*)0); index++, p = p->next)
1056 {
1057 int item_x;
1058
1059 item_x = ((BaulDragSelectionItem *)p->data)->icon_x;
1060 if (is_rtl)
1061 item_x = -item_x - ((BaulDragSelectionItem *)p->data)->icon_width;
1062 g_array_index (source_item_locations, CdkPoint, index)(((CdkPoint*) (void *) (source_item_locations)->data) [(index
)])
.x = item_x;
1063 g_array_index (source_item_locations, CdkPoint, index)(((CdkPoint*) (void *) (source_item_locations)->data) [(index
)])
.y =
1064 ((BaulDragSelectionItem *)p->data)->icon_y;
1065 }
1066 }
1067
1068 free_target_uri = FALSE(0);
1069 /* Rewrite internal desktop URIs to the normal target uri */
1070 if (eel_uri_is_desktop (target_uri))
1071 {
1072 target_uri = baul_get_desktop_directory_uri ();
1073 free_target_uri = TRUE(!(0));
1074 }
1075
1076 if (is_rtl)
1077 {
1078 ctk_widget_get_allocation (CTK_WIDGET (container)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_widget_get_type ()))))))
, &allocation);
1079 x = CANVAS_WIDTH (container, allocation)((allocation.width - container->details->left_margin - container
->details->right_margin) / ((((EelCanvas*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((container)), ((eel_canvas_get_type ())))
)))->pixels_per_unit)
- x;
1080 }
1081
1082 /* start the copy */
1083 g_signal_emit_by_name (container, "move_copy_items",
1084 source_uris,
1085 source_item_locations,
1086 target_uri,
1087 action,
1088 x, y);
1089
1090 if (free_target_uri)
1091 {
1092 g_free ((char *)target_uri);
1093 }
1094
1095 g_list_free (source_uris);
1096 g_array_free (source_item_locations, TRUE(!(0)));
1097}
1098
1099static char *
1100baul_icon_container_find_drop_target (BaulIconContainer *container,
1101 CdkDragContext *context,
1102 int x, int y,
1103 gboolean *icon_hit,
1104 gboolean rewrite_desktop)
1105{
1106 BaulIcon *drop_target_icon;
1107 double world_x, world_y;
1108
1109 if (icon_hit)
1110 {
1111 *icon_hit = FALSE(0);
1112 }
1113
1114 if (!container->details->dnd_info->drag_info.got_drop_data_type)
1115 {
1116 return NULL((void*)0);
1117 }
1118
1119 canvas_widget_to_world (EEL_CANVAS (container)((((EelCanvas*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((eel_canvas_get_type ()))))))
, x, y, &world_x, &world_y);
1120
1121 /* FIXME bugzilla.gnome.org 42485:
1122 * These "can_accept_items" tests need to be done by
1123 * the icon view, not here. This file is not supposed to know
1124 * that the target is a file.
1125 */
1126
1127 /* Find the item we hit with our drop, if any */
1128 drop_target_icon = baul_icon_container_item_at (container, world_x, world_y);
1129 if (drop_target_icon != NULL((void*)0))
1130 {
1131 char *icon_uri;
1132
1133 icon_uri = baul_icon_container_get_icon_uri (container, drop_target_icon);
1134 if (icon_uri != NULL((void*)0))
1135 {
1136 BaulFile *file;
1137
1138 file = baul_file_get_by_uri (icon_uri);
1139
1140 if (!baul_drag_can_accept_info (file,
1141 container->details->dnd_info->drag_info.data_type,
1142 container->details->dnd_info->drag_info.selection_list))
1143 {
1144 /* the item we dropped our selection on cannot accept the items,
1145 * do the same thing as if we just dropped the items on the canvas
1146 */
1147 drop_target_icon = NULL((void*)0);
1148 }
1149
1150 g_free (icon_uri);
1151 baul_file_unref (file);
1152 }
1153 }
1154
1155 if (drop_target_icon == NULL((void*)0))
1156 {
1157 char *container_uri;
1158
1159 if (icon_hit)
1160 {
1161 *icon_hit = FALSE(0);
1162 }
1163
1164 container_uri = get_container_uri (container);
1165
1166 if (rewrite_desktop &&
1167 container_uri != NULL((void*)0) &&
1168 eel_uri_is_desktop (container_uri))
1169 {
1170 g_free (container_uri);
1171 container_uri = baul_get_desktop_directory_uri ();
1172 }
1173
1174 return container_uri;
1175 }
1176
1177 if (icon_hit)
1178 {
1179 *icon_hit = TRUE(!(0));
1180 }
1181 return baul_icon_container_get_icon_drop_target_uri (container, drop_target_icon);
1182}
1183
1184static gboolean
1185selection_is_image_file (GList *selection_list)
1186{
1187 const char *mime_type;
1188 BaulDragSelectionItem *selected_item;
1189 gboolean result;
1190 GFile *location;
1191 GFileInfo *info;
1192
1193 /* Make sure only one item is selected */
1194 if (selection_list == NULL((void*)0) ||
1195 selection_list->next != NULL((void*)0))
1196 {
1197 return FALSE(0);
1198 }
1199
1200 selected_item = selection_list->data;
1201
1202 mime_type = NULL((void*)0);
1203
1204 location = g_file_new_for_uri (selected_item->uri);
1205 info = g_file_query_info (location,
1206 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE"standard::content-type",
1207 0, NULL((void*)0), NULL((void*)0));
1208 if (info)
1209 {
1210 mime_type = g_file_info_get_content_type (info);
1211 }
1212
1213 result = eel_istr_has_prefix (mime_type, "image/");
1214
1215 if (info)
1216 {
1217 g_object_unref (info);
1218 }
1219 g_object_unref (location);
1220
1221 return result;
1222}
1223
1224
1225static void
1226baul_icon_container_receive_dropped_icons (BaulIconContainer *container,
1227 CdkDragContext *context,
1228 int x, int y)
1229{
1230 char *drop_target;
1231 gboolean local_move_only;
1232 double world_x, world_y;
1233 gboolean icon_hit;
1234 CdkDragAction action, real_action;
1235
1236 drop_target = NULL((void*)0);
1237
1238 if (container->details->dnd_info->drag_info.selection_list == NULL((void*)0))
1239 {
1240 return;
1241 }
1242
1243 real_action = cdk_drag_context_get_selected_action (context);
1244
1245 if (real_action == CDK_ACTION_ASK)
1246 {
1247 /* FIXME bugzilla.gnome.org 42485: This belongs in FMDirectoryView, not here. */
1248 /* Check for special case items in selection list */
1249 if (baul_drag_selection_includes_special_link (container->details->dnd_info->drag_info.selection_list))
1250 {
1251 /* We only want to move the trash */
1252 action = CDK_ACTION_MOVE;
1253 }
1254 else
1255 {
1256 action = CDK_ACTION_MOVE | CDK_ACTION_COPY | CDK_ACTION_LINK;
1257
1258 if (selection_is_image_file (container->details->dnd_info->drag_info.selection_list))
1259 {
1260 action |= BAUL_DND_ACTION_SET_AS_BACKGROUND;
1261 }
1262 }
1263 real_action = baul_drag_drop_action_ask (CTK_WIDGET (container)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_widget_get_type ()))))))
, action);
1264 }
1265
1266 if (real_action == (CdkDragAction) BAUL_DND_ACTION_SET_AS_BACKGROUND)
1267 {
1268 BaulDragSelectionItem *selected_item;
1269
1270 selected_item = container->details->dnd_info->drag_info.selection_list->data;
1271 eel_background_set_dropped_image (eel_get_widget_background (CTK_WIDGET (container)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_widget_get_type ()))))))
),
1272 real_action, selected_item->uri);
1273 return;
1274 }
1275
1276 if (real_action > 0)
1277 {
1278 eel_canvas_window_to_world (EEL_CANVAS (container)((((EelCanvas*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((eel_canvas_get_type ()))))))
,
1279 x + ctk_adjustment_get_value (ctk_scrollable_get_hadjustment (CTK_SCROLLABLE (container)((((CtkScrollable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_scrollable_get_type ()))))))
)),
1280 y + ctk_adjustment_get_value (ctk_scrollable_get_vadjustment (CTK_SCROLLABLE (container)((((CtkScrollable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_scrollable_get_type ()))))))
)),
1281 &world_x, &world_y);
1282
1283 drop_target = baul_icon_container_find_drop_target (container,
1284 context, x, y, &icon_hit, FALSE(0));
1285
1286 local_move_only = FALSE(0);
1287 if (!icon_hit && real_action == CDK_ACTION_MOVE)
1288 {
1289 /* we can just move the icon positions if the move ended up in
1290 * the item's parent container
1291 */
1292 local_move_only = baul_icon_container_selection_items_local
1293 (container, container->details->dnd_info->drag_info.selection_list);
1294 }
1295
1296 if (local_move_only)
1297 {
1298 handle_local_move (container, world_x, world_y);
1299 }
1300 else
1301 {
1302 handle_nonlocal_move (container, real_action, world_x, world_y, drop_target, icon_hit);
1303 }
1304 }
1305
1306 g_free (drop_target);
1307 baul_drag_destroy_selection_list (container->details->dnd_info->drag_info.selection_list);
1308 container->details->dnd_info->drag_info.selection_list = NULL((void*)0);
1309}
1310
1311static void
1312baul_icon_container_get_drop_action (BaulIconContainer *container,
1313 CdkDragContext *context,
1314 int x, int y,
1315 int *action)
1316{
1317 char *drop_target;
1318 gboolean icon_hit;
1319 BaulIcon *icon;
1320 double world_x, world_y;
1321
1322 icon_hit = FALSE(0);
1323 if (!container->details->dnd_info->drag_info.got_drop_data_type)
1324 {
1325 /* drag_data_received_callback didn't get called yet */
1326 return;
1327 }
1328
1329 /* find out if we're over an icon */
1330 canvas_widget_to_world (EEL_CANVAS (container)((((EelCanvas*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((eel_canvas_get_type ()))))))
, x, y, &world_x, &world_y);
1331
1332 icon = baul_icon_container_item_at (container, world_x, world_y);
1333
1334 *action = 0;
1335
1336 /* case out on the type of object being dragged */
1337 switch (container->details->dnd_info->drag_info.data_type)
1338 {
1339 case BAUL_ICON_DND_CAFE_ICON_LIST:
1340 if (container->details->dnd_info->drag_info.selection_list == NULL((void*)0))
1341 {
1342 return;
1343 }
1344 drop_target = baul_icon_container_find_drop_target (container,
1345 context, x, y, &icon_hit, FALSE(0));
1346 if (!drop_target)
1347 {
1348 return;
1349 }
1350 baul_drag_default_drop_action_for_icons (context, drop_target,
1351 container->details->dnd_info->drag_info.selection_list,
1352 action);
1353 g_free (drop_target);
1354 break;
1355 case BAUL_ICON_DND_URI_LIST:
1356 drop_target = baul_icon_container_find_drop_target (container,
1357 context, x, y, &icon_hit, FALSE(0));
1358 *action = baul_drag_default_drop_action_for_uri_list (context, drop_target);
1359
1360 g_free (drop_target);
1361 break;
1362
1363 /* handle emblems by setting the action if we're over an object */
1364 case BAUL_ICON_DND_KEYWORD:
1365 if (icon != NULL((void*)0))
1366 {
1367 *action = cdk_drag_context_get_suggested_action (context);
1368 }
1369 break;
1370
1371 case BAUL_ICON_DND_NETSCAPE_URL:
1372 *action = baul_drag_default_drop_action_for_netscape_url (context);
1373 break;
1374
1375 case BAUL_ICON_DND_COLOR:
1376 case BAUL_ICON_DND_BGIMAGE:
1377 case BAUL_ICON_DND_RESET_BACKGROUND:
1378 case BAUL_ICON_DND_ROOTWINDOW_DROP:
1379 *action = cdk_drag_context_get_suggested_action (context);
1380 break;
1381
1382 case BAUL_ICON_DND_TEXT:
1383 case BAUL_ICON_DND_XDNDDIRECTSAVE:
1384 case BAUL_ICON_DND_RAW:
1385 *action = CDK_ACTION_COPY;
1386 break;
1387 }
1388}
1389
1390static void
1391set_drop_target (BaulIconContainer *container,
1392 BaulIcon *icon)
1393{
1394 BaulIcon *old_icon;
1395
1396 /* Check if current drop target changed, update icon drop
1397 * higlight if needed.
1398 */
1399 old_icon = container->details->drop_target;
1400 if (icon == old_icon)
1401 {
1402 return;
1403 }
1404
1405 /* Remember the new drop target for the next round. */
1406 container->details->drop_target = icon;
1407 baul_icon_container_update_icon (container, old_icon);
1408 baul_icon_container_update_icon (container, icon);
1409}
1410
1411static void
1412baul_icon_dnd_update_drop_target (BaulIconContainer *container,
1413 CdkDragContext *context,
1414 int x, int y)
1415{
1416 BaulIcon *icon;
1417 double world_x, world_y;
1418
1419 g_assert (BAUL_IS_ICON_CONTAINER (container))do { if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((container)); GType __t = (baul_icon_container_get_type()
); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))) ; else g_assertion_message_expr (((gchar*) 0), "baul-icon-dnd.c"
, 1419, ((const char*) (__func__)), "BAUL_IS_ICON_CONTAINER (container)"
); } while (0)
;
1420
1421 canvas_widget_to_world (EEL_CANVAS (container)((((EelCanvas*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((eel_canvas_get_type ()))))))
, x, y, &world_x, &world_y);
1422
1423 /* Find the item we hit with our drop, if any. */
1424 icon = baul_icon_container_item_at (container, world_x, world_y);
1425
1426 /* FIXME bugzilla.gnome.org 42485:
1427 * These "can_accept_items" tests need to be done by
1428 * the icon view, not here. This file is not supposed to know
1429 * that the target is a file.
1430 */
1431
1432 /* Find if target icon accepts our drop. */
1433 if (icon != NULL((void*)0) && (container->details->dnd_info->drag_info.data_type != BAUL_ICON_DND_KEYWORD))
1434 {
1435 BaulFile *file;
1436 char *uri;
1437
1438 uri = baul_icon_container_get_icon_uri (container, icon);
1439 file = baul_file_get_by_uri (uri);
1440 g_free (uri);
1441
1442 if (!baul_drag_can_accept_info (file,
1443 container->details->dnd_info->drag_info.data_type,
1444 container->details->dnd_info->drag_info.selection_list))
1445 {
1446 icon = NULL((void*)0);
1447 }
1448
1449 baul_file_unref (file);
1450 }
1451
1452 set_drop_target (container, icon);
1453}
1454
1455static void
1456baul_icon_container_free_drag_data (BaulIconContainer *container)
1457{
1458 BaulIconDndInfo *dnd_info;
1459
1460 dnd_info = container->details->dnd_info;
1461
1462 dnd_info->drag_info.got_drop_data_type = FALSE(0);
1463
1464 if (dnd_info->shadow != NULL((void*)0))
1465 {
1466 eel_canvas_item_destroy (dnd_info->shadow);
1467 dnd_info->shadow = NULL((void*)0);
1468 }
1469
1470 if (dnd_info->drag_info.selection_data != NULL((void*)0))
1471 {
1472 ctk_selection_data_free (dnd_info->drag_info.selection_data);
1473 dnd_info->drag_info.selection_data = NULL((void*)0);
1474 }
1475
1476 if (dnd_info->drag_info.direct_save_uri != NULL((void*)0))
1477 {
1478 g_free (dnd_info->drag_info.direct_save_uri);
1479 dnd_info->drag_info.direct_save_uri = NULL((void*)0);
1480 }
1481}
1482
1483static void
1484drag_leave_callback (CtkWidget *widget,
1485 CdkDragContext *context,
1486 guint32 time,
1487 gpointer data)
1488{
1489 BaulIconDndInfo *dnd_info;
1490
1491 dnd_info = BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
->details->dnd_info;
1492
1493 if (dnd_info->shadow != NULL((void*)0))
1494 eel_canvas_item_hide (dnd_info->shadow);
1495
1496 stop_dnd_highlight (widget);
1497
1498 set_drop_target (BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
, NULL((void*)0));
1499 stop_auto_scroll (BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
);
1500 baul_icon_container_free_drag_data(BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
);
1501}
1502
1503static void
1504drag_begin_callback (CtkWidget *widget,
1505 CdkDragContext *context,
1506 gpointer data)
1507{
1508 BaulIconContainer *container;
1509 cairo_surface_t *surface;
1510 double x1, y1, x2, y2, winx, winy;
1511 int x_offset, y_offset;
1512 int start_x, start_y;
1513
1514 container = BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
;
1515
1516 start_x = container->details->dnd_info->drag_info.start_x +
1517 ctk_adjustment_get_value (ctk_scrollable_get_hadjustment (CTK_SCROLLABLE (container)((((CtkScrollable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_scrollable_get_type ()))))))
));
1518 start_y = container->details->dnd_info->drag_info.start_y +
1519 ctk_adjustment_get_value (ctk_scrollable_get_vadjustment (CTK_SCROLLABLE (container)((((CtkScrollable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_scrollable_get_type ()))))))
));
1520
1521 /* create a pixmap and mask to drag with */
1522 surface = baul_icon_canvas_item_get_drag_surface (container->details->drag_icon->item);
1523
1524 /* compute the image's offset */
1525 eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (container->details->drag_icon->item)((((EelCanvasItem*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container->details->drag_icon->item)), ((eel_canvas_item_get_type
()))))))
,
1526 &x1, &y1, &x2, &y2);
1527 eel_canvas_world_to_window (EEL_CANVAS (container)((((EelCanvas*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((eel_canvas_get_type ()))))))
,
1528 x1, y1, &winx, &winy);
1529 x_offset = start_x - winx;
1530 y_offset = start_y - winy;
1531
1532 cairo_surface_set_device_offset (surface, -x_offset, -y_offset);
1533 ctk_drag_set_icon_surface (context, surface);
1534 cairo_surface_destroy (surface);
1535}
1536
1537void
1538baul_icon_dnd_begin_drag (BaulIconContainer *container,
1539 CdkDragAction actions,
1540 int button,
1541 CdkEventMotion *event,
1542 int start_x,
1543 int start_y)
1544{
1545 BaulIconDndInfo *dnd_info;
1546
1547 g_return_if_fail (BAUL_IS_ICON_CONTAINER (container))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((container)); GType __t = (baul_icon_container_get_type()
); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning (((gchar*) 0
), ((const char*) (__func__)), "BAUL_IS_ICON_CONTAINER (container)"
); return; } } while (0)
;
1548 g_return_if_fail (event != NULL)do { if ((event != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "event != NULL");
return; } } while (0)
;
1549
1550 dnd_info = container->details->dnd_info;
1551 g_return_if_fail (dnd_info != NULL)do { if ((dnd_info != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "dnd_info != NULL"
); return; } } while (0)
;
1552
1553 /* Notice that the event is in bin_window coordinates, because of
1554 the way the canvas handles events.
1555 */
1556 dnd_info->drag_info.start_x = start_x -
1557 ctk_adjustment_get_value (ctk_scrollable_get_hadjustment (CTK_SCROLLABLE (container)((((CtkScrollable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_scrollable_get_type ()))))))
));
1558 dnd_info->drag_info.start_y = start_y -
1559 ctk_adjustment_get_value (ctk_scrollable_get_vadjustment (CTK_SCROLLABLE (container)((((CtkScrollable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_scrollable_get_type ()))))))
));
1560
1561 /* start the drag */
1562 ctk_drag_begin_with_coordinates (CTK_WIDGET (container)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_widget_get_type ()))))))
,
1563 dnd_info->drag_info.target_list,
1564 actions,
1565 button,
1566 (CdkEvent *) event,
1567 dnd_info->drag_info.start_x,
1568 dnd_info->drag_info.start_y);
1569}
1570
1571static gboolean
1572drag_highlight_draw (CtkWidget *widget,
1573 cairo_t *cr,
1574 gpointer user_data)
1575{
1576 gint width, height;
1577 CdkWindow *window;
1578 CtkStyleContext *style;
1579
1580 window = ctk_widget_get_window (widget);
1581 width = cdk_window_get_width (window);
1582 height = cdk_window_get_height (window);
1583
1584 style = ctk_widget_get_style_context (widget);
1585
1586 ctk_style_context_save (style);
1587 ctk_style_context_add_class (style, CTK_STYLE_CLASS_DND"dnd");
1588 ctk_style_context_set_state (style, CTK_STATE_FLAG_FOCUSED);
1589
1590 ctk_render_frame (style,
1591 cr,
1592 0, 0, width, height);
1593
1594 ctk_style_context_restore (style);
1595
1596 return FALSE(0);
1597}
1598
1599/* Queue a redraw of the dnd highlight rect */
1600static void
1601dnd_highlight_queue_redraw (CtkWidget *widget)
1602{
1603 BaulIconDndInfo *dnd_info;
1604 int width, height;
1605 CtkAllocation allocation;
1606
1607 dnd_info = BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
->details->dnd_info;
1608
1609 if (!dnd_info->highlighted)
1610 {
1611 return;
1612 }
1613
1614 ctk_widget_get_allocation (widget, &allocation);
1615 width = allocation.width;
1616 height = allocation.height;
1617
1618 /* we don't know how wide the shadow is exactly,
1619 * so we expose a 10-pixel wide border
1620 */
1621 ctk_widget_queue_draw_area (widget,
1622 0, 0,
1623 width, 10);
1624 ctk_widget_queue_draw_area (widget,
1625 0, 0,
1626 10, height);
1627 ctk_widget_queue_draw_area (widget,
1628 0, height - 10,
1629 width, 10);
1630 ctk_widget_queue_draw_area (widget,
1631 width - 10, 0,
1632 10, height);
1633}
1634
1635static void
1636start_dnd_highlight (CtkWidget *widget)
1637{
1638 BaulIconDndInfo *dnd_info;
1639 CtkWidget *toplevel;
1640
1641 dnd_info = BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
->details->dnd_info;
1642
1643 toplevel = ctk_widget_get_toplevel (widget);
1644 if (toplevel != NULL((void*)0) &&
1645 g_object_get_data (G_OBJECT (toplevel)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toplevel)), (((GType) ((20) << (2))))))))
, "is_desktop_window"))
1646 {
1647 return;
1648 }
1649
1650 if (!dnd_info->highlighted)
1651 {
1652 dnd_info->highlighted = TRUE(!(0));
1653 g_signal_connect_after (widget, "draw",g_signal_connect_data ((widget), ("draw"), (((GCallback) (drag_highlight_draw
))), (((void*)0)), ((void*)0), G_CONNECT_AFTER)
1654 G_CALLBACK (drag_highlight_draw),g_signal_connect_data ((widget), ("draw"), (((GCallback) (drag_highlight_draw
))), (((void*)0)), ((void*)0), G_CONNECT_AFTER)
1655 NULL)g_signal_connect_data ((widget), ("draw"), (((GCallback) (drag_highlight_draw
))), (((void*)0)), ((void*)0), G_CONNECT_AFTER)
;
1656 dnd_highlight_queue_redraw (widget);
1657 }
1658}
1659
1660static void
1661stop_dnd_highlight (CtkWidget *widget)
1662{
1663 BaulIconDndInfo *dnd_info;
1664
1665 dnd_info = BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
->details->dnd_info;
1666
1667 if (dnd_info->highlighted)
1668 {
1669 g_signal_handlers_disconnect_by_func (widget,g_signal_handlers_disconnect_matched ((widget), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (drag_highlight_draw), (((void*)0)))
1670 drag_highlight_draw,g_signal_handlers_disconnect_matched ((widget), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (drag_highlight_draw), (((void*)0)))
1671 NULL)g_signal_handlers_disconnect_matched ((widget), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (drag_highlight_draw), (((void*)0)))
;
1672 dnd_highlight_queue_redraw (widget);
1673 dnd_info->highlighted = FALSE(0);
1674 }
1675}
1676
1677static gboolean
1678drag_motion_callback (CtkWidget *widget,
1679 CdkDragContext *context,
1680 int x, int y,
1681 guint32 time)
1682{
1683 int action;
1684
1685 baul_icon_container_ensure_drag_data (BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
, context, time);
1686 baul_icon_container_position_shadow (BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
, x, y);
1687 baul_icon_dnd_update_drop_target (BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
, context, x, y);
1688 set_up_auto_scroll_if_needed (BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
);
1689 /* Find out what the drop actions are based on our drag selection and
1690 * the drop target.
1691 */
1692 action = 0;
1693 baul_icon_container_get_drop_action (BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
, context, x, y,
1694 &action);
1695 if (action != 0)
1696 {
1697 start_dnd_highlight (widget);
1698 }
1699
1700 cdk_drag_status (context, action, time);
1701
1702 return TRUE(!(0));
1703}
1704
1705static gboolean
1706drag_drop_callback (CtkWidget *widget,
1707 CdkDragContext *context,
1708 int x,
1709 int y,
1710 guint32 time,
1711 gpointer data)
1712{
1713 BaulIconDndInfo *dnd_info;
1714
1715 dnd_info = BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
->details->dnd_info;
1716
1717 /* tell the drag_data_received callback that
1718 the drop occured and that it can actually
1719 process the actions.
1720 make sure it is going to be called at least once.
1721 */
1722 dnd_info->drag_info.drop_occured = TRUE(!(0));
1723
1724 get_data_on_first_target_we_support (widget, context, time, x, y);
1725
1726 return TRUE(!(0));
1727}
1728
1729void
1730baul_icon_dnd_end_drag (BaulIconContainer *container)
1731{
1732 BaulIconDndInfo *dnd_info;
1733
1734 g_return_if_fail (BAUL_IS_ICON_CONTAINER (container))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((container)); GType __t = (baul_icon_container_get_type()
); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning (((gchar*) 0
), ((const char*) (__func__)), "BAUL_IS_ICON_CONTAINER (container)"
); return; } } while (0)
;
1735
1736 dnd_info = container->details->dnd_info;
1737 g_return_if_fail (dnd_info != NULL)do { if ((dnd_info != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "dnd_info != NULL"
); return; } } while (0)
;
1738 stop_auto_scroll (container);
1739 /* Do nothing.
1740 * Can that possibly be right?
1741 */
1742}
1743
1744/** this callback is called in 2 cases.
1745 It is called upon drag_motion events to get the actual data
1746 In that case, it just makes sure it gets the data.
1747 It is called upon drop_drop events to execute the actual
1748 actions on the received action. In that case, it actually first makes sure
1749 that we have got the data then processes it.
1750*/
1751
1752static void
1753drag_data_received_callback (CtkWidget *widget,
1754 CdkDragContext *context,
1755 int x,
1756 int y,
1757 CtkSelectionData *data,
1758 guint info,
1759 guint32 time,
1760 gpointer user_data)
1761{
1762 BaulDragInfo *drag_info;
1763 gboolean success;
1764
1765 drag_info = &(BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
->details->dnd_info->drag_info);
1766
1767 drag_info->got_drop_data_type = TRUE(!(0));
1768 drag_info->data_type = info;
1769
1770 switch (info)
1771 {
1772 case BAUL_ICON_DND_CAFE_ICON_LIST:
1773 baul_icon_container_dropped_icon_feedback (widget, data, x, y);
1774 break;
1775 case BAUL_ICON_DND_COLOR:
1776 case BAUL_ICON_DND_BGIMAGE:
1777 case BAUL_ICON_DND_KEYWORD:
1778 case BAUL_ICON_DND_URI_LIST:
1779 case BAUL_ICON_DND_TEXT:
1780 case BAUL_ICON_DND_RESET_BACKGROUND:
1781 case BAUL_ICON_DND_XDNDDIRECTSAVE:
1782 case BAUL_ICON_DND_RAW:
1783 /* Save the data so we can do the actual work on drop. */
1784 if (drag_info->selection_data != NULL((void*)0))
1785 {
1786 ctk_selection_data_free (drag_info->selection_data);
1787 }
1788 drag_info->selection_data = ctk_selection_data_copy (data);
1789 break;
1790
1791 /* Netscape keeps sending us the data, even though we accept the first drag */
1792 case BAUL_ICON_DND_NETSCAPE_URL:
1793 if (drag_info->selection_data != NULL((void*)0))
1794 {
1795 ctk_selection_data_free (drag_info->selection_data);
1796 drag_info->selection_data = ctk_selection_data_copy (data);
1797 }
1798 break;
1799 case BAUL_ICON_DND_ROOTWINDOW_DROP:
1800 /* Do nothing, this won't even happen, since we don't want to call get_data twice */
1801 break;
1802 }
1803
1804 /* this is the second use case of this callback.
1805 * we have to do the actual work for the drop.
1806 */
1807 if (drag_info->drop_occured)
1808 {
1809 EelBackground *background;
1810 char *tmp;
1811 const char *tmp_raw;
1812 int length;
1813
1814 success = FALSE(0);
1815 switch (info)
1816 {
1817 case BAUL_ICON_DND_CAFE_ICON_LIST:
1818 baul_icon_container_receive_dropped_icons
1819 (BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
,
1820 context, x, y);
1821 break;
1822 case BAUL_ICON_DND_COLOR:
1823 receive_dropped_color (BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
,
1824 x, y,
1825 cdk_drag_context_get_selected_action (context),
1826 data);
1827 success = TRUE(!(0));
1828 break;
1829 case BAUL_ICON_DND_BGIMAGE:
1830 receive_dropped_tile_image
1831 (BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
,
1832 cdk_drag_context_get_selected_action (context),
1833 data);
1834 break;
1835 case BAUL_ICON_DND_KEYWORD:
1836 receive_dropped_keyword
1837 (BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
,
1838 (char *) ctk_selection_data_get_data (data), x, y);
1839 break;
1840 case BAUL_ICON_DND_NETSCAPE_URL:
1841 receive_dropped_netscape_url
1842 (BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
,
1843 (char *) ctk_selection_data_get_data (data), context, x, y);
1844 success = TRUE(!(0));
1845 break;
1846 case BAUL_ICON_DND_URI_LIST:
1847 receive_dropped_uri_list
1848 (BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
,
1849 (char *) ctk_selection_data_get_data (data), context, x, y);
1850 success = TRUE(!(0));
1851 break;
1852 case BAUL_ICON_DND_TEXT:
1853 tmp = ctk_selection_data_get_text (data);
1854 receive_dropped_text
1855 (BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
,
1856 (char *) tmp, context, x, y);
1857 success = TRUE(!(0));
1858 g_free (tmp);
1859 break;
1860 case BAUL_ICON_DND_RAW:
1861 length = ctk_selection_data_get_length (data);
1862 tmp_raw = ctk_selection_data_get_data (data);
1863 receive_dropped_raw
1864 (BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
,
1865 tmp_raw, length, drag_info->direct_save_uri,
1866 context, x, y);
1867 success = TRUE(!(0));
1868 break;
1869 case BAUL_ICON_DND_RESET_BACKGROUND:
1870 background = eel_get_widget_background (widget);
1871 if (background != NULL((void*)0))
1872 {
1873 eel_background_reset (background);
1874 }
1875 ctk_drag_finish (context, FALSE(0), FALSE(0), time);
1876 break;
1877 case BAUL_ICON_DND_ROOTWINDOW_DROP:
1878 /* Do nothing, everything is done by the sender */
1879 break;
1880 case BAUL_ICON_DND_XDNDDIRECTSAVE:
1881 {
1882 const guchar *selection_data;
1883 gint selection_length;
1884 gint selection_format;
1885
1886 selection_data = ctk_selection_data_get_data (drag_info->selection_data);
1887 selection_length = ctk_selection_data_get_length (drag_info->selection_data);
1888 selection_format = ctk_selection_data_get_format (drag_info->selection_data);
1889
1890 if (selection_format == 8 &&
1891 selection_length == 1 &&
1892 selection_data[0] == 'F')
1893 {
1894 ctk_drag_get_data (widget, context,
1895 cdk_atom_intern (BAUL_ICON_DND_RAW_TYPE"application/octet-stream",
1896 FALSE(0)),
1897 time);
1898 return;
1899 }
1900 else if (selection_format == 8 &&
1901 selection_length == 1 &&
1902 selection_data[0] == 'F' &&
1903 drag_info->direct_save_uri != NULL((void*)0))
1904 {
1905 CdkPoint p;
1906 GFile *location;
1907
1908 location = g_file_new_for_uri (drag_info->direct_save_uri);
1909
1910 baul_file_changes_queue_file_added (location);
1911 p.x = x;
1912 p.y = y;
1913 baul_file_changes_queue_schedule_position_set (
1914 location,
1915 p,
1916 cdk_x11_screen_get_screen_number (
1917 ctk_widget_get_screen (widget)));
1918 g_object_unref (location);
1919 baul_file_changes_consume_changes (TRUE(!(0)));
1920 success = TRUE(!(0));
1921 }
1922 break;
1923 } /* BAUL_ICON_DND_XDNDDIRECTSAVE */
1924 }
1925 ctk_drag_finish (context, success, FALSE(0), time);
1926
1927 baul_icon_container_free_drag_data (BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
);
1928
1929 set_drop_target (BAUL_ICON_CONTAINER (widget)((((BaulIconContainer*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), (baul_icon_container_get_type())
))))
, NULL((void*)0));
1930
1931 /* reinitialise it for the next dnd */
1932 drag_info->drop_occured = FALSE(0);
1933 }
1934
1935}
1936
1937void
1938baul_icon_dnd_init (BaulIconContainer *container)
1939{
1940 CtkTargetList *targets;
1941 int n_elements;
1942
1943 g_return_if_fail (container != NULL)do { if ((container != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "container != NULL"
); return; } } while (0)
;
1944 g_return_if_fail (BAUL_IS_ICON_CONTAINER (container))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((container)); GType __t = (baul_icon_container_get_type()
); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning (((gchar*) 0
), ((const char*) (__func__)), "BAUL_IS_ICON_CONTAINER (container)"
); return; } } while (0)
;
1945
1946
1947 container->details->dnd_info = g_new0 (BaulIconDndInfo, 1)((BaulIconDndInfo *) g_malloc0_n ((1), sizeof (BaulIconDndInfo
)))
;
1948 baul_drag_init (&container->details->dnd_info->drag_info,
1949 drag_types, G_N_ELEMENTS (drag_types)(sizeof (drag_types) / sizeof ((drag_types)[0])), TRUE(!(0)));
1950
1951 /* Set up the widget as a drag destination.
1952 * (But not a source, as drags starting from this widget will be
1953 * implemented by dealing with events manually.)
1954 */
1955 n_elements = G_N_ELEMENTS (drop_types)(sizeof (drop_types) / sizeof ((drop_types)[0]));
1956 if (!baul_icon_container_get_is_desktop (container))
1957 {
1958 /* Don't set up rootwindow drop */
1959 n_elements -= 1;
1960 }
1961 ctk_drag_dest_set (CTK_WIDGET (container)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_widget_get_type ()))))))
,
1962 0,
1963 drop_types, n_elements,
1964 CDK_ACTION_COPY | CDK_ACTION_MOVE | CDK_ACTION_LINK | CDK_ACTION_ASK);
1965
1966 targets = ctk_drag_dest_get_target_list (CTK_WIDGET (container)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_widget_get_type ()))))))
);
1967 ctk_target_list_add_text_targets (targets, BAUL_ICON_DND_TEXT);
1968
1969
1970 /* Messages for outgoing drag. */
1971 g_signal_connect (container, "drag_begin",g_signal_connect_data ((container), ("drag_begin"), (((GCallback
) (drag_begin_callback))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
1972 G_CALLBACK (drag_begin_callback), NULL)g_signal_connect_data ((container), ("drag_begin"), (((GCallback
) (drag_begin_callback))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
1973 g_signal_connect (container, "drag_data_get",g_signal_connect_data ((container), ("drag_data_get"), (((GCallback
) (drag_data_get_callback))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
1974 G_CALLBACK (drag_data_get_callback), NULL)g_signal_connect_data ((container), ("drag_data_get"), (((GCallback
) (drag_data_get_callback))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
1975 g_signal_connect (container, "drag_end",g_signal_connect_data ((container), ("drag_end"), (((GCallback
) (drag_end_callback))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
1976 G_CALLBACK (drag_end_callback), NULL)g_signal_connect_data ((container), ("drag_end"), (((GCallback
) (drag_end_callback))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
1977
1978 /* Messages for incoming drag. */
1979 g_signal_connect (container, "drag_data_received",g_signal_connect_data ((container), ("drag_data_received"), (
((GCallback) (drag_data_received_callback))), (((void*)0)), (
(void*)0), (GConnectFlags) 0)
1980 G_CALLBACK (drag_data_received_callback), NULL)g_signal_connect_data ((container), ("drag_data_received"), (
((GCallback) (drag_data_received_callback))), (((void*)0)), (
(void*)0), (GConnectFlags) 0)
;
1981 g_signal_connect (container, "drag_motion",g_signal_connect_data ((container), ("drag_motion"), (((GCallback
) (drag_motion_callback))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
1982 G_CALLBACK (drag_motion_callback), NULL)g_signal_connect_data ((container), ("drag_motion"), (((GCallback
) (drag_motion_callback))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
1983 g_signal_connect (container, "drag_drop",g_signal_connect_data ((container), ("drag_drop"), (((GCallback
) (drag_drop_callback))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
1984 G_CALLBACK (drag_drop_callback), NULL)g_signal_connect_data ((container), ("drag_drop"), (((GCallback
) (drag_drop_callback))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
1985 g_signal_connect (container, "drag_leave",g_signal_connect_data ((container), ("drag_leave"), (((GCallback
) (drag_leave_callback))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
1986 G_CALLBACK (drag_leave_callback), NULL)g_signal_connect_data ((container), ("drag_leave"), (((GCallback
) (drag_leave_callback))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
1987}
1988
1989void
1990baul_icon_dnd_fini (BaulIconContainer *container)
1991{
1992 g_return_if_fail (BAUL_IS_ICON_CONTAINER (container))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((container)); GType __t = (baul_icon_container_get_type()
); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning (((gchar*) 0
), ((const char*) (__func__)), "BAUL_IS_ICON_CONTAINER (container)"
); return; } } while (0)
;
1993
1994 if (container->details->dnd_info != NULL((void*)0))
1995 {
1996 stop_auto_scroll (container);
1997
1998 baul_drag_finalize (&container->details->dnd_info->drag_info);
1999 container->details->dnd_info = NULL((void*)0);
2000 }
2001}