2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
23 /* $TOG: DtDND.C /main/7 1998/08/03 08:58:53 mgreess $ */
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. *
37 #include <Xm/DragCP.h>
39 #include <Dt/Action.h>
44 extern XtPointer _XmStringUngenerate (
48 XmTextType output_type);
51 #define DRAG_THRESHOLD 10
53 // Absolute value macro
55 #define ABS(x) (((x) > 0) ? (x) : (-(x)))
58 boolean DtDND::FirstTime = true;
59 XtCallbackRec DtDND::transferCBRec[] =
61 {&DtDND::TransferCB, NULL}, {NULL, NULL}
63 XtCallbackRec DtDND::convertCBRec[] =
65 {&DtDND::ConvertCB, NULL}, {NULL, NULL}
67 XtCallbackRec DtDND::dragFinishCBRec[] =
69 {&DtDND::DragFinishCB, NULL}, {NULL, NULL}
71 XtCallbackRec DtDND::dropOnRootCBRec[] =
73 {&DtDND::DropOnRootCB, NULL}, {NULL, NULL}
75 XtCallbackRec DtDND::animateCBRec[] =
77 {&DtDND::AnimateCB, NULL}, {NULL, NULL}
79 boolean DtDND::DoingDrag = false;
83 DtDND::DtDND(MotifUI *_obj, DNDCallback _dndCB, boolean _can_drop_on_root)
87 MotifUI *tmp = (MotifUI *)_obj;
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);
101 can_drop_on_root = _can_drop_on_root;
107 transferCBRec[0].closure = (XtPointer)this;
108 animateCBRec[0].closure = (XtPointer)this;
109 if (obj->UIClass() == ICON)
112 XtVaSetValues(obj->BaseWidget(), XmNshadowThickness, 2, NULL);
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);
124 // Set up Drag on Button1
125 XtAddEventHandler(obj->BaseWidget(), Button1MotionMask, False,
126 (XtEventHandler)DragMotionHandler, (XtPointer)this);
128 // Set up Drag on Button2 if not using it for BMenu already
129 if (MotifUI::bMenuButton != Button2)
131 XtAddEventHandler(obj->BaseWidget(), Button2MotionMask, False,
132 (XtEventHandler)DragMotionHandler, (XtPointer)this);
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);
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);
160 XmStringFree(string);
163 XtDestroyWidget(sourceIcon);
168 XtDestroyWidget(dragIcon);
173 void DtDND::GetDragPixmaps()
175 IconObj *icon = (IconObj *)obj;
176 Pixmap tmp_pixmap, tmp_mask;
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);
187 name = strdup(icon->Name());
188 icon_size = icon->IconView();
189 selected = icon->Selected();
190 iconFile = new char[strlen(icon->IconFile()) + 6];
192 Dimension height, width;
193 unsigned int w, h, junk;
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);
202 XmStringExtent(fontList, string, &width, &height);
203 if (icon_size == LARGE_ICON)
204 string_border_width = 1;
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;
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)
222 XGetGeometry(icon->display, tmp_pixmap, (Window *) &junk,
223 (int *) &junk, (int *) &junk, &w, &h, &junk, &junk);
231 s_y = (h - height) / 2;
235 p_y = (height - h) / 2;
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)
243 XGetGeometry(icon->display, tmp_pixmap, (Window *) &junk,
244 (int *) &junk, (int *) &junk, &w, &h, &junk, &junk);
255 sprintf(iconFile, "%s.m.pm", icon->IconFile());
256 icon->GetPixmaps(icon->BaseWidget(), iconFile, &tmp_pixmap, &tmp_mask);
262 pixmap = XCreatePixmap(icon->display, icon->root, width, height,
264 if (icon_size != NAME_ONLY &&
265 tmp_pixmap && tmp_pixmap != XmUNSPECIFIED_PIXMAP)
267 mask = XCreatePixmap(icon->display, icon->root, width, height, 1);
269 XSetForeground(icon->display, gc_mask, 0);
270 XFillRectangle(icon->display, mask, gc_mask, 0, 0, width, height);
273 XSetForeground(icon->display, gc_mask, 1);
274 if (icon_size == LARGE_ICON)
277 if (tmp_mask && tmp_mask != XmUNSPECIFIED_PIXMAP)
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);
287 XFillRectangle(icon->display, mask, gc_mask, p_x, p_y, p_w, p_h);
290 XFillRectangle(icon->display, mask, gc_mask, p_x, p_y, p_w - 1,
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);
299 XFillRectangle(icon->display, mask, gc_mask, s_x, s_y, s_w - 1,
302 // If selected use selectColor as background
303 if (showSelectedPixmap && selected)
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);
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);
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,
323 XCopyArea(icon->display, tmp_pixmap, pixmap, gc, 0, 0, p_w - 1, p_h - 1,
325 XSetClipMask(icon->display, gc, None);
326 XSetClipOrigin(icon->display, gc, 0, 0);
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++;
343 XtSetArg(args[n], XmNmask, mask);
347 dragIcon = XmCreateDragIcon(icon->BaseWidget(), "dragIcon", args, n);
350 if (icon_size == LARGE_ICON)
351 sprintf(iconFile, "%s.m.bm", icon->IconFile());
353 sprintf(iconFile, "%s.t.bm", icon->IconFile());
354 icon->GetPixmaps(icon->BaseWidget(), iconFile, &tmp_pixmap);
356 if (!(tmp_pixmap && tmp_pixmap != XmUNSPECIFIED_PIXMAP))
358 static Pixmap l_pixmap = (Pixmap)NULL, s_pixmap = (Pixmap)NULL;
359 if (icon_size == LARGE_ICON)
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);
366 tmp_pixmap = l_pixmap;
370 if (icon_size == NAME_ONLY)
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);
380 tmp_pixmap = s_pixmap;
384 if (icon_size == NAME_ONLY)
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)
404 XtSetArg(args[n], XmNmask, tmp_mask);
408 sourceIcon = XmCreateDragIcon(icon->BaseWidget(), "sourceIcon", args, n);
409 strcpy(iconFile, icon->IconFile());
412 void DtDND::DrawString()
414 IconObj *icon = (IconObj *)obj;
418 XSetForeground(icon->display, gc, selectColor);
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);
426 XFillRectangle(icon->display, pixmap, gc, s_x, s_y, s_w - 1, s_h - 1);
427 // If selected use selectColor as background
429 XSetForeground(icon->display, gc, textSelectColor);
431 XSetForeground(icon->display, gc, fg);
432 XmStringDraw(icon->display, pixmap, fontList, string, gc, s_x, s_y, s_w,
433 alignment, stringDirection, NULL);
436 void DtDND::GetRects()
438 Dimension shadow, highlight, margin;
440 XtVaGetValues(obj->BaseWidget(), XmNhighlightThickness, &highlight,
441 GuiNiconMarginThickness, &margin,
442 GuiNiconShadowThickness, &shadow, NULL);
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);
456 void DtDND::UpdateActivity(boolean flag)
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);
468 XtSetArg(args[n], XmNanimationStyle, XmDRAG_UNDER_HIGHLIGHT);
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++;
477 XmDropSiteUpdate(obj->BaseWidget(), args, n);
479 XmDropSiteConfigureStackingOrder(obj->BaseWidget(), NULL, XmABOVE);
481 XmDropSiteConfigureStackingOrder(obj->BaseWidget(), NULL, XmBELOW);
484 void DtDND::UpdateRects()
489 XtSetArg(args[0], XmNnumDropRectangles, 2);
490 XtSetArg(args[1], XmNdropRectangles, &rects);
491 XmDropSiteUpdate(obj->BaseWidget(), args, 2);
494 void DtDND::AnimateCB(Widget /*widget*/, XtPointer client_data,
497 DtDND *obj = (DtDND *)client_data;
500 DtDndDropAnimateCallbackStruct *animateInfo;
501 animateInfo = (DtDndDropAnimateCallbackStruct *) call_data;
503 numItems = animateInfo->dropData->numItems;
504 //for (i = 0; i < numItems; i++)
506 (*obj->dndCB)(obj->obj, NULL, NULL, ANIMATE);
511 void DtDND::TransferCB(Widget /*widget*/, XtPointer client_data,
514 DtDndTransferCallbackStruct *transferInfo;
515 transferInfo = (DtDndTransferCallbackStruct *) call_data;
517 int len, i, numItems;
519 DtDND *obj = (DtDND *)client_data;
520 numItems = transferInfo->dropData->numItems;
521 switch (transferInfo->dropData->protocol)
523 case DtDND_FILENAME_TRANSFER:
526 for (i = 0; i < numItems; i++)
528 value = transferInfo->dropData->data.files[i];
530 (*obj->dndCB)(obj->obj, &value, &len, FILENAME_TRANSFER);
534 case DtDND_TEXT_TRANSFER:
537 for (i = 0; i < numItems; i++)
539 value = (char *) _XmStringUngenerate(
540 transferInfo->dropData->data.strings[i], NULL,
541 XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
543 (*obj->dndCB)(obj->obj, &value, &len, TEXT_TRANSFER);
549 case DtDND_BUFFER_TRANSFER:
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++)
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;
562 MotifUI *tmp = (MotifUI *)obj->obj;
563 DtActionInvoke(tmp->topLevel, value, aap, numItems, NULL, NULL, NULL,
570 transferInfo->status = DtDND_FAILURE;
575 void DtDND::DragMotionHandler(Widget /*widget*/, XtPointer client_data,
576 XEvent *event, Boolean * /*continued*/)
578 static int initialX = -1;
579 static int initialY = -1;
581 DtDND *obj = (DtDND *)client_data;
586 // If the drag is just starting, set initial button down coords
587 if (initialX == -1 && initialY == -1)
589 initialX = event->xmotion.x;
590 initialY = event->xmotion.y;
592 // Find out how far pointer has moved since button press
593 diffX = initialX - event->xmotion.x;
594 diffY = initialY - event->xmotion.y;
596 if ((ABS(diffX) >= DRAG_THRESHOLD) ||
597 (ABS(diffY) >= DRAG_THRESHOLD))
599 obj->DoingDrag = true;
600 obj->StartDrag(event);
606 void DtDND::DragFinishCB(Widget /*widget*/, XtPointer client_data,
607 XtPointer /*callData*/)
609 DtDND *obj = (DtDND *) client_data;
610 obj->DoingDrag = false;
613 void DtDND::StartDrag(XEvent *event)
615 IconObj *icon = (IconObj *)obj;
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)
623 XtDestroyWidget(dragIcon);
624 XtDestroyWidget(sourceIcon);
630 else if (selected != icon->Selected())
632 selected = icon->Selected();
636 XtSetArg(arg[0], DtNsourceIcon, (XtArgVal)dragIcon);
637 XtSetArg(arg[1], XmNsourceCursorIcon, (XtArgVal)sourceIcon);
638 XtSetArg(arg[2], DtNdropOnRootCallback, dropOnRootCBRec);
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);
646 XmDragContext xmDragContext = (XmDragContext) dc;
647 XtVaSetValues((Widget)xmDragContext->drag.curDragOver,
648 XmNdragOverMode, XmPIXMAP, NULL);
651 fprintf(stderr, "DtDndDragStart returned NULL.\n");
654 void DtDND::ConvertCB(Widget /*dragContext*/, XtPointer client_data,
658 DtDndConvertCallbackStruct *convertInfo;
659 int len, i, numFiles;
660 DtDND *obj = (DtDND *) client_data;
662 convertInfo = (DtDndConvertCallbackStruct *) call_data;
663 numFiles = convertInfo->dragData->numItems;
664 switch (convertInfo->reason)
666 case DtCR_DND_CONVERT_DATA:
669 for (i = 0; i < numFiles; i++)
672 (*obj->dndCB)(obj->obj, &value, &len, CONVERT_DATA);
674 convertInfo->dragData->data.files[i] = value;
677 convertInfo->status = DtDND_FAILURE;
683 case DtCR_DND_CONVERT_DELETE:
686 for (i = 0; i < numFiles; i++)
688 value = convertInfo->dragData->data.files[i];
690 (*obj->dndCB)(obj->obj, &value, &len, CONVERT_DELETE);
697 void DtDND::DropOnRootCB(Widget /*dragContext*/, XtPointer client_data,
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;
706 char *workspace_name = NULL;
708 if (DtWsmGetCurrentWorkspace(tmp->display, tmp->root, &pCurrent) ==
711 workspace_name = XGetAtomName(tmp->display, pCurrent);
714 numFiles = fileList->dropData->numItems;
715 fileList->completeMove = False;
719 for(i = 0; i < numFiles; i++)
720 if ((len = strlen(fileList->dropData->data.files[i])) > max_len)
723 value = new char[max_len + strlen(workspace_name) + 30];
725 value = new char[max_len + 30];
726 for(i = 0; i < numFiles; i++)
729 sprintf(value, "%d\n%d\n%s \n%s", x, y,
730 fileList->dropData->data.files[i], workspace_name);
732 sprintf(value, "%d\n%d\n%s", x, y, fileList->dropData->data.files[i]);
734 (*obj->dndCB)(obj->obj, &value, &len, DROP_ON_ROOT);