Files
cdesktop/cde/lib/DtSvc/DtUtil1/DndDrag.c
2019-10-28 13:22:09 -06:00

851 lines
23 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 libraries and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/* $XConsortium: DndDrag.c /main/5 1996/09/27 19:00:40 drk $ */
/*********************************************************************
*
* File: DndDrag.c
*
* Description: Implemenation of DND Drag Initator
*
*********************************************************************
*
*+SNOTICE
*
* RESTRICTED CONFIDENTIAL INFORMATION:
*
* The information in this document is subject to special
* restrictions in a confidential disclosure agreement between
* HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
* document outside HP, IBM, Sun, USL, SCO, or Univel without
* 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.
*
*+ENOTICE
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <X11/Intrinsic.h>
#include <Xm/AtomMgr.h>
#include <Xm/DragDrop.h>
#include <Xm/DragC.h>
#include <Xm/DragCP.h>
#include <Xm/DragOverSP.h>
#include <Dt/Wsm.h>
#include "Dnd.h"
#include "DndP.h"
#include "DtSvcLock.h"
/*
* Drag Initiator Callbacks
*/
static Boolean dndConvertProc(Widget, Atom*, Atom*, Atom*, XtPointer *,
unsigned long*, int*);
static void dndAppConvert(Widget, int, XEvent*, DtDragInfo*);
static void dndDropStartCallback(Widget, XtPointer, XtPointer);
static void dndDropFinishCallback(Widget, XtPointer, XtPointer);
static void dndDragDropFinishCallback(Widget, XtPointer, XtPointer);
static void dndTopLevelEnterCallback(Widget, XtPointer, XtPointer);
static void dndTopLevelLeaveCallback(Widget, XtPointer, XtPointer);
extern int _DtDndCountVarArgs(va_list vaList);
extern void _DtDndArgListFromVarArgs(va_list vaList,
Cardinal maxArgs,
ArgList *argListReturn,
Cardinal *argCountReturn);
extern void _XmDragOverChange(Widget w,
unsigned char dropSiteStatus);
/*
* Drag Initiator Resources
*/
typedef struct {
XtCallbackList dropOnRootCallback;
Widget sourceIcon;
Boolean bufferIsText;
} DragSettings;
#define Offset(field) XtOffsetOf(DragSettings, field)
static XtResource dragResources[] = {
{ DtNdropOnRootCallback, DtCDropOnRootCallback,
XtRCallback, sizeof(XtCallbackList), Offset(dropOnRootCallback),
XtRImmediate, (XtPointer)NULL},
{ DtNsourceIcon, DtCSourceIcon,
XtRWidget, sizeof(Widget), Offset(sourceIcon),
XtRImmediate, (XtPointer)NULL },
{ DtNbufferIsText, DtCBufferIsText,
XtRBoolean, sizeof(Boolean), Offset(bufferIsText),
XtRImmediate, (XtPointer)False },
};
#undef Offset
/*
* DtDndVaDragStart
*
* Drag Start - varargs version
*/
Widget
DtDndVaDragStart(
Widget dragInitiator,
XEvent* event,
DtDndProtocol protocol,
Cardinal numItems,
unsigned char operations,
XtCallbackList dragConvertCallback,
XtCallbackList dragFinishCallback,
...)
{
Widget dragContext;
va_list vaList;
ArgList argList;
Cardinal argCount;
_DtSvcWidgetToAppContext(dragInitiator);
_DtSvcAppLock(app);
va_start(vaList, dragFinishCallback);
argCount = _DtDndCountVarArgs(vaList);
va_end(vaList);
va_start(vaList, dragFinishCallback);
_DtDndArgListFromVarArgs(vaList, argCount, &argList, &argCount);
va_end(vaList);
dragContext = DtDndDragStart(dragInitiator, event, protocol,
numItems, operations,
dragConvertCallback, dragFinishCallback,
argList, argCount);
XtFree((char *)argList);
_DtSvcAppUnlock(app);
return dragContext;
}
/*
* DtDndVaDragStart
*
* Drag Start - arglist version
*/
Widget
DtDndDragStart(
Widget dragInitiator,
XEvent* event,
DtDndProtocol protocol,
Cardinal numItems,
unsigned char operations,
XtCallbackList dragConvertCallback,
XtCallbackList dragFinishCallback,
ArgList argList,
Cardinal argCount)
{
XtCallbackRec dragDropFinishCbRec[] = { {dndDragDropFinishCallback,
NULL}, {NULL, NULL} };
XtCallbackRec topLevelEnterCbRec[] = { {dndTopLevelEnterCallback,
NULL}, {NULL, NULL} };
XtCallbackRec topLevelLeaveCbRec[] = { {dndTopLevelLeaveCallback,
NULL}, {NULL, NULL} };
XtCallbackRec dropStartCbRec[] = { {dndDropStartCallback,
NULL}, {NULL, NULL} };
XtCallbackRec dropFinishCbRec[] = { {dndDropFinishCallback,
NULL}, {NULL, NULL} };
Display * display = XtDisplayOfObject(dragInitiator);
Screen * screen = XtScreenOfObject(dragInitiator);
Window rootWindow = RootWindowOfScreen(screen);
DtDragInfo * dtDragInfo;
DragSettings settings;
DtDndDragSource sourceType;
DtDndTransfer * transfer;
Arg * args;
int ii, nn, savedEventType;
Atom * exportTargets;
Cardinal numExportTargets;
_DtSvcWidgetToAppContext(dragInitiator);
_DtSvcAppLock(app);
/*
* Reject the drag if noop or multiple protocols specified
*/
switch (protocol) {
case DtDND_BUFFER_TRANSFER:
case DtDND_FILENAME_TRANSFER:
case DtDND_TEXT_TRANSFER:
break;
case DtDND_NOOP_TRANSFER:
default:
_DtSvcAppUnlock(app);
return (Widget)NULL;
}
/*
* Parse resources into dragResources
*/
XtGetSubresources(dragInitiator, &settings,
(String)NULL, (String)NULL,
dragResources, XtNumber(dragResources),
argList, argCount);
/*
* Initialize DragInfo
*/
dtDragInfo = (DtDragInfo *) XtMalloc(sizeof(DtDragInfo));
dtDragInfo->dragInitiator = dragInitiator;
dtDragInfo->dragContext = NULL;
dtDragInfo->protocol = protocol;
dtDragInfo->numItems = numItems;
dtDragInfo->operations = operations;
dtDragInfo->sourceIcon = settings.sourceIcon;
dtDragInfo->bufferIsText = settings.bufferIsText;
dtDragInfo->dragData = NULL;
dtDragInfo->inRoot = False;
dtDragInfo->status = DtDND_SUCCESS;
dtDragInfo->clientData = NULL;
dtDragInfo->backdropWindow
= DtWsmGetCurrentBackdropWindow(display, rootWindow);
dtDragInfo->dragConvertCallback
= _DtDndCopyCallbackList(dragConvertCallback);
dtDragInfo->dragFinishCallback
= _DtDndCopyCallbackList(dragFinishCallback);
dtDragInfo->dropOnRootCallback
= _DtDndCopyCallbackList(settings.dropOnRootCallback);
dtDragInfo->dragData = (DtDndContext *)XtCalloc(1,sizeof(DtDndContext));
dtDragInfo->dragData->protocol = dtDragInfo->protocol;
dtDragInfo->dragData->numItems = 0;
/*
* Get data transfer method
* Use the transfer targets as export targets
*/
dtDragInfo->transfer = _DtDndCreateExportTransfer(dtDragInfo);
exportTargets = dtDragInfo->transfer->targets;
numExportTargets = dtDragInfo->transfer->numTargets;
#ifdef DEBUG
printf("DtDndDragStart: drag from widget 0x%p\n", dragInitiator);
_DtDndPrintTransfers(display,dtDragInfo->transfer,1);
#endif
/*
* Set up drag icon
*/
if (numItems > 1) {
sourceType = DtDND_DRAG_SOURCE_MULTIPLE;
} else {
sourceType = dtDragInfo->transfer->methods->sourceType;
}
_DtDndSelectDragSource(dragInitiator, sourceType,
dtDragInfo->sourceIcon);
/*
* Construct argument list
*/
#define NUM_DRAG_ARGS 30
args = (Arg *) XtMalloc(sizeof(Arg) * (NUM_DRAG_ARGS + argCount));
#undef NUM_DRAG_ARGS
/*
* Copy in passed arguments
*/
nn = 0;
for (ii = 0; ii < argCount; ii++) {
XtSetArg(args[nn], argList[ii].name, argList[ii].value); nn++;
}
/*
* Set basic drag start arguments
*/
XtSetArg(args[nn], XmNexportTargets, exportTargets);
nn++;
XtSetArg(args[nn], XmNnumExportTargets, numExportTargets);
nn++;
XtSetArg(args[nn], XmNdragOperations, operations);
nn++;
XtSetArg(args[nn], XmNblendModel, XmBLEND_ALL);
nn++;
XtSetArg(args[nn], XmNcursorBackground, WhitePixelOfScreen(screen));
nn++;
XtSetArg(args[nn], XmNcursorForeground, BlackPixelOfScreen(screen));
nn++;
XtSetArg(args[nn], XmNclientData, dtDragInfo);
nn++;
if (dtDragInfo->sourceIcon != NULL) {
XtSetArg(args[nn],XmNsourcePixmapIcon, dtDragInfo->sourceIcon);
nn++;
XtSetArg(args[nn],XmNsourceCursorIcon, dtDragInfo->sourceIcon);
nn++;
}
/*
* Set up DnD callbacks for Motif
*/
XtSetArg(args[nn], XmNconvertProc, dndConvertProc);
nn++;
dragDropFinishCbRec[0].closure = (XtPointer) dtDragInfo;
dropFinishCbRec[0].closure = (XtPointer) dtDragInfo;
dtDragInfo->dragDropFinishCallback
= _DtDndCopyCallbackList(dragDropFinishCbRec);
dtDragInfo->dropFinishCallback
= _DtDndCopyCallbackList(dropFinishCbRec);
XtSetArg(args[nn], XmNdragDropFinishCallback, dtDragInfo->dragDropFinishCallback);
nn++;
XtSetArg(args[nn], XmNdropFinishCallback, dtDragInfo->dropFinishCallback);
nn++;
/*
* Only use top-level-enter/leave callbacks if also doing drop-on-root
*/
if (dtDragInfo->dropOnRootCallback != NULL) {
topLevelEnterCbRec[0].closure = (XtPointer) dtDragInfo;
topLevelLeaveCbRec[0].closure = (XtPointer) dtDragInfo;
dropStartCbRec[0].closure = (XtPointer) dtDragInfo;
dtDragInfo->topLevelEnterCallback
= _DtDndCopyCallbackList(topLevelEnterCbRec);
dtDragInfo->topLevelLeaveCallback
= _DtDndCopyCallbackList(topLevelLeaveCbRec);
dtDragInfo->dropStartCallback
= _DtDndCopyCallbackList(dropStartCbRec);
XtSetArg(args[nn], XmNtopLevelEnterCallback, dtDragInfo->topLevelEnterCallback);
nn++;
XtSetArg(args[nn], XmNtopLevelLeaveCallback, dtDragInfo->topLevelLeaveCallback);
nn++;
XtSetArg(args[nn], XmNdropStartCallback, dtDragInfo->dropStartCallback);
nn++;
}
/*
* Fake a button press. This is necessary because Motif requires
* a drag to start on a button press. We need to be able to start
* a drag on a mouse motion event when Bselect is held down. Since
* the motion event has the fields necessary for Motif this works.
*/
savedEventType = event->type;
if (event->type == MotionNotify) {
event->type = ButtonPress;
}
/*
* Start the drag
*/
dtDragInfo->dragContext = XmDragStart(dragInitiator, event, args, nn);
XtFree((char *)args);
event->type = savedEventType;
_DtSvcAppUnlock(app);
return (dtDragInfo->dragContext);
}
/*********************************************************************
*
* Drag Initiator Callbacks
*
*********************************************************************/
/*
* dndDropStartCallback
*
*
*/
static void
dndDropStartCallback(
Widget dragContext,
XtPointer clientData,
XtPointer callData)
{
DtDragInfo *dtDragInfo = (DtDragInfo *) clientData;
DtDndContext *dragData;
XmDragContext xmDragContext = (XmDragContext)dtDragInfo->dragContext;
XmDropStartCallbackStruct *xmDropInfo = (XmDropStartCallback) callData;
DtDndTransferCallbackStruct dropCallData;
int posOffsetX, posOffsetY;
/*
* If the user has cancelled the drop, or the drop isn't on the
* root, or there are no dropOnRoot or convert callbacks
* then reject the drop.
*/
if (xmDragContext->drag.dragCompletionStatus == XmDROP_CANCEL ||
dtDragInfo->inRoot == False ||
dtDragInfo->dropOnRootCallback == NULL ||
dtDragInfo->dragConvertCallback == NULL ) {
xmDropInfo->dropSiteStatus = XmINVALID_DROP_SITE;
xmDropInfo->dropAction = XmDROP_CANCEL;
return;
}
/*
* The following is to handle the dropOnRoot situation.
* We handle both the convert and transfer sides of the
* transaction here. First we get the application drag data
* and then we call the application dropOnRoot callback.
*/
/*
* Initialize protocol specific dragData
*/
dtDragInfo->dragData->numItems = dtDragInfo->numItems;
(*dtDragInfo->transfer->methods->convertInit)(dtDragInfo);
/*
* Invoke the application convert callback
*/
dndAppConvert(dragContext, DtCR_DND_CONVERT_DATA,
xmDropInfo->event, dtDragInfo);
if (dtDragInfo->status == DtDND_FAILURE) {
return;
}
/*
* Setup dropOnRootcall data and invoke the dropOnroot callback
*/
_DtDndGetIconOffset(dtDragInfo->dragContext,
dtDragInfo->transfer->methods->sourceType,
&posOffsetX, &posOffsetY);
dropCallData.reason = DtCR_DND_ROOT_TRANSFER;
dropCallData.event = xmDropInfo->event;
dropCallData.x = xmDropInfo->x + posOffsetX;
dropCallData.y = xmDropInfo->y + posOffsetY;
dropCallData.operation = xmDropInfo->operation;
dropCallData.dropData = dtDragInfo->dragData;
dropCallData.completeMove = False;
dropCallData.status = DtDND_SUCCESS;
_DtDndCallCallbackList(dragContext, dtDragInfo->dropOnRootCallback,
(XtPointer)&dropCallData);
/*
* Tell Motif that the root is a valid drop site
*/
xmDropInfo->dropSiteStatus = XmVALID_DROP_SITE;
xmDropInfo->dropAction = XmDROP;
}
/*
* dndConvertProc
*
*
*/
static Boolean
dndConvertProc(
Widget dragContext,
Atom *selection,
Atom *target,
Atom *returnType,
XtPointer *returnValue,
unsigned long *returnLength,
int *returnFormat)
{
Atom realSelectionAtom; /* Motif hides the selection atom */
DtDragInfo *dtDragInfo = NULL;
XSelectionRequestEvent *selectionRequestEvent;
Boolean status;
#ifdef DEBUG
{
Display *display = XtDisplayOfObject(dragContext);
char *atomname = XGetAtomName(display,*target);
printf("dndConvertProc: target = %s\n",(atomname ? atomname : "Null"));
if (atomname) XFree(atomname);
}
#endif
/*
* Get the DtDragInfo
*/
XtVaGetValues(dragContext, XmNclientData, &dtDragInfo, NULL);
if (dtDragInfo == NULL || dtDragInfo->status == DtDND_FAILURE) {
return False;
}
/*
* Get selection request event
*/
XtVaGetValues(dragContext, XmNiccHandle, &realSelectionAtom, NULL);
selectionRequestEvent = XtGetSelectionRequest(dragContext,
realSelectionAtom, NULL); /* REMIND: NULL for atomic transfer */
/*
* Get the application drag data if necessary
*/
if (dtDragInfo->dragData->numItems == 0) {
dtDragInfo->dragData->numItems = dtDragInfo->numItems;
(*dtDragInfo->transfer->methods->convertInit)(dtDragInfo);
dndAppConvert(dragContext, DtCR_DND_CONVERT_DATA,
(XEvent *)selectionRequestEvent, dtDragInfo);
if (dtDragInfo->status == DtDND_FAILURE) {
return False;
}
}
/*
* Handle transfer protocol independent target conversions
*/
if (*target == XA_TARGETS) {
/*
* TARGETS Construct a list of targets consisting of those
* the dnd library supports plus those supported by
* the drag initiator.
*/
int ii, LIBRARY_TARGETS = 6;
Atom * availTargets;
Atom * allTargets;
Cardinal numAvailTargets;
Cardinal numAllTargets;
(*dtDragInfo->transfer->methods->getAvailTargets)(dtDragInfo,
&availTargets, &numAvailTargets);
numAllTargets = numAvailTargets + LIBRARY_TARGETS;
allTargets = (Atom *)XtMalloc(sizeof(Atom) * numAllTargets);
for (ii = 0; ii < numAvailTargets; ii++) {
allTargets[ii] = availTargets[ii];
}
XtFree((char *)availTargets);
ii = numAvailTargets;
allTargets[ii++] = XA_TARGETS;
allTargets[ii++] = XA_TIMESTAMP;
allTargets[ii++] = XA_MULTIPLE;
allTargets[ii++] = XA_HOST_NAME;
allTargets[ii++] = XA_SUN_FILE_HOST_NAME;
allTargets[ii++] = XA_DELETE;
*returnType = XA_ATOM;
*returnFormat = 32;
*returnValue = (XtPointer)allTargets;
*returnLength = numAllTargets * sizeof(Atom)/4;
status = True;
} else if (*target == XA_TIMESTAMP || *target == XA_MULTIPLE) {
/*
* TIMESTAMP and MULTIPLE are handled by the Intrinsics
*/
status = True;
} else if (*target == XA_HOST_NAME ||
*target == XA_SUN_FILE_HOST_NAME) {
/*
* HOST_NAME, _SUN_FILE_HOST_NAME The name of this host
*/
*returnType = XA_STRING;
*returnValue = (XtPointer)XtNewString(_DtDndGetHostName());
*returnLength = strlen((char *)*returnValue) + 1;
*returnFormat = 8;
status = True;
} else if (*target == XA_DELETE) {
/*
* DELETE Set up convert callback data to specify
* deletion and invoke the application-defined
* convertCallback() to perform the delete.
*/
*returnType = XA_NULL;
*returnFormat = 32;
*returnValue = (XtPointer) NULL;
*returnLength = 0;
dndAppConvert(dragContext, DtCR_DND_CONVERT_DELETE,
(XEvent *)selectionRequestEvent, dtDragInfo);
status = True;
} else if (*target == XA_SUN_ENUM_COUNT) {
/*
* _SUN_ENUMERATION_COUNT The number of items available
*/
int *count = XtNew(int);
if (dtDragInfo->dragData->numItems == 1) {
count[0] = 1;
} else {
count[0] = 0;
dtDragInfo->status = DtDND_FAILURE;
}
*returnType = XA_INTEGER;
*returnValue = (XtPointer)count;
*returnLength = 1;
*returnFormat = 32;
status = True;
} else {
/*
* Invoke protocol specific convert method
*/
status = (*dtDragInfo->transfer->methods->convert)(
dragContext, dtDragInfo,
selection, target,
returnType, returnValue,
returnLength, returnFormat,
selectionRequestEvent);
}
return status;
}
/*
* dndAppConvert
*
* Call the application convert callback
*/
static void
dndAppConvert(
Widget dragContext,
int reason,
XEvent * event,
DtDragInfo * dtDragInfo)
{
DtDndConvertCallbackStruct convertCallData;
convertCallData.reason = reason;
convertCallData.event = event;
convertCallData.dragData = dtDragInfo->dragData;
convertCallData.status = DtDND_SUCCESS;
_DtDndCallCallbackList(dragContext, dtDragInfo->dragConvertCallback,
(XtPointer)&convertCallData);
dtDragInfo->status = convertCallData.status;
if (reason == DtCR_DND_CONVERT_DATA &&
dtDragInfo->dragData->numItems <= 0) {
dtDragInfo->status = DtDND_FAILURE;
}
}
/*
* dndDropFinishCallback
*
* Handle drop-on-root case
*/
static void
dndDropFinishCallback(
Widget dragContext,
XtPointer clientData,
XtPointer callData)
{
DtDragInfo *dtDragInfo = (DtDragInfo *) clientData;
XmDropFinishCallbackStruct *xmDropFinishCallData =
(XmDropFinishCallbackStruct *) callData;
if (dtDragInfo->dropOnRootCallback != NULL &&
dtDragInfo->inRoot &&
xmDropFinishCallData->dropSiteStatus == XmVALID_DROP_SITE) {
xmDropFinishCallData->completionStatus = XmDROP_SUCCESS;
XtVaSetValues(dtDragInfo->dragContext,
XmNblendModel, XmBLEND_NONE, NULL);
}
}
/*
* dndDragDropFinishCallback
*
* Call the application dragFinishCallback
*/
static void
dndDragDropFinishCallback(
Widget dragContext,
XtPointer clientData,
XtPointer callData)
{
XmDragDropFinishCallbackStruct *xmDndFinishInfo =
(XmDragDropFinishCallbackStruct *)callData;
DtDragInfo *dtDragInfo = (DtDragInfo *)clientData;
DtDndDragFinishCallbackStruct dragFinishCallData;
/*
* Invoke application dragFinishCallback
*/
dragFinishCallData.reason = DtCR_DND_DRAG_FINISH;
dragFinishCallData.event = xmDndFinishInfo->event;
dragFinishCallData.sourceIcon = dtDragInfo->sourceIcon;
dragFinishCallData.dragData = dtDragInfo->dragData;
_DtDndCallCallbackList(dragContext, dtDragInfo->dragFinishCallback,
(XtPointer)&dragFinishCallData);
/*
* Restore motif default drag cursors
*/
_DtDndSelectDragSource(dragContext, DtDND_DRAG_SOURCE_DEFAULT, NULL);
/*
* Invoke protocol specific convertFinish
*/
(*dtDragInfo->transfer->methods->convertFinish)(dtDragInfo);
/*
* Free data structures allocated during the drag
*/
XtFree((char *)dtDragInfo->transfer->targets);
XtFree((char *)dtDragInfo->transfer);
XtFree((char *)dtDragInfo->dragConvertCallback);
XtFree((char *)dtDragInfo->dragFinishCallback);
XtFree((char *)dtDragInfo->dragDropFinishCallback);
XtFree((char *)dtDragInfo->dropFinishCallback);
if (dtDragInfo->dropOnRootCallback != NULL) {
XtFree((char *)dtDragInfo->topLevelEnterCallback);
XtFree((char *)dtDragInfo->topLevelLeaveCallback);
XtFree((char *)dtDragInfo->dropStartCallback);
}
XtFree((char *)dtDragInfo->dropOnRootCallback);
XtFree((char *)dtDragInfo->dragData);
XtFree((char *)dtDragInfo);
}
/*
* dndTopLevelEnterCallback -- Support for drop-on-root callback.
* When a drop-on-root callback has been set, determines if
* the drag has entered the root window (or equivalents)
* and sneakily changes Motif's idea that the root is an
* invalid drop site to think that it's really a valid one.
* Also updates dtDragInfo.inRoot as needed.
*/
static void
dndTopLevelEnterCallback(
Widget dragContext,
XtPointer clientData,
XtPointer callData)
{
XmTopLevelEnterCallbackStruct *xmEnterInfo =
(XmTopLevelEnterCallbackStruct *) callData;
DtDragInfo *dtDragInfo = (DtDragInfo *) clientData;
XmDragContext xmDragContext = (XmDragContext) dragContext;
XmDragOverShellWidget dragOverShell = xmDragContext->drag.curDragOver;
if (xmEnterInfo->window == RootWindowOfScreen(xmEnterInfo->screen) ||
dtDragInfo->backdropWindow == xmEnterInfo->window ) {
dragOverShell->drag.cursorState = XmVALID_DROP_SITE;
_XmDragOverChange((Widget)dragOverShell,
dragOverShell->drag.cursorState);
dtDragInfo->inRoot = True;
} else {
dtDragInfo->inRoot = False;
}
}
/*
* dndTopLevelLeaveCallback -- Support for drop-on-root callback.
* When a drop-on-root callback has been set, determines if
* the drag is exiting the root window and restores Motif's
* internal state back to thinking that the root window is
* an invalid drop site. We don't update dtDragInfo->inRoot
* here since the top-level-leave callback is called before
* the drop callback which needs to know if we're in the root
* or not.
*/
static void
dndTopLevelLeaveCallback(
Widget dragContext,
XtPointer clientData,
XtPointer callData)
{
XmTopLevelLeaveCallbackStruct *xmLeaveInfo =
(XmTopLevelLeaveCallbackStruct *) callData;
DtDragInfo *dtDragInfo = (DtDragInfo *) clientData;
XmDragContext xmDragContext = (XmDragContext) dragContext;
XmDragOverShellWidget dragOverShell = xmDragContext->drag.curDragOver;
if (xmLeaveInfo->window == RootWindowOfScreen(xmLeaveInfo->screen) ||
dtDragInfo->backdropWindow == xmLeaveInfo->window ) {
dragOverShell->drag.cursorState = XmINVALID_DROP_SITE;
_XmDragOverChange((Widget)dragOverShell,
dragOverShell->drag.cursorState);
}
}