/* * CDE - Common Desktop Environment * * Copyright (c) 1993-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these libraries and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* $TOG: DtDND.C /main/7 1998/08/03 08:58:53 mgreess $ */ /* * * (c) Copyright 1993, 1994 Hewlett-Packard Company * * (c) Copyright 1993, 1994 International Business Machines Corp. * * (c) Copyright 1993, 1994 Sun Microsystems, Inc. * * (c) Copyright 1993, 1994 Novell, Inc. * */ #include "stdlib.h" #include "DtDND.h" #include "IconObj.h" #include "Icon.h" #include "Dt/Dnd.h" #include #include
#include
#include extern "C" { extern XtPointer _XmStringUngenerate ( XmString string, XmStringTag tag, XmTextType tag_type, XmTextType output_type); } #define DRAG_THRESHOLD 10 // Absolute value macro #ifndef ABS #define ABS(x) (((x) > 0) ? (x) : (-(x))) #endif boolean DtDND::FirstTime = true; XtCallbackRec DtDND::transferCBRec[] = { {&DtDND::TransferCB, NULL}, {NULL, NULL} }; XtCallbackRec DtDND::convertCBRec[] = { {&DtDND::ConvertCB, NULL}, {NULL, NULL} }; XtCallbackRec DtDND::dragFinishCBRec[] = { {&DtDND::DragFinishCB, NULL}, {NULL, NULL} }; XtCallbackRec DtDND::dropOnRootCBRec[] = { {&DtDND::DropOnRootCB, NULL}, {NULL, NULL} }; XtCallbackRec DtDND::animateCBRec[] = { {&DtDND::AnimateCB, NULL}, {NULL, NULL} }; boolean DtDND::DoingDrag = false; GC DtDND::gc; GC DtDND::gc_mask; DtDND::DtDND(MotifUI *_obj, DNDCallback _dndCB, boolean _can_drop_on_root) { if (FirstTime) { MotifUI *tmp = (MotifUI *)_obj; Pixmap tmp_pixmap; BaseUI *parent = _obj; while (parent->Parent()) parent = parent->Parent(); tmp_pixmap = XCreatePixmap(tmp->display, tmp->root, 1, 1, tmp->depth); gc = XCreateGC(tmp->display, tmp_pixmap, 0, NULL); tmp_pixmap = XCreatePixmap(tmp->display, tmp->root, 1, 1, 1); gc_mask = XCreateGC(tmp->display, tmp_pixmap, 0, NULL); if (tmp->font) { XSetFont(tmp->display, gc, tmp->font); } FirstTime = false; } obj = _obj; can_drop_on_root = _can_drop_on_root; dndCB = _dndCB; dragIcon = NULL; sourceIcon = NULL; // Set up Drop transferCBRec[0].closure = (XtPointer)this; animateCBRec[0].closure = (XtPointer)this; if (obj->UIClass() == ICON) { GetRects(); XtVaSetValues(obj->BaseWidget(), XmNshadowThickness, 2, NULL); Arg args[6]; XtSetArg(args[0], XmNdropSiteType, XmDROP_SITE_SIMPLE); XtSetArg(args[1], XmNanimationStyle, XmDRAG_UNDER_SHADOW_IN); XtSetArg(args[2], XmNnumDropRectangles, 2); XtSetArg(args[3], XmNdropRectangles, &rects); XtSetArg(args[4], DtNdropAnimateCallback, animateCBRec); XtSetArg(args[5], DtNtextIsBuffer, True); DtDndDropRegister(obj->BaseWidget(), DtDND_FILENAME_TRANSFER| DtDND_BUFFER_TRANSFER, (unsigned char)XmDROP_COPY, transferCBRec, args, 6); // Set up Drag on Button1 XtAddEventHandler(obj->BaseWidget(), Button1MotionMask, False, (XtEventHandler)DragMotionHandler, (XtPointer)this); // Set up Drag on Button2 if not using it for BMenu already if (MotifUI::bMenuButton != Button2) { XtAddEventHandler(obj->BaseWidget(), Button2MotionMask, False, (XtEventHandler)DragMotionHandler, (XtPointer)this); } } else { Arg args[2]; XtSetArg(args[0], DtNdropAnimateCallback, animateCBRec); XtSetArg(args[1], DtNtextIsBuffer, True); DtDndDropRegister(obj->BaseWidget(), DtDND_FILENAME_TRANSFER| DtDND_BUFFER_TRANSFER, (unsigned char)XmDROP_COPY, transferCBRec, args, 2); } pixmap = 0L; mask = 0L; name = NULL; iconFile = NULL; string = NULL; } DtDND::~DtDND() { MotifUI *icon = (MotifUI *)obj; if (pixmap && pixmap != XmUNSPECIFIED_PIXMAP) XFreePixmap(icon->display, pixmap); if (mask && mask != XmUNSPECIFIED_PIXMAP) XFreePixmap(icon->display, mask); free(name); delete iconFile; XmStringFree(string); if (sourceIcon) { XtDestroyWidget(sourceIcon); sourceIcon = NULL; } if (dragIcon) { XtDestroyWidget(dragIcon); dragIcon = NULL; } } void DtDND::GetDragPixmaps() { IconObj *icon = (IconObj *)obj; Pixmap tmp_pixmap, tmp_mask; delete iconFile; free(name); XmStringFree(string); if (pixmap && pixmap != XmUNSPECIFIED_PIXMAP) XFreePixmap(icon->display, pixmap); if (mask && mask != XmUNSPECIFIED_PIXMAP) XFreePixmap(icon->display, mask); mask = 0L; pixmap = 0L; name = strdup(icon->Name()); icon_size = icon->IconView(); selected = icon->Selected(); iconFile = new char[strlen(icon->IconFile()) + 6]; Dimension height, width; unsigned int w, h, junk; Window junkwin; XtVaGetValues(icon->BaseWidget(), XmNbackground, &bg, XmNforeground, &fg, GuiNselectColor, &selectColor, XmNalignment, &alignment, GuiNshowSelectedPixmap, &showSelectedPixmap, XmNstringDirection, &stringDirection, GuiNtextSelectColor, &textSelectColor, XmNlabelString, &string, XmNfontList, &fontList, NULL); XmStringExtent(fontList, string, &width, &height); if (icon_size == LARGE_ICON) string_border_width = 1; else string_border_width = 0; height += 2 * string_border_width; width += 2 * string_border_width; s_x = s_y = string_border_width; p_x = p_y = 0; s_w = width; s_h = height; p_w = p_h = 0; switch (icon_size) { case DETAILS: case SMALL_ICON: sprintf(iconFile, "%s.t.pm", icon->IconFile()); icon->GetPixmaps(icon->BaseWidget(), iconFile, &tmp_pixmap, &tmp_mask); if (tmp_pixmap && tmp_pixmap != XmUNSPECIFIED_PIXMAP) { XGetGeometry(icon->display, tmp_pixmap, &junkwin, (int *) &junk, (int *) &junk, &w, &h, &junk, &junk); p_w = w; p_h = h; w += 2; s_x += w; width += w; if (h > height) { s_y = (h - height) / 2; height = h; } else p_y = (height - h) / 2; } break; case LARGE_ICON: sprintf(iconFile, "%s.m.pm", icon->IconFile()); icon->GetPixmaps(icon->BaseWidget(), iconFile, &tmp_pixmap, &tmp_mask); if (tmp_pixmap && tmp_pixmap != XmUNSPECIFIED_PIXMAP) { XGetGeometry(icon->display, tmp_pixmap, (Window *) &junk, (int *) &junk, (int *) &junk, &w, &h, &junk, &junk); p_w = w; p_h = h; h += 2; s_y += h; height += h; if (w > width) width = w; } break; default: sprintf(iconFile, "%s.m.pm", icon->IconFile()); icon->GetPixmaps(icon->BaseWidget(), iconFile, &tmp_pixmap, &tmp_mask); break; } // Create pixmap pixmap = XCreatePixmap(icon->display, icon->root, width, height, icon->depth); if (icon_size != NAME_ONLY && tmp_pixmap && tmp_pixmap != XmUNSPECIFIED_PIXMAP) { mask = XCreatePixmap(icon->display, icon->root, width, height, 1); // Clear mask XSetForeground(icon->display, gc_mask, 0); XFillRectangle(icon->display, mask, gc_mask, 0, 0, width, height); // Set Mask Bits XSetForeground(icon->display, gc_mask, 1); if (icon_size == LARGE_ICON) { #ifndef hpux if (tmp_mask && tmp_mask != XmUNSPECIFIED_PIXMAP) { XSetClipOrigin(icon->display, gc_mask, p_x, p_y); XSetClipMask(icon->display, gc_mask, tmp_mask); XFillRectangle(icon->display, mask, gc_mask, p_x, p_y, p_w, p_h); XSetClipMask(icon->display, gc_mask, None); XSetClipOrigin(icon->display, gc_mask, 0, 0); } else #endif XFillRectangle(icon->display, mask, gc_mask, p_x, p_y, p_w, p_h); } else XFillRectangle(icon->display, mask, gc_mask, p_x, p_y, p_w - 1, p_h - 1); if (icon_size == LARGE_ICON) XFillRectangle(icon->display, mask, gc_mask, s_x - string_border_width, s_y - string_border_width, s_w + 2 * string_border_width, s_h + 2 * string_border_width); else XFillRectangle(icon->display, mask, gc_mask, s_x, s_y, s_w - 1, s_h - 1); } // If selected use selectColor as background if (showSelectedPixmap && selected) bg = selectColor; // Copy Pixmap to new pixmap XSetClipMask(icon->display, gc, None); XSetFillStyle(icon->display, gc, FillSolid); XSetForeground(icon->display, gc, bg); if (icon_size == LARGE_ICON) XFillRectangle(icon->display, pixmap, gc, p_x, p_y, p_w, p_h); else XFillRectangle(icon->display, pixmap, gc, p_x, p_y, p_w - 1, p_h - 1); XSetClipOrigin(icon->display, gc, p_x, p_y); if (tmp_mask && tmp_mask != XmUNSPECIFIED_PIXMAP) XSetClipMask(icon->display, gc, tmp_mask); else XSetClipMask(icon->display, gc, None); if (icon_size == LARGE_ICON) XCopyArea(icon->display, tmp_pixmap, pixmap, gc, 0, 0, p_w, p_h, p_x, p_y); else XCopyArea(icon->display, tmp_pixmap, pixmap, gc, 0, 0, p_w - 1, p_h - 1, p_x, p_y); XSetClipMask(icon->display, gc, None); XSetClipOrigin(icon->display, gc, 0, 0); DrawString(); Arg args[11]; int n = 0; w = width; h = height; XtSetArg(args[n], XmNwidth, w); n++; XtSetArg(args[n], XmNheight, h); n++; XtSetArg(args[n], XmNmaxWidth, w); n++; XtSetArg(args[n], XmNmaxHeight, h); n++; XtSetArg(args[n], XmNdepth, icon->depth); n++; XtSetArg(args[n], XmNforeground, bg); n++; XtSetArg(args[n], XmNbackground, fg); n++; XtSetArg(args[n], XmNpixmap, pixmap); n++; if (mask) { XtSetArg(args[n], XmNmask, mask); n++; } dragIcon = XmCreateDragIcon(icon->BaseWidget(), "dragIcon", args, n); n = 0; if (icon_size == LARGE_ICON) sprintf(iconFile, "%s.m.bm", icon->IconFile()); else sprintf(iconFile, "%s.t.bm", icon->IconFile()); icon->GetPixmaps(icon->BaseWidget(), iconFile, &tmp_pixmap); if (!(tmp_pixmap && tmp_pixmap != XmUNSPECIFIED_PIXMAP)) { static Pixmap l_pixmap = (Pixmap)NULL, s_pixmap = (Pixmap)NULL; if (icon_size == LARGE_ICON) { if (!l_pixmap) { l_pixmap = XCreatePixmap(icon->display, icon->root, p_w, p_h, 1); XFillRectangle(icon->display, l_pixmap, gc_mask, 0, 0, p_w, p_h); } tmp_pixmap = l_pixmap; } else { if (icon_size == NAME_ONLY) { p_w = 16; p_h = 16; } if (!s_pixmap) { s_pixmap = XCreatePixmap(icon->display, icon->root, p_w, p_h, 1); XFillRectangle(icon->display, s_pixmap, gc_mask, 0, 0, p_w, p_h); } tmp_pixmap = s_pixmap; } } if (icon_size == NAME_ONLY) { w = 16; h = 16; } else { w = p_w; h = p_h; } XtSetArg(args[n], XmNwidth, w); n++; XtSetArg(args[n], XmNheight, h); n++; XtSetArg(args[n], XmNmaxWidth, w); n++; XtSetArg(args[n], XmNmaxHeight, h); n++; XtSetArg(args[n], XmNdepth, 1); n++; XtSetArg(args[n], XmNforeground, icon->black); n++; XtSetArg(args[n], XmNbackground, icon->white); n++; XtSetArg(args[n], XmNpixmap, tmp_pixmap); n++; if (tmp_mask && tmp_mask != XmUNSPECIFIED_PIXMAP) { XtSetArg(args[n], XmNmask, tmp_mask); n++; } sourceIcon = XmCreateDragIcon(icon->BaseWidget(), "sourceIcon", args, n); strcpy(iconFile, icon->IconFile()); } void DtDND::DrawString() { IconObj *icon = (IconObj *)obj; // Draw String if (selected) XSetForeground(icon->display, gc, selectColor); else XSetForeground(icon->display, gc, bg); if (icon_size == LARGE_ICON) XFillRectangle(icon->display, pixmap, gc, s_x - string_border_width, s_y - string_border_width, s_w + 2 * string_border_width, s_h + 2 * string_border_width); else XFillRectangle(icon->display, pixmap, gc, s_x, s_y, s_w - 1, s_h - 1); // If selected use selectColor as background if (selected) XSetForeground(icon->display, gc, textSelectColor); else XSetForeground(icon->display, gc, fg); XmStringDraw(icon->display, pixmap, fontList, string, gc, s_x, s_y, s_w, alignment, stringDirection, NULL); } void DtDND::GetRects() { Dimension shadow, highlight, margin; XtVaGetValues(obj->BaseWidget(), XmNhighlightThickness, &highlight, GuiNiconMarginThickness, &margin, GuiNiconShadowThickness, &shadow, NULL); margin += (shadow + highlight); GuiIconGetRects(obj->BaseWidget(), &rects[0], &rects[1]); rects[0].x -= margin; rects[0].y -= margin; rects[0].width += (2 * margin); rects[0].height += (2 * margin); rects[1].x -= margin; rects[1].y -= margin; rects[1].width += (2 * margin); rects[1].height += (2 * margin); } void DtDND::UpdateActivity(boolean flag) { Arg args[3]; int n = 0; if (flag) { XtSetArg(args[n], XmNdropSiteOperations, XmDROP_COPY | XmDROP_MOVE); n++; XtSetArg(args[n], XmNdropSiteActivity, XmDROP_SITE_ACTIVE); n++; if (obj->UIClass() == ICON) XtSetArg(args[n], XmNanimationStyle, XmDRAG_UNDER_SHADOW_IN); else XtSetArg(args[n], XmNanimationStyle, XmDRAG_UNDER_HIGHLIGHT); n++; } else { XtSetArg(args[n], XmNdropSiteOperations, XmDROP_NOOP); n++; XtSetArg(args[n], XmNdropSiteActivity, XmDROP_SITE_INACTIVE); n++; XtSetArg(args[n], XmNanimationStyle, XmDRAG_UNDER_NONE); n++; } XmDropSiteUpdate(obj->BaseWidget(), args, n); if (flag) XmDropSiteConfigureStackingOrder(obj->BaseWidget(), NULL, XmABOVE); else XmDropSiteConfigureStackingOrder(obj->BaseWidget(), NULL, XmBELOW); } void DtDND::UpdateRects() { Arg args[2]; GetRects(); XtSetArg(args[0], XmNnumDropRectangles, 2); XtSetArg(args[1], XmNdropRectangles, &rects); XmDropSiteUpdate(obj->BaseWidget(), args, 2); } void DtDND::AnimateCB(Widget /*widget*/, XtPointer client_data, XtPointer call_data) { DtDND *obj = (DtDND *)client_data; if (obj->dndCB) { DtDndDropAnimateCallbackStruct *animateInfo; animateInfo = (DtDndDropAnimateCallbackStruct *) call_data; int i = 0, numItems; numItems = animateInfo->dropData->numItems; //for (i = 0; i < numItems; i++) { (*obj->dndCB)(obj->obj, NULL, NULL, ANIMATE); } } } void DtDND::TransferCB(Widget /*widget*/, XtPointer client_data, XtPointer call_data) { DtDndTransferCallbackStruct *transferInfo; transferInfo = (DtDndTransferCallbackStruct *) call_data; char *value; int len, i, numItems; DtDND *obj = (DtDND *)client_data; numItems = transferInfo->dropData->numItems; switch (transferInfo->dropData->protocol) { case DtDND_FILENAME_TRANSFER: if (obj->dndCB) { for (i = 0; i < numItems; i++) { value = transferInfo->dropData->data.files[i]; len = strlen(value); (*obj->dndCB)(obj->obj, &value, &len, FILENAME_TRANSFER); } } break; case DtDND_TEXT_TRANSFER: if (obj->dndCB) { for (i = 0; i < numItems; i++) { value = (char *) _XmStringUngenerate( transferInfo->dropData->data.strings[i], NULL, XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT); len = strlen(value); (*obj->dndCB)(obj->obj, &value, &len, TEXT_TRANSFER); if (NULL != value) XtFree(value); } } break; case DtDND_BUFFER_TRANSFER: if (obj->dndCB) { (*obj->dndCB)(obj->obj, &value, &len, BUFFER_TRANSFER); DtActionArg *aap = new DtActionArg[numItems]; memset(aap, 0, numItems * sizeof(DtActionArg)); for (i = 0; i < numItems; i++) { aap[i].argClass = DtACTION_BUFFER; aap[i].u.buffer.bp = transferInfo->dropData->data.buffers[i].bp; aap[i].u.buffer.size = transferInfo->dropData->data.buffers[i].size; aap[i].u.buffer.name = transferInfo->dropData->data.buffers[i].name; } MotifUI *tmp = (MotifUI *)obj->obj; DtActionInvoke(tmp->topLevel, value, aap, numItems, NULL, NULL, NULL, 1, NULL, NULL); delete aap; delete value; } break; default: transferInfo->status = DtDND_FAILURE; break; } } void DtDND::DragMotionHandler(Widget /*widget*/, XtPointer client_data, XEvent *event, Boolean * /*continued*/) { static int initialX = -1; static int initialY = -1; int diffX, diffY; DtDND *obj = (DtDND *)client_data; if (obj->DoingDrag) return; // If the drag is just starting, set initial button down coords if (initialX == -1 && initialY == -1) { initialX = event->xmotion.x; initialY = event->xmotion.y; } // Find out how far pointer has moved since button press diffX = initialX - event->xmotion.x; diffY = initialY - event->xmotion.y; if ((ABS(diffX) >= DRAG_THRESHOLD) || (ABS(diffY) >= DRAG_THRESHOLD)) { obj->DoingDrag = true; obj->StartDrag(event); initialX = -1; initialY = -1; } } void DtDND::DragFinishCB(Widget /*widget*/, XtPointer client_data, XtPointer /*callData*/) { DtDND *obj = (DtDND *) client_data; obj->DoingDrag = false; } void DtDND::StartDrag(XEvent *event) { IconObj *icon = (IconObj *)obj; convertCBRec[0].closure = (XtPointer)this; dragFinishCBRec[0].closure = (XtPointer)this; dropOnRootCBRec[0].closure = (XtPointer)this; if ((!STRCMP(name, icon->Name()) || !STRCMP(iconFile, icon->IconFile()) || icon_size != icon->IconView()) && dragIcon) { XtDestroyWidget(dragIcon); XtDestroyWidget(sourceIcon); dragIcon = NULL; sourceIcon = NULL; } if (!dragIcon) GetDragPixmaps(); else if (selected != icon->Selected()) { selected = icon->Selected(); DrawString(); } Arg arg[3]; XtSetArg(arg[0], DtNsourceIcon, (XtArgVal)dragIcon); XtSetArg(arg[1], XmNsourceCursorIcon, (XtArgVal)sourceIcon); XtSetArg(arg[2], DtNdropOnRootCallback, dropOnRootCBRec); Widget dc = DtDndDragStart(obj->BaseWidget(), event, DtDND_FILENAME_TRANSFER, 1, (unsigned char)(XmDROP_COPY | XmDROP_MOVE), convertCBRec, dragFinishCBRec, arg, can_drop_on_root ? 3 : 2); if (dc) { XmDragContext xmDragContext = (XmDragContext) dc; XtVaSetValues((Widget)xmDragContext->drag.curDragOver, XmNdragOverMode, XmPIXMAP, NULL); } else fprintf(stderr, "DtDndDragStart returned NULL.\n"); } void DtDND::ConvertCB(Widget /*dragContext*/, XtPointer client_data, XtPointer call_data) { char *value; DtDndConvertCallbackStruct *convertInfo; int len, i, numFiles; DtDND *obj = (DtDND *) client_data; convertInfo = (DtDndConvertCallbackStruct *) call_data; numFiles = convertInfo->dragData->numItems; switch (convertInfo->reason) { case DtCR_DND_CONVERT_DATA: if (obj->dndCB) { for (i = 0; i < numFiles; i++) { value = NULL; (*obj->dndCB)(obj->obj, &value, &len, CONVERT_DATA); if (value && *value) convertInfo->dragData->data.files[i] = value; else { convertInfo->status = DtDND_FAILURE; return; } } } break; case DtCR_DND_CONVERT_DELETE: if (obj->dndCB) { for (i = 0; i < numFiles; i++) { value = convertInfo->dragData->data.files[i]; len = strlen(value); (*obj->dndCB)(obj->obj, &value, &len, CONVERT_DELETE); } } break; } } void DtDND::DropOnRootCB(Widget /*dragContext*/, XtPointer client_data, XtPointer call_data) { char *value; int len, x, y, i, numFiles; DtDND *obj = (DtDND *) client_data; DtDndDropCallbackStruct *fileList = (DtDndDropCallbackStruct *)call_data; MotifUI *tmp = (MotifUI *)obj->obj; Atom pCurrent; char *workspace_name = NULL; if (DtWsmGetCurrentWorkspace(tmp->display, tmp->root, &pCurrent) == Success) { workspace_name = XGetAtomName(tmp->display, pCurrent); } numFiles = fileList->dropData->numItems; fileList->completeMove = False; x = fileList->x; y = fileList->y; int max_len = 0; for(i = 0; i < numFiles; i++) if ((len = strlen(fileList->dropData->data.files[i])) > max_len) max_len = len; if (workspace_name) value = new char[max_len + strlen(workspace_name) + 30]; else value = new char[max_len + 30]; for(i = 0; i < numFiles; i++) { if (workspace_name) sprintf(value, "%d\n%d\n%s \n%s", x, y, fileList->dropData->data.files[i], workspace_name); else sprintf(value, "%d\n%d\n%s", x, y, fileList->dropData->data.files[i]); len = strlen(value); (*obj->dndCB)(obj->obj, &value, &len, DROP_ON_ROOT); y += 20; x += 20; } delete value; }