cdesktopenv/cde/lib/DtSvc/DtUtil1/DndBuff.c

746 lines
18 KiB
C

/*
* 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 librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/* $XConsortium: DndBuff.c /main/5 1996/06/21 17:30:55 ageorge $ */
/*********************************************************************
*
* File: DndBuff.c
*
* Description: Implementation of the Buffer Transfer routines
* FOR the DND Convenience API.
*
*********************************************************************
*
*
* RESTRICTED CONFIDENTIAL INFORMATION:
*
* The information in this document is subject to special
* restrictions in a confidential disclosure agreement bertween
* HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
* document outside HP, IBM, Sun, USL, SCO, or Univel wihtout
* Sun's specific written approval. This documment and all copies
* and derivative works thereof must be returned or destroyed at
* Sun's request.
*
* Copyright 1993 Sun Microsystems, Inc. All rights reserved.
*
* (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 <X11/Intrinsic.h>
#include <Xm/AtomMgr.h>
#include <Xm/DragC.h>
#include <Xm/DropSMgr.h>
#include <Xm/DropTrans.h>
#include "Dnd.h"
#include "DndP.h"
#include "DtSvcLock.h"
/*
* Buffer Transfer Protocol Function Prototypes
*/
static void dndBuffGetTargets(Boolean, Boolean, Atom**, Cardinal*);
static void dndBuffGetAvailTargets(DtDragInfo*, Atom**, Cardinal*);
static void dndBuffGetExportTargets(DtDragInfo*, Atom**, Cardinal*);
static void dndBuffGetImportTargets(DtDropInfo*, Atom**, Cardinal*);
static void dndBuffConvertInit(DtDragInfo*);
static Boolean dndBuffConvert(Widget, DtDragInfo*, Atom*, Atom*,
Atom*, XtPointer*, unsigned long*, int*,
XSelectionRequestEvent*);
static void dndBuffConvertFinish(DtDragInfo*);
static void dndBuffTransferTargets(DtDropInfo*,
Atom*, Cardinal, Atom**, Cardinal*);
static void dndBuffTransfer(Widget, DtDropInfo*, Atom*, Atom*, Atom*,
XtPointer, unsigned long*, int*);
static void dndBuffTransferFinish(DtDropInfo*);
/*
* Buffer Transfer Support Functions
*/
static void dndBufferDataToSelectionValue(DtDndBuffer *, Cardinal,
XtPointer *, unsigned long *, Boolean);
static void dndBufferLengthsToSelectionValue(DtDndBuffer *, Cardinal,
XtPointer *, unsigned long *);
static void dndBufferNamesToSelectionValue(DtDndBuffer *, Cardinal,
XtPointer *, unsigned long *);
static void dndTextSelectionValueToBuffer(Display *,
Atom *, XtPointer, unsigned long *, int *, String,
XtPointer *, unsigned long *,
DtDndBuffer **, Cardinal *);
static void dndSelectionValueToBuffer(XtPointer, unsigned long,
XtPointer, unsigned long, XtPointer, unsigned long,
DtDndBuffer **, Cardinal *);
/*
* Buffer Transfer Selection Targets
*/
static Atom XA_DT_BUFFER_DATA;
static Atom XA_DT_BUFFER_LENGTHS;
static Atom XA_DT_BUFFER_NAMES;
/*
* Buffer Transfer Protocol Methods
*/
static DtDndMethods dndBuffTransferProtocol = {
"DtDndBufferTransfer", /* name */
(DtDndProtocol)DtDND_BUFFER_TRANSFER, /* protocol */
DtDND_DRAG_SOURCE_DATA, /* sourceType */
dndBuffGetAvailTargets, /* getAvailTargets */
dndBuffGetExportTargets, /* getExportTargets */
dndBuffGetImportTargets, /* getImportTargets */
dndBuffConvertInit, /* convertInit */
dndBuffConvert, /* convert */
dndBuffConvertFinish, /* convertFinish */
dndBuffTransferTargets, /* transferTargets */
dndBuffTransfer, /* transfer */
dndBuffTransferFinish, /* transferFinish */
};
typedef struct _TransferState {
XtPointer dataValue;
unsigned long dataLength;
XtPointer lengthsValue;
unsigned long lengthsLength;
XtPointer namesValue;
unsigned long namesLength;
String dataLabel;
Atom textTarget;
} TransferState;
/*
* Buffer transfer protocol initialization
*/
DtDndMethods *
_DtDndBuffTransferProtocolInitialize(
Display * dpy)
{
_DtSvcProcessLock();
if (XA_DT_BUFFER_DATA == 0) {
XA_DT_BUFFER_DATA = DtGetAtom(dpy,"_DT_BUFFER_DATA");
XA_DT_BUFFER_LENGTHS = DtGetAtom(dpy,"_DT_BUFFER_LENGTHS");
XA_DT_BUFFER_NAMES = DtGetAtom(dpy,"_DT_BUFFER_NAMES");
}
_DtSvcProcessUnlock();
return &dndBuffTransferProtocol;
}
/*
* Returns export/import targets for buffer transfers
*/
static void
dndBuffGetTargets(
Boolean includeText,
Boolean owCompat,
Atom ** targets,
Cardinal * numTargets)
{
int ii = 0;
*numTargets = 3 + (includeText ? 2 : 0) + (owCompat ? 1 : 0);
*targets = (Atom *)XtMalloc(*numTargets * sizeof(Atom));
(*targets)[ii++] = XA_DT_BUFFER_DATA;
(*targets)[ii++] = XA_DT_BUFFER_LENGTHS;
(*targets)[ii++] = XA_DT_BUFFER_NAMES;
if (includeText) {
(*targets)[ii++] = XA_TEXT;
(*targets)[ii++] = XA_STRING;
}
if (owCompat) {
(*targets)[ii++] = XA_SUN_DATA_LABEL;
}
}
/*
* Returns available targets for buffer transfers
*/
static void
dndBuffGetAvailTargets(
DtDragInfo * dtDragInfo,
Atom ** availTargets,
Cardinal * numAvailTargets)
{
dndBuffGetTargets(True, True, availTargets, numAvailTargets);
}
/*
* Returns export targets for buffer transfers
*/
static void
dndBuffGetExportTargets(
DtDragInfo * dtDragInfo,
Atom ** exportTargets,
Cardinal * numExportTargets)
{
dndBuffGetTargets(dtDragInfo->bufferIsText, True,
exportTargets, numExportTargets);
}
/*
* Returns import targets for buffer transfers
*/
static void
dndBuffGetImportTargets(
DtDropInfo * dtDropInfo,
Atom ** importTargets,
Cardinal * numImportTargets)
{
dndBuffGetTargets(dtDropInfo->textIsBuffer, True,
importTargets, numImportTargets);
}
/*
* Initialize protocol specific part of drag data
*/
static void
dndBuffConvertInit(
DtDragInfo * dtDragInfo)
{
DtDndContext * dragData = dtDragInfo->dragData;
dragData->data.buffers = (DtDndBuffer *)
XtCalloc(dragData->numItems, sizeof(DtDndBuffer));
}
/*
* Convert the buffers into selection data
*/
static Boolean
dndBuffConvert(
Widget dragContext,
DtDragInfo * dtDragInfo,
Atom * selection,
Atom * target,
Atom * returnType,
XtPointer * returnValue,
unsigned long * returnLength,
int * returnFormat,
XSelectionRequestEvent * selectionRequestEvent)
{
DtDndContext * dragData = dtDragInfo->dragData;
/*
* TEXT or STRING
* Convert the buffer data to a text selection
*/
if (*target == XA_TEXT || *target == XA_STRING) {
*returnType = XA_STRING;
*returnFormat = 8;
dndBufferDataToSelectionValue(
dragData->data.buffers, dragData->numItems,
returnValue, returnLength, True);
/*
* _SUN_DATA_LABEL
* Convert the first buffer name to a selection
*/
} else if (*target == XA_SUN_DATA_LABEL) {
*returnType = XA_STRING;
*returnFormat = 8;
*returnValue = XtNewString(dragData->data.buffers[0].name);
*returnLength = strlen(*returnValue)+1;
/*
* _DT_BUFFER_DATA
* Convert the buffer data to a selection
*/
} else if (*target == XA_DT_BUFFER_DATA) {
*returnType = XA_DT_BUFFER_DATA;
*returnFormat = 8;
dndBufferDataToSelectionValue(
dragData->data.buffers, dragData->numItems,
returnValue, returnLength, False);
/*
* _DT_BUFFER_LENGTHS
* Convert the buffer lengths to a selection
*/
} else if (*target == XA_DT_BUFFER_LENGTHS) {
*returnType = XA_INTEGER;
*returnFormat = 32;
dndBufferLengthsToSelectionValue(
dragData->data.buffers, dragData->numItems,
returnValue, returnLength);
/*
* _DT_BUFFER_NAMES
* Convert the buffer names to a selection
*/
} else if (*target == XA_DT_BUFFER_NAMES) {
*returnType = XA_STRING;
*returnFormat = 8;
dndBufferNamesToSelectionValue(
dragData->data.buffers, dragData->numItems,
returnValue, returnLength);
} else {
return False;
}
return True;
}
/*
* Clean up from the convert init proc
*/
static void
dndBuffConvertFinish(
DtDragInfo * dtDragInfo)
{
DtDndContext * dragData = dtDragInfo->dragData;
if (dragData->data.buffers) {
XtFree((char *)dragData->data.buffers);
dragData->data.buffers = NULL;
}
}
/*
* Returns the transfer targets selected from the export targets
* Prefer buffers over TEXT/STRING
*/
static void
dndBuffTransferTargets(
DtDropInfo * dtDropInfo,
Atom * exportTargets,
Cardinal numExportTargets,
Atom ** transferTargets,
Cardinal * numTransferTargets)
{
Boolean foundData, foundLengths, foundNames,
foundDataLabel, foundText, foundString;
int ii;
TransferState * xferState;
xferState = (TransferState *)XtCalloc(1,sizeof(TransferState));
dtDropInfo->transferInfo->clientData = (XtPointer)xferState;
foundData = foundLengths = foundNames = False;
foundDataLabel = foundText = foundString = False;
for (ii = 0; ii < numExportTargets; ii++) {
if (exportTargets[ii] == XA_DT_BUFFER_DATA) {
foundData = True;
} else if (exportTargets[ii] == XA_DT_BUFFER_LENGTHS) {
foundLengths = True;
} else if (exportTargets[ii] == XA_DT_BUFFER_NAMES) {
foundNames = True;
} else if (exportTargets[ii] == XA_SUN_DATA_LABEL) {
foundDataLabel = True;
} else if (exportTargets[ii] == XA_TEXT) {
foundText = True;
} else if (exportTargets[ii] == XA_STRING) {
foundString = True;
}
}
*numTransferTargets = 2; /* max number of transfer targets */
*transferTargets = (Atom *)XtMalloc(*numTransferTargets * sizeof(Atom));
ii = 0;
if (foundData && foundLengths && foundNames) {
*numTransferTargets = 2;
(*transferTargets)[ii++] = XA_DT_BUFFER_NAMES;
(*transferTargets)[ii++] = XA_DT_BUFFER_LENGTHS;
} else if (foundDataLabel && (foundText || foundString)) {
*numTransferTargets = 2;
(*transferTargets)[ii++] = XA_SUN_DATA_LABEL;
(*transferTargets)[ii++] = foundText ? XA_TEXT : XA_STRING;
xferState->textTarget = foundText ? XA_TEXT : XA_STRING;
} else if (foundText || foundString) {
*numTransferTargets = 1;
(*transferTargets)[ii++] = foundText ? XA_TEXT : XA_STRING;
} else {
*numTransferTargets = 0;
*transferTargets = NULL;
return;
}
}
/*
* Transfer the selection data into buffers
*/
static void
dndBuffTransfer(
Widget dropTransfer,
DtDropInfo * dtDropInfo,
Atom * selection,
Atom * target,
Atom * type,
XtPointer value,
unsigned long * length,
int * format)
{
Display * display = XtDisplayOfObject(dropTransfer);
DtDndContext * dropData = dtDropInfo->dropData;
TransferState * xferState =
(TransferState *)dtDropInfo->transferInfo->clientData;
/*
* Ignore if we've already transferred
*/
if (dropData->data.buffers) {
XtFree(value);
return;
}
/*
* TEXT or STRING
*
* Convert the text selection into buffers
*/
if (*target == XA_TEXT || *target == XA_STRING) {
dndTextSelectionValueToBuffer(display,
type, value, length, format, xferState->dataLabel,
&(xferState->dataValue), &(xferState->dataLength),
&(dropData->data.buffers), &(dropData->numItems));
/*
* _SUN_DATA_LABEL
*
* Save the buffer name selection for later conversion
* Request the text data transfer
*/
} else if (*target == XA_SUN_DATA_LABEL &&
*type == XA_STRING &&
*format == 8) {
xferState->dataLabel = (String)value;
_DtDndTransferAdd(dropTransfer, dtDropInfo,
&(xferState->textTarget), 1);
/*
* _DT_BUFFER_DATA
*
* Save the buffer data selection for later conversion
*/
} else if (*target == XA_DT_BUFFER_DATA &&
*type == XA_DT_BUFFER_DATA &&
*format == 8) {
xferState->dataValue = value;
xferState->dataLength = *length;
dndSelectionValueToBuffer(
xferState->dataValue, xferState->dataLength,
xferState->lengthsValue, xferState->lengthsLength,
xferState->namesValue, xferState->namesLength,
&(dropData->data.buffers), &(dropData->numItems));
/*
* _DT_BUFFER_LENGTHS
*
* Save the buffer lengths selection for later conversion
* Request the buffer data transfer
*/
} else if (*target == XA_DT_BUFFER_LENGTHS &&
*type == XA_INTEGER &&
*format == 32) {
xferState->lengthsValue = value;
xferState->lengthsLength = *length;
_DtDndTransferAdd(dropTransfer, dtDropInfo,
&XA_DT_BUFFER_DATA, 1);
/*
* _DT_BUFFER_NAMES
*
* Save the buffer names selection for later conversion
*/
} else if (*target == XA_DT_BUFFER_NAMES &&
*type == XA_STRING &&
*format == 8) {
xferState->namesValue = value;
xferState->namesLength = *length;
/*
* Ignore transfers we don't understand
*/
} else {
XtFree(value);
return;
}
}
/*
* Clean up from the transfer proc
*/
static void
dndBuffTransferFinish(
DtDropInfo * dtDropInfo)
{
DtDndContext * dropData = dtDropInfo->dropData;
TransferState * xferState =
(TransferState *)dtDropInfo->transferInfo->clientData;
dtDropInfo->transferInfo->clientData = NULL;
if (xferState->dataValue)
XtFree(xferState->dataValue);
if (xferState->lengthsValue)
XtFree(xferState->lengthsValue);
if (xferState->namesValue)
XtFree(xferState->namesValue);
if (xferState->dataLabel)
XtFree(xferState->dataLabel);
XtFree((char *)xferState);
XtFree((char *)dropData->data.buffers);
}
/*
* Convert buffer data into a single chunk of memory
*/
static void
dndBufferDataToSelectionValue(
DtDndBuffer * buffers,
Cardinal numBuffers,
XtPointer * returnValue,
unsigned long * returnLength,
Boolean isText)
{
int ii;
char *bufferPtr;
*returnLength = 0;
for (ii = 0; ii < numBuffers; ii++) {
*returnLength += buffers[ii].size;
if (isText) {
*returnLength += 1;
}
}
*returnValue = (XtPointer) XtMalloc(*returnLength);
bufferPtr = (XtPointer)*returnValue;
for (ii = 0; ii < numBuffers; ii++) {
memcpy(bufferPtr, buffers[ii].bp, buffers[ii].size);
bufferPtr += buffers[ii].size;
if (isText) {
*bufferPtr = '\0';
bufferPtr++;
}
}
if (isText) {
*returnLength -= 1;
}
}
/*
* Convert buffer lengths into a list of integers
*/
static void
dndBufferLengthsToSelectionValue(
DtDndBuffer * buffers,
Cardinal numBuffers,
XtPointer * returnValue,
unsigned long * returnLength)
{
int ii;
unsigned long * lengths;
*returnLength = numBuffers;
*returnValue = (XtPointer) XtMalloc(*returnLength * sizeof(long));
lengths = (unsigned long *)*returnValue;
for (ii = 0; ii < numBuffers; ii++) {
lengths[ii] = buffers[ii].size;
}
}
/*
* Convert buffer names into a single chunk of memory
*/
static void
dndBufferNamesToSelectionValue(
DtDndBuffer * buffers,
Cardinal numBuffers,
XtPointer * returnValue,
unsigned long * returnLength)
{
int ii, len;
char * namePtr;
*returnLength = 0;
for (ii = 0; ii < numBuffers; ii++) {
if (buffers[ii].name != NULL) {
*returnLength += strlen(buffers[ii].name) + 1;
} else {
*returnLength += 1;
}
}
*returnValue = (XtPointer) XtMalloc(*returnLength);
namePtr = (char *)*returnValue;
for (ii = 0; ii < numBuffers; ii++) {
if (buffers[ii].name == NULL) {
*namePtr = '\0';
namePtr++;
} else {
len = strlen(buffers[ii].name) + 1;
memcpy(namePtr, buffers[ii].name, len);
namePtr += len;
}
}
}
/*
* Split text selection data into multiple buffers
*/
static void
dndTextSelectionValueToBuffer(
Display * display,
Atom * type,
XtPointer value,
unsigned long * length,
int * format,
String dataLabel,
XtPointer * returnValue,
unsigned long * returnLength,
DtDndBuffer ** buffers,
Cardinal * numBuffers)
{
XTextProperty textProp;
char ** text;
char * bufPtr;
int ii, status, textCount, textLen;
textProp.value = (unsigned char *)value;
textProp.encoding = *type;
textProp.format = *format;
textProp.nitems = *length;
status = XmbTextPropertyToTextList(display, &textProp,
&text, &textCount);
if (status != Success) {
*numBuffers = 1;
(*buffers) = (DtDndBuffer *)XtMalloc(sizeof(DtDndBuffer));
(*buffers)[0].bp = value;
(*buffers)[0].size = *length;
(*buffers)[0].name = dataLabel ? dataLabel : (String)NULL;
*returnValue = value;
*returnLength = *length;
return;
}
*numBuffers = textCount;
(*buffers) = (DtDndBuffer *)XtMalloc(*numBuffers * sizeof(DtDndBuffer));
textLen = 0;
for (ii = 0; ii < *numBuffers; ii++) {
(*buffers)[ii].size = strlen(text[ii]);
(*buffers)[ii].name = (String)NULL;
textLen += (*buffers)[ii].size+1;
}
(*returnValue) = XtMalloc(textLen * sizeof(char));
(*returnLength) = textLen;
bufPtr = (*returnValue);
for (ii = 0; ii < *numBuffers; ii++) {
(*buffers)[ii].bp = bufPtr;
memcpy(bufPtr,text[ii],(*buffers)[ii].size+1);
bufPtr += (*buffers)[ii].size+1;
}
if (dataLabel)
(*buffers)[0].name = dataLabel;
XtFree(value);
XFreeStringList(text);
}
/*
* Split data/lengths/names selection data into multiple buffers
*/
static void
dndSelectionValueToBuffer(
XtPointer dataValue,
unsigned long dataLength,
XtPointer lengthsValue,
unsigned long lengthsLength,
XtPointer namesValue,
unsigned long namesLength,
DtDndBuffer ** buffers,
Cardinal * numBuffers)
{
int ii;
char * bufPtr;
char * namePtr;
unsigned long * lenList;
if (lengthsLength == 0 || lengthsValue == NULL) {
*numBuffers = 1;
(*buffers) = (DtDndBuffer *)XtMalloc(sizeof(DtDndBuffer));
(*buffers)[0].bp = dataValue;
(*buffers)[0].size = dataLength;
(*buffers)[0].name = (String)NULL;
return;
}
*numBuffers = lengthsLength;
(*buffers) = (DtDndBuffer *)XtMalloc(*numBuffers * sizeof(DtDndBuffer));
lenList = (unsigned long *)lengthsValue;
bufPtr = dataValue;
namePtr = namesValue;
for (ii = 0; ii < *numBuffers; ii++) {
(*buffers)[ii].bp = bufPtr;
(*buffers)[ii].size = lenList[ii];
(*buffers)[ii].name = namePtr;
bufPtr += lenList[ii];
namePtr = strchr(namePtr, '\0');
namePtr++;
}
}