Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtprintinfo / libUI / MotifUI / DtDND.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: DtDND.C /main/7 1998/08/03 08:58:53 mgreess $ */
24 /*                                                                      *
25  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
26  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
27  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
28  * (c) Copyright 1993, 1994 Novell, Inc.                                *
29  */
30
31 #include "stdlib.h"
32
33 #include "DtDND.h"
34 #include "IconObj.h"
35 #include "Icon.h"
36 #include "Dt/Dnd.h"
37 #include <Xm/DragCP.h>
38 #include <Dt/Wsm.h>
39 #include <Dt/Action.h>
40
41 #include <stdio.h>
42
43 extern "C" {
44 extern XtPointer _XmStringUngenerate (
45                                 XmString string,
46                                 XmStringTag tag,
47                                 XmTextType tag_type,
48                                 XmTextType output_type);
49 }
50
51 #define DRAG_THRESHOLD 10
52
53 // Absolute value macro
54 #ifndef ABS
55 #define ABS(x) (((x) > 0) ? (x) : (-(x)))
56 #endif
57
58 boolean DtDND::FirstTime = true;
59 XtCallbackRec DtDND::transferCBRec[] =
60 {
61    {&DtDND::TransferCB, NULL}, {NULL, NULL}
62 };
63 XtCallbackRec DtDND::convertCBRec[] =
64 {
65    {&DtDND::ConvertCB, NULL}, {NULL, NULL}
66 };
67 XtCallbackRec DtDND::dragFinishCBRec[] =
68 {
69    {&DtDND::DragFinishCB, NULL}, {NULL, NULL}
70 };
71 XtCallbackRec DtDND::dropOnRootCBRec[] =
72 {
73    {&DtDND::DropOnRootCB, NULL}, {NULL, NULL}
74 };
75 XtCallbackRec DtDND::animateCBRec[] =
76 {
77    {&DtDND::AnimateCB, NULL}, {NULL, NULL}
78 };
79 boolean DtDND::DoingDrag = false;
80 GC DtDND::gc;
81 GC DtDND::gc_mask;
82
83 DtDND::DtDND(MotifUI *_obj, DNDCallback _dndCB, boolean _can_drop_on_root)
84 {
85    if (FirstTime)
86     {
87       MotifUI *tmp = (MotifUI *)_obj;
88       Pixmap tmp_pixmap;
89       BaseUI *parent = _obj;
90       while (parent->Parent())
91          parent = parent->Parent();
92       tmp_pixmap = XCreatePixmap(tmp->display, tmp->root, 1, 1, tmp->depth);
93       gc = XCreateGC(tmp->display, tmp_pixmap, 0, NULL);
94       tmp_pixmap = XCreatePixmap(tmp->display, tmp->root, 1, 1, 1);
95       gc_mask = XCreateGC(tmp->display, tmp_pixmap, 0, NULL);
96       XSetFont(tmp->display, gc, tmp->font);
97       FirstTime = false;
98     }
99
100    obj = _obj;
101    can_drop_on_root = _can_drop_on_root;
102    dndCB = _dndCB;
103    dragIcon = NULL;
104    sourceIcon = NULL;
105
106    // Set up Drop
107    transferCBRec[0].closure = (XtPointer)this;
108    animateCBRec[0].closure = (XtPointer)this;
109    if (obj->UIClass() == ICON)
110     {
111       GetRects();
112       XtVaSetValues(obj->BaseWidget(), XmNshadowThickness, 2, NULL);
113       Arg args[6];
114       XtSetArg(args[0], XmNdropSiteType, XmDROP_SITE_SIMPLE);
115       XtSetArg(args[1], XmNanimationStyle, XmDRAG_UNDER_SHADOW_IN);
116       XtSetArg(args[2], XmNnumDropRectangles, 2);
117       XtSetArg(args[3], XmNdropRectangles, &rects);
118       XtSetArg(args[4], DtNdropAnimateCallback, animateCBRec);
119       XtSetArg(args[5], DtNtextIsBuffer, True);
120       DtDndDropRegister(obj->BaseWidget(), DtDND_FILENAME_TRANSFER|
121                         DtDND_BUFFER_TRANSFER,
122                         (unsigned char)XmDROP_COPY, transferCBRec, args, 6); 
123
124       // Set up Drag on Button1
125       XtAddEventHandler(obj->BaseWidget(), Button1MotionMask,  False, 
126                         (XtEventHandler)DragMotionHandler, (XtPointer)this);
127
128       // Set up Drag on Button2 if not using it for BMenu already
129       if (MotifUI::bMenuButton != Button2)
130        {
131          XtAddEventHandler(obj->BaseWidget(), Button2MotionMask,  False, 
132                         (XtEventHandler)DragMotionHandler, (XtPointer)this);
133        }
134     }
135    else
136     {
137       Arg args[2];
138       XtSetArg(args[0], DtNdropAnimateCallback, animateCBRec);
139       XtSetArg(args[1], DtNtextIsBuffer, True);
140       DtDndDropRegister(obj->BaseWidget(), DtDND_FILENAME_TRANSFER|
141                         DtDND_BUFFER_TRANSFER,
142                         (unsigned char)XmDROP_COPY, transferCBRec, args, 2);
143     }
144    pixmap = 0L;
145    mask = 0L;
146    name = NULL;
147    iconFile = NULL;
148    string = NULL;
149 }
150
151 DtDND::~DtDND()
152 {
153    MotifUI *icon = (MotifUI *)obj;
154    if (pixmap && pixmap != XmUNSPECIFIED_PIXMAP)
155       XFreePixmap(icon->display, pixmap);
156    if (mask && mask != XmUNSPECIFIED_PIXMAP)
157       XFreePixmap(icon->display, mask);
158    free(name);
159    delete iconFile;
160    XmStringFree(string);
161    if (sourceIcon)
162     {
163       XtDestroyWidget(sourceIcon);
164       sourceIcon = NULL;
165     }
166    if (dragIcon)
167     {
168       XtDestroyWidget(dragIcon);
169       dragIcon = NULL;
170     }
171 }
172
173 void DtDND::GetDragPixmaps()
174 {
175    IconObj *icon = (IconObj *)obj;
176    Pixmap tmp_pixmap, tmp_mask;
177
178    delete iconFile;
179    free(name);
180    XmStringFree(string);
181    if (pixmap && pixmap != XmUNSPECIFIED_PIXMAP)
182       XFreePixmap(icon->display, pixmap);
183    if (mask && mask != XmUNSPECIFIED_PIXMAP)
184       XFreePixmap(icon->display, mask);
185    mask = 0L;
186    pixmap = 0L;
187    name = strdup(icon->Name());
188    icon_size = icon->IconView();
189    selected = icon->Selected();
190    iconFile = new char[strlen(icon->IconFile()) + 6];
191
192    Dimension height, width;
193    unsigned int w, h, junk;
194
195    XtVaGetValues(icon->BaseWidget(), XmNbackground, &bg, XmNforeground, &fg,
196                  GuiNselectColor, &selectColor, XmNalignment, &alignment,
197                  GuiNshowSelectedPixmap, &showSelectedPixmap,
198                  XmNstringDirection, &stringDirection,
199                  GuiNtextSelectColor, &textSelectColor,
200                  XmNlabelString, &string, XmNfontList, &fontList, NULL);
201
202    XmStringExtent(fontList, string, &width, &height);
203    if (icon_size == LARGE_ICON)
204       string_border_width = 1;
205    else
206       string_border_width = 0;
207    height += 2 * string_border_width;
208    width += 2 * string_border_width;
209    s_x = s_y = string_border_width;
210    p_x = p_y = 0;
211    s_w = width;
212    s_h = height;
213    p_w = p_h = 0;
214    switch (icon_size)
215    {
216    case DETAILS:
217    case SMALL_ICON:
218       sprintf(iconFile, "%s.t.pm", icon->IconFile());
219       icon->GetPixmaps(icon->BaseWidget(), iconFile, &tmp_pixmap, &tmp_mask);
220       if (tmp_pixmap && tmp_pixmap != XmUNSPECIFIED_PIXMAP)
221        {
222          XGetGeometry(icon->display, tmp_pixmap, (Window *) &junk, 
223                       (int *) &junk, (int *) &junk, &w, &h, &junk, &junk);
224          p_w = w;
225          p_h = h;
226          w += 2;
227          s_x += w;
228          width += w;
229          if (h > height)
230           {
231             s_y = (h - height) / 2;
232             height = h;
233           }
234          else
235             p_y = (height - h) / 2;
236        }
237       break;
238    case LARGE_ICON:
239       sprintf(iconFile, "%s.m.pm", icon->IconFile());
240       icon->GetPixmaps(icon->BaseWidget(), iconFile, &tmp_pixmap, &tmp_mask);
241       if (tmp_pixmap && tmp_pixmap != XmUNSPECIFIED_PIXMAP)
242        {
243          XGetGeometry(icon->display, tmp_pixmap, (Window *) &junk, 
244                       (int *) &junk, (int *) &junk, &w, &h, &junk, &junk);
245          p_w = w;
246          p_h = h;
247          h += 2;
248          s_y += h;
249          height += h;
250          if (w > width)
251             width = w;
252        }
253       break;
254    default:
255       sprintf(iconFile, "%s.m.pm", icon->IconFile());
256       icon->GetPixmaps(icon->BaseWidget(), iconFile, &tmp_pixmap, &tmp_mask);
257       break;
258    }
259
260
261    // Create pixmap
262    pixmap = XCreatePixmap(icon->display, icon->root, width, height,
263                           icon->depth);
264    if (icon_size != NAME_ONLY &&
265        tmp_pixmap && tmp_pixmap != XmUNSPECIFIED_PIXMAP)
266     {
267       mask = XCreatePixmap(icon->display, icon->root, width, height, 1);
268       // Clear mask
269       XSetForeground(icon->display, gc_mask, 0);
270       XFillRectangle(icon->display, mask, gc_mask, 0, 0, width, height);
271
272       // Set Mask Bits
273       XSetForeground(icon->display, gc_mask, 1);
274       if (icon_size == LARGE_ICON)
275        {
276 #ifndef hpux
277          if (tmp_mask && tmp_mask != XmUNSPECIFIED_PIXMAP)
278           {
279             XSetClipOrigin(icon->display, gc_mask, p_x, p_y);
280             XSetClipMask(icon->display, gc_mask, tmp_mask);
281             XFillRectangle(icon->display, mask, gc_mask, p_x, p_y, p_w, p_h);
282             XSetClipMask(icon->display, gc_mask, None);
283             XSetClipOrigin(icon->display, gc_mask, 0, 0);
284           }
285          else
286 #endif
287             XFillRectangle(icon->display, mask, gc_mask, p_x, p_y, p_w, p_h);
288        }
289       else
290          XFillRectangle(icon->display, mask, gc_mask, p_x, p_y, p_w - 1,
291                         p_h - 1);
292
293       if (icon_size == LARGE_ICON)
294          XFillRectangle(icon->display, mask, gc_mask, s_x - string_border_width,
295                         s_y - string_border_width,
296                         s_w + 2 * string_border_width,
297                         s_h + 2 * string_border_width);
298       else
299          XFillRectangle(icon->display, mask, gc_mask, s_x, s_y, s_w - 1,
300                         s_h - 1);
301     }
302    // If selected use selectColor as background
303    if (showSelectedPixmap && selected)
304       bg = selectColor;
305
306    // Copy Pixmap to new pixmap
307    XSetClipMask(icon->display, gc, None);
308    XSetFillStyle(icon->display, gc, FillSolid);
309    XSetForeground(icon->display, gc, bg);
310    if (icon_size == LARGE_ICON)
311       XFillRectangle(icon->display, pixmap, gc, p_x, p_y, p_w, p_h);
312    else
313       XFillRectangle(icon->display, pixmap, gc, p_x, p_y, p_w - 1, p_h - 1);
314    XSetClipOrigin(icon->display, gc, p_x, p_y);
315    if (tmp_mask && tmp_mask != XmUNSPECIFIED_PIXMAP)
316       XSetClipMask(icon->display, gc, tmp_mask);
317    else
318       XSetClipMask(icon->display, gc, None);
319    if (icon_size == LARGE_ICON)
320       XCopyArea(icon->display, tmp_pixmap, pixmap, gc, 0, 0, p_w, p_h,
321                 p_x, p_y);
322    else
323       XCopyArea(icon->display, tmp_pixmap, pixmap, gc, 0, 0, p_w - 1, p_h - 1,
324                 p_x, p_y);
325    XSetClipMask(icon->display, gc, None);
326    XSetClipOrigin(icon->display, gc, 0, 0);
327    DrawString();
328
329    Arg args[11];
330    int n = 0;
331    w = width;
332    h = height;
333    XtSetArg(args[n], XmNwidth, w);  n++;
334    XtSetArg(args[n], XmNheight, h);  n++;
335    XtSetArg(args[n], XmNmaxWidth, w);  n++;
336    XtSetArg(args[n], XmNmaxHeight, h);  n++;
337    XtSetArg(args[n], XmNdepth, icon->depth);  n++;
338    XtSetArg(args[n], XmNforeground, bg);  n++;
339    XtSetArg(args[n], XmNbackground, fg);  n++;
340    XtSetArg(args[n], XmNpixmap, pixmap);  n++;
341    if (mask)
342     {
343       XtSetArg(args[n], XmNmask, mask);
344       n++;
345     }
346
347    dragIcon = XmCreateDragIcon(icon->BaseWidget(), "dragIcon", args, n);
348
349    n = 0;
350    if (icon_size == LARGE_ICON)
351       sprintf(iconFile, "%s.m.bm", icon->IconFile());
352    else
353       sprintf(iconFile, "%s.t.bm", icon->IconFile());
354    icon->GetPixmaps(icon->BaseWidget(), iconFile, &tmp_pixmap);
355
356    if (!(tmp_pixmap && tmp_pixmap != XmUNSPECIFIED_PIXMAP))
357     {
358       static Pixmap l_pixmap = (Pixmap)NULL, s_pixmap = (Pixmap)NULL;
359       if (icon_size == LARGE_ICON)
360        {
361          if (!l_pixmap)
362           {
363             l_pixmap = XCreatePixmap(icon->display, icon->root, p_w, p_h, 1);
364             XFillRectangle(icon->display, l_pixmap, gc_mask, 0, 0, p_w, p_h);
365           }
366          tmp_pixmap = l_pixmap;
367        }
368       else
369        {
370          if (icon_size == NAME_ONLY)
371           {
372             p_w = 16;
373             p_h = 16;
374           }
375          if (!s_pixmap)
376           {
377             s_pixmap = XCreatePixmap(icon->display, icon->root, p_w, p_h, 1);
378             XFillRectangle(icon->display, s_pixmap, gc_mask, 0, 0, p_w, p_h);
379           }
380          tmp_pixmap = s_pixmap;
381        }
382     }
383
384    if (icon_size == NAME_ONLY)
385     {
386       w = 16;
387       h = 16;
388     }
389    else
390     {
391       w = p_w;
392       h = p_h;
393     }
394    XtSetArg(args[n], XmNwidth, w);  n++;
395    XtSetArg(args[n], XmNheight, h);  n++;
396    XtSetArg(args[n], XmNmaxWidth, w);  n++;
397    XtSetArg(args[n], XmNmaxHeight, h);  n++;
398    XtSetArg(args[n], XmNdepth, 1);  n++;
399    XtSetArg(args[n], XmNforeground, icon->black);  n++;
400    XtSetArg(args[n], XmNbackground, icon->white);  n++;
401    XtSetArg(args[n], XmNpixmap, tmp_pixmap);  n++;
402    if (tmp_mask && tmp_mask != XmUNSPECIFIED_PIXMAP)
403     {
404       XtSetArg(args[n], XmNmask, tmp_mask);
405       n++;
406     }
407
408    sourceIcon = XmCreateDragIcon(icon->BaseWidget(), "sourceIcon", args, n);
409    strcpy(iconFile, icon->IconFile());
410 }
411
412 void DtDND::DrawString()
413 {
414    IconObj *icon = (IconObj *)obj;
415
416    // Draw String
417    if (selected)
418       XSetForeground(icon->display, gc, selectColor);
419    else
420       XSetForeground(icon->display, gc, bg);
421    if (icon_size == LARGE_ICON)
422       XFillRectangle(icon->display, pixmap, gc, s_x - string_border_width,
423                      s_y - string_border_width, s_w + 2 * string_border_width,
424                      s_h + 2 * string_border_width);
425    else
426       XFillRectangle(icon->display, pixmap, gc, s_x, s_y, s_w - 1, s_h - 1);
427    // If selected use selectColor as background
428    if (selected)
429       XSetForeground(icon->display, gc, textSelectColor);
430    else
431       XSetForeground(icon->display, gc, fg);
432    XmStringDraw(icon->display, pixmap, fontList, string, gc, s_x, s_y, s_w,
433                 alignment, stringDirection, NULL);
434 }
435
436 void DtDND::GetRects()
437 {
438    Dimension shadow, highlight, margin;
439
440    XtVaGetValues(obj->BaseWidget(), XmNhighlightThickness, &highlight, 
441                  GuiNiconMarginThickness, &margin, 
442                  GuiNiconShadowThickness, &shadow, NULL);
443
444    margin += (shadow + highlight);
445    GuiIconGetRects(obj->BaseWidget(), &rects[0], &rects[1]);
446    rects[0].x -= margin;
447    rects[0].y -= margin;
448    rects[0].width += (2 * margin);
449    rects[0].height += (2 * margin);
450    rects[1].x -= margin;
451    rects[1].y -= margin;
452    rects[1].width += (2 * margin);
453    rects[1].height += (2 * margin);
454 }
455
456 void DtDND::UpdateActivity(boolean flag)
457 {
458    Arg args[3];
459    int n = 0;
460
461    if (flag)
462     {
463       XtSetArg(args[n], XmNdropSiteOperations, XmDROP_COPY | XmDROP_MOVE); n++;
464       XtSetArg(args[n], XmNdropSiteActivity, XmDROP_SITE_ACTIVE); n++;
465       if (obj->UIClass() == ICON)
466          XtSetArg(args[n], XmNanimationStyle, XmDRAG_UNDER_SHADOW_IN);
467       else
468          XtSetArg(args[n], XmNanimationStyle, XmDRAG_UNDER_HIGHLIGHT);
469       n++;
470     }
471    else
472     {
473       XtSetArg(args[n], XmNdropSiteOperations, XmDROP_NOOP); n++;
474       XtSetArg(args[n], XmNdropSiteActivity, XmDROP_SITE_INACTIVE); n++;
475       XtSetArg(args[n], XmNanimationStyle, XmDRAG_UNDER_NONE); n++;
476     }
477    XmDropSiteUpdate(obj->BaseWidget(), args, n);
478    if (flag)
479       XmDropSiteConfigureStackingOrder(obj->BaseWidget(), NULL, XmABOVE);
480    else
481       XmDropSiteConfigureStackingOrder(obj->BaseWidget(), NULL, XmBELOW);
482 }
483
484 void DtDND::UpdateRects()
485 {
486    Arg args[2];
487
488    GetRects();
489    XtSetArg(args[0], XmNnumDropRectangles, 2);
490    XtSetArg(args[1], XmNdropRectangles, &rects);
491    XmDropSiteUpdate(obj->BaseWidget(), args, 2);
492 }
493
494 void DtDND::AnimateCB(Widget /*widget*/, XtPointer client_data,
495                       XtPointer call_data)
496 {
497    DtDND *obj = (DtDND *)client_data;
498    if (obj->dndCB)
499     {
500       DtDndDropAnimateCallbackStruct *animateInfo;
501       animateInfo = (DtDndDropAnimateCallbackStruct *) call_data;
502       int i = 0, numItems;
503       numItems = animateInfo->dropData->numItems;
504       //for (i = 0; i < numItems; i++)
505        {
506          (*obj->dndCB)(obj->obj, NULL, NULL, ANIMATE);
507        }
508     }
509 }
510
511 void DtDND::TransferCB(Widget /*widget*/, XtPointer client_data,
512                        XtPointer call_data)
513 {
514    DtDndTransferCallbackStruct *transferInfo;
515    transferInfo = (DtDndTransferCallbackStruct *) call_data;
516    char *value;
517    int len, i, numItems;
518
519    DtDND *obj = (DtDND *)client_data;
520    numItems = transferInfo->dropData->numItems;
521    switch (transferInfo->dropData->protocol)
522    {
523    case DtDND_FILENAME_TRANSFER:
524       if (obj->dndCB)
525        {
526          for (i = 0; i < numItems; i++)
527           {
528             value = transferInfo->dropData->data.files[i];
529             len = strlen(value);
530             (*obj->dndCB)(obj->obj, &value, &len, FILENAME_TRANSFER);
531           }
532        }
533       break;
534    case DtDND_TEXT_TRANSFER:
535       if (obj->dndCB)
536        {
537          for (i = 0; i < numItems; i++)
538           {
539             value = (char *) _XmStringUngenerate(
540                                 transferInfo->dropData->data.strings[i], NULL,
541                                 XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
542             len = strlen(value);
543             (*obj->dndCB)(obj->obj, &value, &len, TEXT_TRANSFER);
544             if (NULL != value)
545               XtFree(value);
546           }
547        }
548       break;
549    case DtDND_BUFFER_TRANSFER:
550       if (obj->dndCB)
551        {
552          (*obj->dndCB)(obj->obj, &value, &len, BUFFER_TRANSFER);
553          DtActionArg *aap = new DtActionArg[numItems];
554          memset(aap, 0, numItems * sizeof(DtActionArg));
555          for (i = 0; i < numItems; i++)
556           {
557             aap[i].argClass = DtACTION_BUFFER;
558             aap[i].u.buffer.bp = transferInfo->dropData->data.buffers[i].bp;
559             aap[i].u.buffer.size = transferInfo->dropData->data.buffers[i].size;
560             aap[i].u.buffer.name = transferInfo->dropData->data.buffers[i].name;
561           }
562          MotifUI *tmp = (MotifUI *)obj->obj;
563          DtActionInvoke(tmp->topLevel, value, aap, numItems, NULL, NULL, NULL,
564                         1, NULL, NULL);
565          delete aap;
566          delete value;
567        }
568       break;
569    default:
570       transferInfo->status = DtDND_FAILURE;
571       break;
572    }
573 }
574
575 void DtDND::DragMotionHandler(Widget /*widget*/, XtPointer client_data,
576                               XEvent *event, Boolean * /*continued*/)
577 {
578    static int initialX = -1;
579    static int initialY = -1;
580    int diffX, diffY;
581    DtDND *obj = (DtDND *)client_data;
582
583    if (obj->DoingDrag)
584       return;
585
586    // If the drag is just starting, set initial button down coords
587    if (initialX == -1 && initialY == -1)
588     {
589       initialX = event->xmotion.x;
590       initialY = event->xmotion.y;
591     }
592    // Find out how far pointer has moved since button press
593    diffX = initialX - event->xmotion.x;
594    diffY = initialY - event->xmotion.y;
595
596    if ((ABS(diffX) >= DRAG_THRESHOLD) ||
597        (ABS(diffY) >= DRAG_THRESHOLD))
598     {
599       obj->DoingDrag = true;
600       obj->StartDrag(event);
601       initialX = -1;
602       initialY = -1;
603    }
604 }
605
606 void DtDND::DragFinishCB(Widget /*widget*/, XtPointer client_data,
607                          XtPointer /*callData*/)
608 {
609    DtDND *obj = (DtDND *) client_data;
610    obj->DoingDrag = false;
611 }
612
613 void DtDND::StartDrag(XEvent *event)
614 {
615    IconObj *icon = (IconObj *)obj;
616
617    convertCBRec[0].closure = (XtPointer)this;
618    dragFinishCBRec[0].closure = (XtPointer)this;
619    dropOnRootCBRec[0].closure = (XtPointer)this;
620    if ((!STRCMP(name, icon->Name()) || !STRCMP(iconFile, icon->IconFile()) ||
621        icon_size != icon->IconView()) && dragIcon)
622     {
623       XtDestroyWidget(dragIcon);
624       XtDestroyWidget(sourceIcon);
625       dragIcon = NULL;
626       sourceIcon = NULL;
627     }
628    if (!dragIcon)
629       GetDragPixmaps();
630    else if (selected != icon->Selected())
631     {
632       selected = icon->Selected();
633       DrawString();
634     }
635    Arg arg[3];
636    XtSetArg(arg[0], DtNsourceIcon, (XtArgVal)dragIcon);
637    XtSetArg(arg[1], XmNsourceCursorIcon, (XtArgVal)sourceIcon);
638    XtSetArg(arg[2], DtNdropOnRootCallback, dropOnRootCBRec);
639
640    Widget dc = DtDndDragStart(obj->BaseWidget(), event, DtDND_FILENAME_TRANSFER,
641                               1, (unsigned char)(XmDROP_COPY | XmDROP_MOVE),
642                               convertCBRec, dragFinishCBRec, arg,
643                               can_drop_on_root ? 3 : 2);
644    if (dc)
645     {
646       XmDragContext xmDragContext = (XmDragContext) dc;
647       XtVaSetValues((Widget)xmDragContext->drag.curDragOver,
648                     XmNdragOverMode, XmPIXMAP, NULL);
649     }
650    else
651       fprintf(stderr, "DtDndDragStart returned NULL.\n");
652 }
653
654 void DtDND::ConvertCB(Widget /*dragContext*/, XtPointer client_data,
655                       XtPointer call_data)
656 {
657    char *value;
658    DtDndConvertCallbackStruct *convertInfo;
659    int len, i, numFiles;
660    DtDND *obj = (DtDND *) client_data;
661
662    convertInfo = (DtDndConvertCallbackStruct *) call_data;
663    numFiles = convertInfo->dragData->numItems;
664    switch (convertInfo->reason)
665    {
666    case DtCR_DND_CONVERT_DATA:
667       if (obj->dndCB)
668        {
669          for (i = 0; i < numFiles; i++)
670           {
671             value = NULL;
672             (*obj->dndCB)(obj->obj, &value, &len, CONVERT_DATA);
673             if (value && *value)
674                convertInfo->dragData->data.files[i] = value;
675             else
676              {
677                convertInfo->status = DtDND_FAILURE;
678                return;
679              }
680           }
681        }
682       break;
683    case DtCR_DND_CONVERT_DELETE:
684       if (obj->dndCB)
685        {
686          for (i = 0; i < numFiles; i++)
687           {
688             value = convertInfo->dragData->data.files[i];
689             len = strlen(value);
690             (*obj->dndCB)(obj->obj, &value, &len, CONVERT_DELETE);
691           }
692        }
693       break;
694    }
695 }
696
697 void DtDND::DropOnRootCB(Widget /*dragContext*/, XtPointer client_data,
698                          XtPointer call_data)
699 {
700    char *value;
701    int len, x, y, i, numFiles;
702    DtDND *obj = (DtDND *) client_data;
703    DtDndDropCallbackStruct *fileList = (DtDndDropCallbackStruct *)call_data;
704    MotifUI *tmp = (MotifUI *)obj->obj;
705    Atom     pCurrent;
706    char *workspace_name = NULL;
707
708    if (DtWsmGetCurrentWorkspace(tmp->display, tmp->root, &pCurrent) ==
709        Success)
710     {
711       workspace_name = XGetAtomName(tmp->display, pCurrent);
712     }
713
714    numFiles = fileList->dropData->numItems;
715    fileList->completeMove = False;
716    x = fileList->x;
717    y = fileList->y;
718    int max_len = 0;
719    for(i = 0; i < numFiles; i++)
720       if ((len = strlen(fileList->dropData->data.files[i])) > max_len)
721          max_len = len;
722    if (workspace_name)
723       value = new char[max_len + strlen(workspace_name) + 30];
724    else
725       value = new char[max_len + 30];
726    for(i = 0; i < numFiles; i++)
727     {
728       if (workspace_name)
729          sprintf(value, "%d\n%d\n%s \n%s", x, y,
730                  fileList->dropData->data.files[i], workspace_name);
731       else
732          sprintf(value, "%d\n%d\n%s", x, y, fileList->dropData->data.files[i]);
733       len = strlen(value);
734       (*obj->dndCB)(obj->obj, &value, &len, DROP_ON_ROOT);
735       y += 20;
736       x += 20;
737     }
738    delete value;
739 }