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 /* $XConsortium: DndBuff.c /main/5 1996/06/21 17:30:55 ageorge $ */
24 /*********************************************************************
28 * Description: Implementation of the Buffer Transfer routines
29 * FOR the DND Convenience API.
31 *********************************************************************
34 * RESTRICTED CONFIDENTIAL INFORMATION:
36 * The information in this document is subject to special
37 * restrictions in a confidential disclosure agreement bertween
38 * HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
39 * document outside HP, IBM, Sun, USL, SCO, or Univel wihtout
40 * Sun's specific written approval. This documment and all copies
41 * and derivative works thereof must be returned or destroyed at
44 * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
46 * (c) Copyright 1993, 1994 Hewlett-Packard Company
47 * (c) Copyright 1993, 1994 International Business Machines Corp.
48 * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
49 * (c) Copyright 1993, 1994 Novell, Inc.
54 #include <X11/Intrinsic.h>
55 #include <Xm/AtomMgr.h>
57 #include <Xm/DropSMgr.h>
58 #include <Xm/DropTrans.h>
61 #include "DtSvcLock.h"
64 * Buffer Transfer Protocol Function Prototypes
67 static void dndBuffGetTargets(Boolean, Boolean, Atom**, Cardinal*);
68 static void dndBuffGetAvailTargets(DtDragInfo*, Atom**, Cardinal*);
69 static void dndBuffGetExportTargets(DtDragInfo*, Atom**, Cardinal*);
70 static void dndBuffGetImportTargets(DtDropInfo*, Atom**, Cardinal*);
71 static void dndBuffConvertInit(DtDragInfo*);
72 static Boolean dndBuffConvert(Widget, DtDragInfo*, Atom*, Atom*,
73 Atom*, XtPointer*, unsigned long*, int*,
74 XSelectionRequestEvent*);
75 static void dndBuffConvertFinish(DtDragInfo*);
76 static void dndBuffTransferTargets(DtDropInfo*,
77 Atom*, Cardinal, Atom**, Cardinal*);
78 static void dndBuffTransfer(Widget, DtDropInfo*, Atom*, Atom*, Atom*,
79 XtPointer, unsigned long*, int*);
80 static void dndBuffTransferFinish(DtDropInfo*);
83 * Buffer Transfer Support Functions
86 static void dndBufferDataToSelectionValue(DtDndBuffer *, Cardinal,
87 XtPointer *, unsigned long *, Boolean);
88 static void dndBufferLengthsToSelectionValue(DtDndBuffer *, Cardinal,
89 XtPointer *, unsigned long *);
90 static void dndBufferNamesToSelectionValue(DtDndBuffer *, Cardinal,
91 XtPointer *, unsigned long *);
92 static void dndTextSelectionValueToBuffer(Display *,
93 Atom *, XtPointer, unsigned long *, int *, String,
94 XtPointer *, unsigned long *,
95 DtDndBuffer **, Cardinal *);
96 static void dndSelectionValueToBuffer(XtPointer, unsigned long,
97 XtPointer, unsigned long, XtPointer, unsigned long,
98 DtDndBuffer **, Cardinal *);
101 * Buffer Transfer Selection Targets
104 static Atom XA_DT_BUFFER_DATA;
105 static Atom XA_DT_BUFFER_LENGTHS;
106 static Atom XA_DT_BUFFER_NAMES;
109 * Buffer Transfer Protocol Methods
112 static DtDndMethods dndBuffTransferProtocol = {
113 "DtDndBufferTransfer", /* name */
114 (DtDndProtocol)DtDND_BUFFER_TRANSFER, /* protocol */
115 DtDND_DRAG_SOURCE_DATA, /* sourceType */
116 dndBuffGetAvailTargets, /* getAvailTargets */
117 dndBuffGetExportTargets, /* getExportTargets */
118 dndBuffGetImportTargets, /* getImportTargets */
119 dndBuffConvertInit, /* convertInit */
120 dndBuffConvert, /* convert */
121 dndBuffConvertFinish, /* convertFinish */
122 dndBuffTransferTargets, /* transferTargets */
123 dndBuffTransfer, /* transfer */
124 dndBuffTransferFinish, /* transferFinish */
127 typedef struct _TransferState {
129 unsigned long dataLength;
130 XtPointer lengthsValue;
131 unsigned long lengthsLength;
132 XtPointer namesValue;
133 unsigned long namesLength;
139 * Buffer transfer protocol initialization
142 _DtDndBuffTransferProtocolInitialize(
146 if (XA_DT_BUFFER_DATA == 0) {
147 XA_DT_BUFFER_DATA = DtGetAtom(dpy,"_DT_BUFFER_DATA");
148 XA_DT_BUFFER_LENGTHS = DtGetAtom(dpy,"_DT_BUFFER_LENGTHS");
149 XA_DT_BUFFER_NAMES = DtGetAtom(dpy,"_DT_BUFFER_NAMES");
151 _DtSvcProcessUnlock();
152 return &dndBuffTransferProtocol;
156 * Returns export/import targets for buffer transfers
163 Cardinal * numTargets)
167 *numTargets = 3 + (includeText ? 2 : 0) + (owCompat ? 1 : 0);
169 *targets = (Atom *)XtMalloc(*numTargets * sizeof(Atom));
171 (*targets)[ii++] = XA_DT_BUFFER_DATA;
172 (*targets)[ii++] = XA_DT_BUFFER_LENGTHS;
173 (*targets)[ii++] = XA_DT_BUFFER_NAMES;
176 (*targets)[ii++] = XA_TEXT;
177 (*targets)[ii++] = XA_STRING;
181 (*targets)[ii++] = XA_SUN_DATA_LABEL;
186 * Returns available targets for buffer transfers
189 dndBuffGetAvailTargets(
190 DtDragInfo * dtDragInfo,
191 Atom ** availTargets,
192 Cardinal * numAvailTargets)
194 dndBuffGetTargets(True, True, availTargets, numAvailTargets);
198 * Returns export targets for buffer transfers
201 dndBuffGetExportTargets(
202 DtDragInfo * dtDragInfo,
203 Atom ** exportTargets,
204 Cardinal * numExportTargets)
206 dndBuffGetTargets(dtDragInfo->bufferIsText, True,
207 exportTargets, numExportTargets);
211 * Returns import targets for buffer transfers
214 dndBuffGetImportTargets(
215 DtDropInfo * dtDropInfo,
216 Atom ** importTargets,
217 Cardinal * numImportTargets)
219 dndBuffGetTargets(dtDropInfo->textIsBuffer, True,
220 importTargets, numImportTargets);
224 * Initialize protocol specific part of drag data
228 DtDragInfo * dtDragInfo)
230 DtDndContext * dragData = dtDragInfo->dragData;
232 dragData->data.buffers = (DtDndBuffer *)
233 XtCalloc(dragData->numItems, sizeof(DtDndBuffer));
237 * Convert the buffers into selection data
242 DtDragInfo * dtDragInfo,
246 XtPointer * returnValue,
247 unsigned long * returnLength,
249 XSelectionRequestEvent * selectionRequestEvent)
251 DtDndContext * dragData = dtDragInfo->dragData;
255 * Convert the buffer data to a text selection
257 if (*target == XA_TEXT || *target == XA_STRING) {
258 *returnType = XA_STRING;
260 dndBufferDataToSelectionValue(
261 dragData->data.buffers, dragData->numItems,
262 returnValue, returnLength, True);
265 * Convert the first buffer name to a selection
267 } else if (*target == XA_SUN_DATA_LABEL) {
268 *returnType = XA_STRING;
270 *returnValue = XtNewString(dragData->data.buffers[0].name);
271 *returnLength = strlen(*returnValue)+1;
274 * Convert the buffer data to a selection
276 } else if (*target == XA_DT_BUFFER_DATA) {
277 *returnType = XA_DT_BUFFER_DATA;
279 dndBufferDataToSelectionValue(
280 dragData->data.buffers, dragData->numItems,
281 returnValue, returnLength, False);
284 * Convert the buffer lengths to a selection
286 } else if (*target == XA_DT_BUFFER_LENGTHS) {
287 *returnType = XA_INTEGER;
289 dndBufferLengthsToSelectionValue(
290 dragData->data.buffers, dragData->numItems,
291 returnValue, returnLength);
294 * Convert the buffer names to a selection
296 } else if (*target == XA_DT_BUFFER_NAMES) {
297 *returnType = XA_STRING;
299 dndBufferNamesToSelectionValue(
300 dragData->data.buffers, dragData->numItems,
301 returnValue, returnLength);
310 * Clean up from the convert init proc
313 dndBuffConvertFinish(
314 DtDragInfo * dtDragInfo)
316 DtDndContext * dragData = dtDragInfo->dragData;
318 if (dragData->data.buffers) {
319 XtFree((char *)dragData->data.buffers);
320 dragData->data.buffers = NULL;
325 * Returns the transfer targets selected from the export targets
326 * Prefer buffers over TEXT/STRING
329 dndBuffTransferTargets(
330 DtDropInfo * dtDropInfo,
331 Atom * exportTargets,
332 Cardinal numExportTargets,
333 Atom ** transferTargets,
334 Cardinal * numTransferTargets)
336 Boolean foundData, foundLengths, foundNames,
337 foundDataLabel, foundText, foundString;
339 TransferState * xferState;
341 xferState = (TransferState *)XtCalloc(1,sizeof(TransferState));
342 dtDropInfo->transferInfo->clientData = (XtPointer)xferState;
345 foundData = foundLengths = foundNames = False;
346 foundDataLabel = foundText = foundString = False;
348 for (ii = 0; ii < numExportTargets; ii++) {
349 if (exportTargets[ii] == XA_DT_BUFFER_DATA) {
351 } else if (exportTargets[ii] == XA_DT_BUFFER_LENGTHS) {
353 } else if (exportTargets[ii] == XA_DT_BUFFER_NAMES) {
355 } else if (exportTargets[ii] == XA_SUN_DATA_LABEL) {
356 foundDataLabel = True;
357 } else if (exportTargets[ii] == XA_TEXT) {
359 } else if (exportTargets[ii] == XA_STRING) {
364 *numTransferTargets = 2; /* max number of transfer targets */
366 *transferTargets = (Atom *)XtMalloc(*numTransferTargets * sizeof(Atom));
370 if (foundData && foundLengths && foundNames) {
371 *numTransferTargets = 2;
372 (*transferTargets)[ii++] = XA_DT_BUFFER_NAMES;
373 (*transferTargets)[ii++] = XA_DT_BUFFER_LENGTHS;
374 } else if (foundDataLabel && (foundText || foundString)) {
375 *numTransferTargets = 2;
376 (*transferTargets)[ii++] = XA_SUN_DATA_LABEL;
377 (*transferTargets)[ii++] = foundText ? XA_TEXT : XA_STRING;
378 xferState->textTarget = foundText ? XA_TEXT : XA_STRING;
379 } else if (foundText || foundString) {
380 *numTransferTargets = 1;
381 (*transferTargets)[ii++] = foundText ? XA_TEXT : XA_STRING;
383 *numTransferTargets = 0;
384 *transferTargets = NULL;
390 * Transfer the selection data into buffers
395 DtDropInfo * dtDropInfo,
400 unsigned long * length,
403 Display * display = XtDisplayOfObject(dropTransfer);
404 DtDndContext * dropData = dtDropInfo->dropData;
405 TransferState * xferState =
406 (TransferState *)dtDropInfo->transferInfo->clientData;
409 * Ignore if we've already transferred
411 if (dropData->data.buffers) {
419 * Convert the text selection into buffers
421 if (*target == XA_TEXT || *target == XA_STRING) {
423 dndTextSelectionValueToBuffer(display,
424 type, value, length, format, xferState->dataLabel,
425 &(xferState->dataValue), &(xferState->dataLength),
426 &(dropData->data.buffers), &(dropData->numItems));
431 * Save the buffer name selection for later conversion
432 * Request the text data transfer
434 } else if (*target == XA_SUN_DATA_LABEL &&
435 *type == XA_STRING &&
438 xferState->dataLabel = (String)value;
440 _DtDndTransferAdd(dropTransfer, dtDropInfo,
441 &(xferState->textTarget), 1);
445 * Save the buffer data selection for later conversion
447 } else if (*target == XA_DT_BUFFER_DATA &&
448 *type == XA_DT_BUFFER_DATA &&
451 xferState->dataValue = value;
452 xferState->dataLength = *length;
454 dndSelectionValueToBuffer(
455 xferState->dataValue, xferState->dataLength,
456 xferState->lengthsValue, xferState->lengthsLength,
457 xferState->namesValue, xferState->namesLength,
458 &(dropData->data.buffers), &(dropData->numItems));
464 * Save the buffer lengths selection for later conversion
465 * Request the buffer data transfer
467 } else if (*target == XA_DT_BUFFER_LENGTHS &&
468 *type == XA_INTEGER &&
471 xferState->lengthsValue = value;
472 xferState->lengthsLength = *length;
474 _DtDndTransferAdd(dropTransfer, dtDropInfo,
475 &XA_DT_BUFFER_DATA, 1);
479 * Save the buffer names selection for later conversion
481 } else if (*target == XA_DT_BUFFER_NAMES &&
482 *type == XA_STRING &&
485 xferState->namesValue = value;
486 xferState->namesLength = *length;
489 * Ignore transfers we don't understand
498 * Clean up from the transfer proc
501 dndBuffTransferFinish(
502 DtDropInfo * dtDropInfo)
504 DtDndContext * dropData = dtDropInfo->dropData;
505 TransferState * xferState =
506 (TransferState *)dtDropInfo->transferInfo->clientData;
508 dtDropInfo->transferInfo->clientData = NULL;
510 if (xferState->dataValue)
511 XtFree(xferState->dataValue);
512 if (xferState->lengthsValue)
513 XtFree(xferState->lengthsValue);
514 if (xferState->namesValue)
515 XtFree(xferState->namesValue);
516 if (xferState->dataLabel)
517 XtFree(xferState->dataLabel);
518 XtFree((char *)xferState);
519 XtFree((char *)dropData->data.buffers);
523 * Convert buffer data into a single chunk of memory
526 dndBufferDataToSelectionValue(
527 DtDndBuffer * buffers,
529 XtPointer * returnValue,
530 unsigned long * returnLength,
538 for (ii = 0; ii < numBuffers; ii++) {
539 *returnLength += buffers[ii].size;
545 *returnValue = (XtPointer) XtMalloc(*returnLength);
547 bufferPtr = (XtPointer)*returnValue;
549 for (ii = 0; ii < numBuffers; ii++) {
550 memcpy(bufferPtr, buffers[ii].bp, buffers[ii].size);
551 bufferPtr += buffers[ii].size;
564 * Convert buffer lengths into a list of integers
567 dndBufferLengthsToSelectionValue(
568 DtDndBuffer * buffers,
570 XtPointer * returnValue,
571 unsigned long * returnLength)
574 unsigned long * lengths;
576 *returnLength = numBuffers;
578 *returnValue = (XtPointer) XtMalloc(*returnLength * sizeof(long));
580 lengths = (unsigned long *)*returnValue;
582 for (ii = 0; ii < numBuffers; ii++) {
583 lengths[ii] = buffers[ii].size;
588 * Convert buffer names into a single chunk of memory
591 dndBufferNamesToSelectionValue(
592 DtDndBuffer * buffers,
594 XtPointer * returnValue,
595 unsigned long * returnLength)
602 for (ii = 0; ii < numBuffers; ii++) {
603 if (buffers[ii].name != NULL) {
604 *returnLength += strlen(buffers[ii].name) + 1;
610 *returnValue = (XtPointer) XtMalloc(*returnLength);
612 namePtr = (char *)*returnValue;
614 for (ii = 0; ii < numBuffers; ii++) {
615 if (buffers[ii].name == NULL) {
619 len = strlen(buffers[ii].name) + 1;
620 memcpy(namePtr, buffers[ii].name, len);
627 * Split text selection data into multiple buffers
630 dndTextSelectionValueToBuffer(
634 unsigned long * length,
637 XtPointer * returnValue,
638 unsigned long * returnLength,
639 DtDndBuffer ** buffers,
640 Cardinal * numBuffers)
642 XTextProperty textProp;
645 int ii, status, textCount, textLen;
647 textProp.value = (unsigned char *)value;
648 textProp.encoding = *type;
649 textProp.format = *format;
650 textProp.nitems = *length;
652 status = XmbTextPropertyToTextList(display, &textProp,
655 if (status != Success) {
657 (*buffers) = (DtDndBuffer *)XtMalloc(sizeof(DtDndBuffer));
659 (*buffers)[0].bp = value;
660 (*buffers)[0].size = *length;
661 (*buffers)[0].name = dataLabel ? dataLabel : (String)NULL;
663 *returnValue = value;
664 *returnLength = *length;
669 *numBuffers = textCount;
671 (*buffers) = (DtDndBuffer *)XtMalloc(*numBuffers * sizeof(DtDndBuffer));
674 for (ii = 0; ii < *numBuffers; ii++) {
675 (*buffers)[ii].size = strlen(text[ii]);
676 (*buffers)[ii].name = (String)NULL;
677 textLen += (*buffers)[ii].size+1;
680 (*returnValue) = XtMalloc(textLen * sizeof(char));
681 (*returnLength) = textLen;
683 bufPtr = (*returnValue);
684 for (ii = 0; ii < *numBuffers; ii++) {
685 (*buffers)[ii].bp = bufPtr;
686 memcpy(bufPtr,text[ii],(*buffers)[ii].size+1);
687 bufPtr += (*buffers)[ii].size+1;
691 (*buffers)[0].name = dataLabel;
694 XFreeStringList(text);
698 * Split data/lengths/names selection data into multiple buffers
701 dndSelectionValueToBuffer(
703 unsigned long dataLength,
704 XtPointer lengthsValue,
705 unsigned long lengthsLength,
706 XtPointer namesValue,
707 unsigned long namesLength,
708 DtDndBuffer ** buffers,
709 Cardinal * numBuffers)
714 unsigned long * lenList;
716 if (lengthsLength == 0 || lengthsValue == NULL) {
720 (*buffers) = (DtDndBuffer *)XtMalloc(sizeof(DtDndBuffer));
722 (*buffers)[0].bp = dataValue;
723 (*buffers)[0].size = dataLength;
724 (*buffers)[0].name = (String)NULL;
729 *numBuffers = lengthsLength;
731 (*buffers) = (DtDndBuffer *)XtMalloc(*numBuffers * sizeof(DtDndBuffer));
733 lenList = (unsigned long *)lengthsValue;
735 namePtr = namesValue;
737 for (ii = 0; ii < *numBuffers; ii++) {
738 (*buffers)[ii].bp = bufPtr;
739 (*buffers)[ii].size = lenList[ii];
740 (*buffers)[ii].name = namePtr;
741 bufPtr += lenList[ii];
742 namePtr = strchr(namePtr, '\0');