/*
* Motif
*
* Copyright (c) 1987-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
*/
/*
* HISTORY
*/
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$TOG: DragC.c /main/29 1997/10/07 12:19:52 cshi $"
#endif
#endif
/* (c) Copyright 1991, 1992 HEWLETT-PACKARD COMPANY */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifndef DEFAULT_WM_TIMEOUT
#define DEFAULT_WM_TIMEOUT 5000
#endif
#include <X11/Xatom.h>
#include <X11/cursorfont.h>
#include <Xm/AtomMgr.h>
#include <Xm/DisplayP.h>
#include <Xm/DragOverSP.h>
#include <Xm/GadgetP.h>
#include <Xm/ManagerP.h>
#include <Xm/PrimitiveP.h>
#include <Xm/TransltnsP.h>
#include <Xm/VendorSP.h>
#include "XmI.h"
#include "DisplayI.h"
#include "DragBSI.h"
#include "DragCI.h"
#include "DragICCI.h"
#include "DragOverSI.h"
#include "MessagesI.h"
#include "TraversalI.h"
#include "VendorSI.h"
#include <stdio.h>
#ifndef X_NOT_STDC_ENV
#include <stdlib.h>
#endif
/* force the multi screen support on */
#define MULTI_SCREEN_DONE
#ifdef DEBUG
#define Warning(str) XmeWarning(NULL, str)
#else
#define Warning(str) /*EMPTY*/
#endif
#define BIGSIZE ((Dimension)32767)
#define MESSAGE1 _XmMMsgDragC_0001
#define MESSAGE2 _XmMMsgDragC_0002
#define MESSAGE3 _XmMMsgDragC_0003
#define MESSAGE4 _XmMMsgDragC_0004
#define MESSAGE5 _XmMMsgDragC_0005
#define MESSAGE6 _XmMMsgDragC_0006
typedef struct _MotionEntryRec{
int type;
Time time;
Window window;
Window subwindow;
Position x, y;
unsigned int state;
} MotionEntryRec, *MotionEntry;
#define STACKMOTIONBUFFERSIZE 120
typedef struct _MotionBufferRec{
XmDragReceiverInfo currReceiverInfo;
Cardinal count;
MotionEntryRec entries[STACKMOTIONBUFFERSIZE];
} MotionBufferRec, *MotionBuffer;
#define MOTIONFILTER 16
/******** Static Function Declarations ********/
static void GetRefForeground(
Widget widget,
int offset,
XrmValue *value) ;
static void CopyRefForeground(
Widget widget,
int offset,
XrmValue *value) ;
static void GetRefBackground(
Widget widget,
int offset,
XrmValue *value) ;
static void DragContextInitialize(
Widget req,
Widget new_w,
ArgList args,
Cardinal *numArgs) ;
static Boolean DragContextSetValues(
Widget old,
Widget ref,
Widget new_w,
Arg *args,
Cardinal *numArgs) ;
static void DragContextDestroy(
Widget w) ;
static void DragContextClassInitialize( void ) ;
static void DragContextClassPartInitialize( WidgetClass ) ;
static Window GetClientWindow(
Display *dpy,
Window win,
Atom atom) ;
static void ValidateDragOver(
XmDragContext dc,
unsigned char oldStyle,
unsigned char newStyle) ;
static XmDragReceiverInfo FindReceiverInfo(
XmDragContext dc,
Window win) ;
static void GetDestinationInfo(
XmDragContext dc,
Window root,
Window win) ;
static void GetScreenInfo(
XmDragContext dc) ;
static void SendDragMessage(
XmDragContext dc,
Window destination,
unsigned char messageType) ;
static void GenerateClientCallback(
XmDragContext dc,
unsigned char reason) ;
static void DropLoseIncrSelection(
Widget w,
Atom *selection,
XtPointer clientData) ;
static void DropLoseSelection(
Widget w,
Atom *selection) ;
static void DragDropFinish(
XmDragContext dc) ;
static Boolean DropConvertIncrCallback(
Widget w,
Atom *selection,
Atom *target,
Atom *typeRtn,
XtPointer *valueRtn,
unsigned long *lengthRtn,
int *formatRtn,
unsigned long *maxLengthRtn,
XtPointer clientData,
XtRequestId *requestID) ;
static Boolean DropConvertCallback(
Widget w,
Atom *selection,
Atom *target,
Atom *typeRtn,
XtPointer *valueRtn,
unsigned long *lengthRtn,
int *formatRtn) ;
static void DragStartProto(
XmDragContext dc) ;
static void NewScreen(
XmDragContext dc,
Window newRoot) ;
static void LocalNotifyHandler(
Widget w,
XtPointer client,
XtPointer call) ;
static void ExternalNotifyHandler(
Widget w,
XtPointer client,
XtPointer call) ;
static void InitiatorMsgHandler(
Widget w,
XtPointer clientData,
XEvent *event,
Boolean *dontSwallow) ;
static void SiteEnteredWithLocalSource(
Widget w,
XtPointer client,
XtPointer call) ;
static void SiteLeftWithLocalSource(
Widget w,
XtPointer client,
XtPointer call) ;
static void OperationChanged(
Widget w,
XtPointer client,
XtPointer call) ;
static void SiteMotionWithLocalSource(
Widget w,
XtPointer client,
XtPointer call) ;
static void DropStartConfirmed(
Widget w,
XtPointer client,
XtPointer call) ;
static Widget GetShell(
Widget w) ;
static void InitDropSiteManager(
XmDragContext dc) ;
static void TopWindowsReceived(
Widget w,
XtPointer client_data,
Atom *selection,
Atom *type,
XtPointer value,
unsigned long *length,
int *format) ;
static void DragStart(
XmDragContext dc,
Widget src,
XEvent *event) ;
static void DragStartWithTracking(
XmDragContext dc) ;
static void UpdateMotionBuffer(
XmDragContext dc,
MotionBuffer mb,
XEvent *event) ;
static void DragMotionProto(
XmDragContext dc,
Window root,
Window subWindow) ;
static void ProcessMotionBuffer(
XmDragContext dc,
MotionBuffer mb) ;
static void DragMotion(
Widget w,
XEvent *event,
String *params,
Cardinal *numParams) ;
static void DragKey(
Widget w,
XEvent *event,
String *params,
Cardinal *numParams) ;
static void DropStartTimeout(
XtPointer clientData,
XtIntervalId *id) ;
static void DropFinishTimeout(
XtPointer clientData,
XtIntervalId *id) ;
static void FinishAction(
XmDragContext dc,
XEvent *ev) ;
static void CheckModifiers(
XmDragContext dc,
unsigned int state) ;
static void IgnoreButtons(
Widget w,
XEvent *event,
String *params,
Cardinal *numParams) ;
static void CancelDrag(
Widget w,
XEvent *event,
String *params,
Cardinal *numParams) ;
static void HelpDrag(
Widget w,
XEvent *event,
String *params,
Cardinal *numParams) ;
static void FinishDrag(
Widget w,
XEvent *event,
String *params,
Cardinal *numParams) ;
static void InitiatorMainLoop(
XtPointer clientData,
XtIntervalId *id) ;
static void DragCancel(
XmDragContext dc) ;
static void CalculateDragOperation(
XmDragContext dc) ;
static void cancelDrag(
Widget w,
XtPointer client,
XtPointer call) ;
static void noMoreShell (
Widget w,
XtPointer client,
XtPointer call) ;
/******** End Static Function Declarations ********/
static XtActionsRec dragContextActions[] =
{
{"FinishDrag" , FinishDrag },
{"CancelDrag" , CancelDrag },
{"HelpDrag" , HelpDrag },
{"DragMotion" , DragMotion },
{"DragKey" , DragKey },
{"IgnoreButtons" , IgnoreButtons },
};
static XmConst unsigned char protocolMatrix[7][6] = {
/*
*
* Rows are initiator styles, Columns are receiver styles.
*
* Receiver NO DO PP P PD D
* Initiator -------------------------------
* NO | NO | NO | NO | NO | NO | NO |
* DO | NO | DO | DO | DO | DO | DO |
* PP | NO | DO | P | P | P | D |
* P | NO | DO | P | P | P | DO |
* PD | NO | DO | D | P | D | D |
* D | NO | DO | D | DO | D | D |
* PR | NO | DO | P | P | D | D |
*/
{ /* Initiator == XmDRAG_NONE == 0 */
XmDRAG_NONE, XmDRAG_NONE, XmDRAG_NONE,
XmDRAG_NONE, XmDRAG_NONE, XmDRAG_NONE,
},
{ /* Initiator == DROP_ONLY == 1 */
XmDRAG_NONE, XmDRAG_DROP_ONLY, XmDRAG_DROP_ONLY,
XmDRAG_DROP_ONLY, XmDRAG_DROP_ONLY, XmDRAG_DROP_ONLY,
},
{ /* Initiator == PREFER_PREREG == 2 */
XmDRAG_NONE, XmDRAG_DROP_ONLY, XmDRAG_PREREGISTER,
XmDRAG_PREREGISTER, XmDRAG_PREREGISTER, XmDRAG_DYNAMIC,
},
{ /* Initiator == PREREG == 3 */
XmDRAG_NONE, XmDRAG_DROP_ONLY, XmDRAG_PREREGISTER,
XmDRAG_PREREGISTER, XmDRAG_PREREGISTER, XmDRAG_DROP_ONLY,
},
{ /* Initiator == PREFER_DYNAMIC == 4 */
XmDRAG_NONE, XmDRAG_DROP_ONLY, XmDRAG_DYNAMIC,
XmDRAG_PREREGISTER, XmDRAG_DYNAMIC, XmDRAG_DYNAMIC,
},
{ /* Initiator == XmDRAG_DYNAMIC == 5 */
XmDRAG_NONE, XmDRAG_DROP_ONLY, XmDRAG_DYNAMIC,
XmDRAG_DROP_ONLY, XmDRAG_DYNAMIC, XmDRAG_DYNAMIC,
},
{ /* Initiator == DRAG_RECEIVER == 6 */
XmDRAG_NONE, XmDRAG_DROP_ONLY, XmDRAG_PREREGISTER,
XmDRAG_PREREGISTER, XmDRAG_DYNAMIC, XmDRAG_DYNAMIC,
},
};
/***************************************************************************
*
* Default values for resource lists
*
***************************************************************************/
#define Offset(x) (XtOffsetOf(XmDragContextRec, x))
static XtResource dragContextResources[] =
{
{
XmNsourceWidget, XmCSourceWidget, XmRWidget,
sizeof(Widget), Offset(drag.sourceWidget),
XmRImmediate, (XtPointer)NULL,
},
{
XmNexportTargets, XmCExportTargets, XmRAtomList,
sizeof(Atom *), Offset(drag.exportTargets),
XmRImmediate, (XtPointer)NULL,
},
{
XmNnumExportTargets, XmCNumExportTargets, XmRInt,
sizeof(Cardinal), Offset(drag.numExportTargets),
XmRImmediate, (XtPointer)0,
},
{
XmNconvertProc, XmCConvertProc, XmRFunction,
sizeof(XmConvertSelectionRec), Offset(drag.convertProc),
XmRImmediate, (XtPointer)NULL,
},
{
XmNclientData, XmCClientData, XmRPointer,
sizeof(XtPointer), Offset(drag.clientData),
XmRImmediate, (XtPointer)NULL,
},
{
XmNincremental, XmCIncremental, XmRBoolean,
sizeof(Boolean), Offset(drag.incremental),
XmRImmediate, (XtPointer)NULL,
},
{
XmNdragOperations, XmCDragOperations, XmRUnsignedChar,
sizeof(unsigned char), Offset(drag.dragOperations),
XmRImmediate, (XtPointer)(XmDROP_COPY | XmDROP_MOVE),
},
{
XmNsourceCursorIcon, XmCSourceCursorIcon,
XmRWidget, sizeof(Widget),
Offset(drag.sourceCursorIcon), XmRImmediate, (XtPointer)NULL,
},
{
XmNsourcePixmapIcon, XmCSourcePixmapIcon,
XmRWidget, sizeof(Widget),
Offset(drag.sourcePixmapIcon), XmRImmediate, (XtPointer)NULL,
},
{
XmNstateCursorIcon, XmCStateCursorIcon,
XmRWidget, sizeof(Widget),
Offset(drag.stateCursorIcon), XmRImmediate, (XtPointer)NULL,
},
{
XmNoperationCursorIcon, XmCOperationCursorIcon,
XmRWidget, sizeof(Widget),
Offset(drag.operationCursorIcon), XmRImmediate, (XtPointer)NULL,
},
{
XmNcursorBackground, XmCCursorBackground, XmRPixel,
sizeof(Pixel), Offset(drag.cursorBackground), XmRCallProc,
(XtPointer)GetRefBackground,
},
{
XmNcursorForeground, XmCCursorForeground, XmRPixel,
sizeof(Pixel), Offset(drag.cursorForeground), XmRCallProc, (XtPointer)GetRefForeground,
},
{
XmNvalidCursorForeground, XmCValidCursorForeground, XmRPixel,
sizeof(Pixel), Offset(drag.validCursorForeground), XmRCallProc, (XtPointer)CopyRefForeground,
},
{
XmNinvalidCursorForeground, XmCInvalidCursorForeground,
XmRPixel, sizeof(Pixel), Offset(drag.invalidCursorForeground),
XmRCallProc, (XtPointer)CopyRefForeground,
},
{
XmNnoneCursorForeground, XmCNoneCursorForeground, XmRPixel,
sizeof(Pixel), Offset(drag.noneCursorForeground),
XmRCallProc, (XtPointer)CopyRefForeground,
},
{
XmNdropSiteEnterCallback, XmCCallback, XmRCallback,
sizeof(XtCallbackList), Offset(drag.siteEnterCallback),
XmRImmediate, (XtPointer)NULL,
},
{
XmNdropSiteLeaveCallback, XmCCallback, XmRCallback,
sizeof(XtCallbackList), Offset(drag.siteLeaveCallback),
XmRImmediate, (XtPointer)NULL,
},
{
XmNtopLevelEnterCallback, XmCCallback, XmRCallback,
sizeof(XtCallbackList), Offset(drag.topLevelEnterCallback),
XmRImmediate, (XtPointer)NULL,
},
{
XmNdragMotionCallback, XmCCallback, XmRCallback,
sizeof(XtCallbackList), Offset(drag.dragMotionCallback),
XmRImmediate, (XtPointer)NULL,
},
{
XmNtopLevelLeaveCallback, XmCCallback, XmRCallback,
sizeof(XtCallbackList), Offset(drag.topLevelLeaveCallback),
XmRImmediate, (XtPointer)NULL,
},
{
XmNdropStartCallback, XmCCallback, XmRCallback,
sizeof(XtCallbackList), Offset(drag.dropStartCallback),
XmRImmediate, (XtPointer)NULL,
},
{
XmNdragDropFinishCallback, XmCCallback, XmRCallback,
sizeof(XtCallbackList), Offset(drag.dragDropFinishCallback),
XmRImmediate, (XtPointer)NULL,
},
{
XmNdropFinishCallback, XmCCallback, XmRCallback,
sizeof(XtCallbackList), Offset(drag.dropFinishCallback),
XmRImmediate, (XtPointer)NULL,
},
{
XmNoperationChangedCallback, XmCCallback, XmRCallback,
sizeof(XtCallbackList), Offset(drag.operationChangedCallback),
XmRImmediate, (XtPointer)NULL,
},
{
XmNblendModel, XmCBlendModel,
XmRBlendModel,
sizeof(unsigned char), Offset(drag.blendModel),
XmRImmediate, (XtPointer)XmBLEND_ALL,
},
{
XmNsourceIsExternal, XmCSourceIsExternal, XmRBoolean,
sizeof(Boolean), Offset(drag.sourceIsExternal),
XmRImmediate, (XtPointer)False,
},
{
XmNsourceWindow, XmCSourceWindow, XmRWindow,
sizeof(Window), Offset(drag.srcWindow),
XmRImmediate, (XtPointer)None,
},
{
XmNstartTime, XmCStartTime, XmRInt,
sizeof(Time), Offset(drag.dragStartTime),
XmRImmediate, (XtPointer)0,
},
{
XmNiccHandle, XmCICCHandle, XmRAtom,
sizeof(Atom), Offset(drag.iccHandle),
XmRImmediate, (XtPointer)None,
},
};
externaldef(xmdragcontextclassrec)
XmDragContextClassRec xmDragContextClassRec = {
{
(WidgetClass) &coreClassRec, /* superclass */
"XmDragContext", /* class_name */
sizeof(XmDragContextRec), /* size */
DragContextClassInitialize, /* Class Initializer */
DragContextClassPartInitialize, /* class_part_init */
FALSE, /* Class init'ed ? */
DragContextInitialize, /* initialize */
NULL, /* initialize_notify */
XtInheritRealize, /* realize */
dragContextActions, /* actions */
XtNumber(dragContextActions), /* num_actions */
dragContextResources, /* resources */
XtNumber(dragContextResources),/* resource_count */
NULLQUARK, /* xrm_class */
FALSE, /* compress_motion */
XtExposeNoCompress, /* compress_exposure */
FALSE, /* compress_enterleave */
FALSE, /* visible_interest */
DragContextDestroy, /* destroy */
NULL, /* resize */
NULL, /* expose */
DragContextSetValues, /* set_values */
NULL, /* set_values_hook */
NULL, /* set_values_almost */
NULL, /* get_values_hook */
NULL, /* accept_focus */
XtVersion, /* intrinsics version */
NULL, /* callback offsets */
_XmDragC_defaultTranslations, /* tm_table */
NULL, /* query_geometry */
NULL, /* display_accelerator */
NULL, /* extension */
},
{ /* dragContext */
DragStart, /* start */
DragCancel, /* cancel */
NULL, /* extension record */
},
};
externaldef(dragContextclass) WidgetClass
xmDragContextClass = (WidgetClass) &xmDragContextClassRec;
/*ARGSUSED*/
static void
GetRefForeground(
Widget widget,
int offset,
XrmValue *value )
{
static Pixel pixel;
XmDragContext dc = (XmDragContext)widget;
Widget sw = dc->drag.sourceWidget;
pixel = BlackPixelOfScreen(XtScreen(widget));
value->addr = (XPointer)(&pixel);
value->size = sizeof(Pixel);
if (sw) {
if (XmIsGadget(sw))
pixel = ((XmManagerWidget)(XtParent(sw)))->manager.foreground;
else if (XmIsPrimitive(sw))
pixel = ((XmPrimitiveWidget)sw)->primitive.foreground;
else if (XmIsManager(sw))
pixel = ((XmManagerWidget)sw)->manager.foreground;
}
} /* GetRefForeground */
/*ARGSUSED*/
static void
CopyRefForeground(
Widget widget,
int offset,
XrmValue *value )
{
XmDragContext dc = (XmDragContext)widget;
value->addr = (XPointer)(&dc->drag.cursorForeground);
value->size = sizeof(Pixel);
} /* CopyRefForeground */
/*ARGSUSED*/
static void
GetRefBackground(
Widget widget,
int offset,
XrmValue *value )
{
static Pixel pixel;
XmDragContext dc = (XmDragContext)widget;
Widget sw = dc->drag.sourceWidget;
pixel = WhitePixelOfScreen(XtScreen(dc));
value->addr = (XPointer)(&pixel);
value->size = sizeof(Pixel);
if (sw) {
if (XmIsGadget(sw))
pixel = ((XmManagerWidget)(XtParent(sw)))->core.background_pixel;
else
pixel = sw->core.background_pixel;
}
} /* GetRefBackground */
/*ARGSUSED*/
static void
DragContextInitialize(
Widget req,
Widget new_w,
ArgList args,
Cardinal *numArgs )
{
XmDragContext dc = (XmDragContext)new_w;
dc->drag.roundOffTime = 50;
dc->drag.dragFinishTime =
dc->drag.dropFinishTime = 0;
dc->drag.inDropSite = False;
dc->drag.dragTimerId = (XtIntervalId) NULL;
dc->drag.activeBlendModel = dc->drag.blendModel;
dc->drag.trackingMode = XmDRAG_TRACK_MOTION ;
dc->drag.curDragOver = dc->drag.origDragOver = NULL;
dc->drag.startX = dc->drag.startY = 0;
dc->drag.SaveEventMask = 0L;
InitDropSiteManager(dc);
if (dc->drag.exportTargets) {
unsigned int size;
size = sizeof(Atom) * dc->drag.numExportTargets;
dc->drag.exportTargets = (Atom *)
_XmAllocAndCopy(dc->drag.exportTargets, size);
}
dc->core.x =
dc->core.y = 0;
dc->core.width =
dc->core.height = 16;
/* pixel values in drag context refer to the source widget's colormap */
if (dc->drag.sourceWidget) {
Widget sw = dc->drag.sourceWidget;
dc->core.colormap = XmIsGadget(sw) ?
XtParent(sw)->core.colormap : sw->core.colormap;
}
XtRealizeWidget((Widget)dc);
dc->drag.currReceiverInfo =
dc->drag.receiverInfos = NULL;
dc->drag.numReceiverInfos =
dc->drag.maxReceiverInfos = 0;
dc->drag.dragDropCancelEffect = False;
}
/*ARGSUSED*/
static Boolean
DragContextSetValues(
Widget old,
Widget ref,
Widget new_w,
Arg *args,
Cardinal *numArgs )
{
XmDragContext oldDC = (XmDragContext)old;
XmDragContext newDC = (XmDragContext)new_w;
XmDragOverShellWidget dos = newDC->drag.curDragOver;
if (oldDC->drag.exportTargets != newDC->drag.exportTargets) {
if (oldDC->drag.exportTargets) /* should have been freed */
XtFree( (char *)oldDC->drag.exportTargets);
if (newDC->drag.exportTargets) {
unsigned int size;
size = sizeof(Atom) * newDC->drag.numExportTargets;
newDC->drag.exportTargets = (Atom *)
_XmAllocAndCopy(newDC->drag.exportTargets, size);
}
}
if ( oldDC->drag.operationCursorIcon != newDC->drag.operationCursorIcon ||
oldDC->drag.sourceCursorIcon != newDC->drag.sourceCursorIcon ||
oldDC->drag.sourcePixmapIcon != newDC->drag.sourcePixmapIcon ||
oldDC->drag.stateCursorIcon != newDC->drag.stateCursorIcon ||
oldDC->drag.cursorBackground != newDC->drag.cursorBackground ||
oldDC->drag.cursorForeground != newDC->drag.cursorForeground ||
oldDC->drag.noneCursorForeground != newDC->drag.noneCursorForeground ||
oldDC->drag.invalidCursorForeground !=
newDC->drag.invalidCursorForeground ||
oldDC->drag.validCursorForeground !=
newDC->drag.validCursorForeground) {
_XmDragOverChange((Widget)dos, dos->drag.cursorState);
}
return False;
}
static void
DragContextDestroy(
Widget w )
{
XmDragContext dc = (XmDragContext)w;
Cardinal i;
/* Fix CR 5556: Restore root event mask saved at DragStart time */
if (0 != dc->drag.SaveEventMask)
XSelectInput(XtDisplay(dc), dc->drag.currWmRoot, dc->drag.SaveEventMask);
if (dc->drag.exportTargets)
XtFree((char *)dc->drag.exportTargets);
dc->drag.exportTargets = NULL;
if (dc->drag.dragTimerId)
{
XtRemoveTimeOut(dc->drag.dragTimerId);
dc->drag.dragTimerId = (XtIntervalId) NULL;
}
if (dc->drag.receiverInfos)
{
#ifdef MULTI_SCREEN_DONE
if (dc->drag.trackingMode != XmDRAG_TRACK_MOTION)
{
EventMask mask;
XmDragReceiverInfo info;
for (i = 1; i < dc->drag.numReceiverInfos; i++)
{
info = &(dc->drag.receiverInfos[i]);
if (info->shell)
mask = XtBuildEventMask(info->shell);
else
mask = 0;
XSelectInput(XtDisplay(w), info->window, mask);
}
}
#endif /* MULTI_SCREEN_DONE */
XtFree((char *)dc->drag.receiverInfos);
}
}
static void
DragContextClassInitialize( void )
{
/* The applications should call XtRegisterGrabAction. */
}
static void
DragContextClassPartInitialize( WidgetClass wc )
{
_XmFastSubclassInit (wc, XmDRAG_CONTEXT_BIT);
}
static Window
GetClientWindow(
Display *dpy,
Window win,
Atom atom )
{
Window root, parent;
Window *children;
unsigned int nchildren;
int i;
Atom type = None;
int format;
unsigned long nitems, after;
unsigned char *data = NULL;
Window inf = 0;
XGetWindowProperty(dpy, win, atom, 0, 0, False, AnyPropertyType,
&type, &format, &nitems, &after, &data);
if (data)
XFree(data);
if (type)
return win;
else {
if (!XQueryTree(dpy, win, &root, &parent, &children, &nchildren) ||
(nchildren == 0))
return 0;
for (i = nchildren - 1; i >= 0; i--) {
if ((inf = GetClientWindow(dpy, children[i], atom)) != 0) {
XFree(children);
return inf;
}
}
XFree(children);
}
return 0;
}
static void
ValidateDragOver(
XmDragContext dc,
unsigned char oldStyle,
unsigned char newStyle )
{
Arg args[1];
XmDisplay xmDisplay = (XmDisplay)XtParent(dc);
unsigned char initiator = XmDRAG_NONE;
initiator = xmDisplay->display.dragInitiatorProtocolStyle;
if (newStyle != oldStyle)
{
/*
* If we're not still waiting to hear from the window manager,
* and we're not running dynamic, then we can grab.
*/
if ((dc->drag.trackingMode != XmDRAG_TRACK_WM_QUERY_PENDING) &&
(newStyle != XmDRAG_DYNAMIC) &&
(initiator != XmDRAG_DYNAMIC) &&
(initiator != XmDRAG_PREFER_DYNAMIC))
{
if (!dc->drag.serverGrabbed)
{
XGrabServer(XtDisplay(dc));
dc->drag.serverGrabbed = True;
XtSetArg(args[0], XmNdragOverMode, XmPIXMAP);
XtSetValues( (Widget)dc->drag.curDragOver, args, 1);
}
}
else
{
if (dc->drag.serverGrabbed)
{
XUngrabServer(XtDisplay(dc));
dc->drag.serverGrabbed = False;
if (xmDisplay -> display.displayHasShapeExtension)
XtSetArg(args[0], XmNdragOverMode, XmDRAG_WINDOW);
else
XtSetArg(args[0], XmNdragOverMode, XmCURSOR);
XtSetValues( (Widget)dc->drag.curDragOver, args, 1);
}
}
}
}
static XmDragReceiverInfo
FindReceiverInfo(
XmDragContext dc,
Window win )
{
Cardinal i;
XmDragReceiverInfo info = NULL;
for (i = 0; i < dc->drag.numReceiverInfos; i++) {
info = &dc->drag.receiverInfos[i];
if ((info->frame == win) || (info->window == win))
break;
}
if (i < dc->drag.numReceiverInfos)
return info;
else
return NULL;
}
XmDragReceiverInfo
_XmAllocReceiverInfo(
XmDragContext dc )
{
Cardinal offset = 0;
if (dc->drag.currReceiverInfo) {
offset = (Cardinal) (dc->drag.currReceiverInfo -
dc->drag.receiverInfos);
}
if (dc->drag.numReceiverInfos == dc->drag.maxReceiverInfos) {
dc->drag.maxReceiverInfos = dc->drag.maxReceiverInfos*2 + 2;
dc->drag.receiverInfos = (XmDragReceiverInfoStruct *)
XtRealloc((char*)dc->drag.receiverInfos,
dc->drag.maxReceiverInfos *
sizeof(XmDragReceiverInfoStruct));
}
if (offset)
dc->drag.currReceiverInfo = &(dc->drag.receiverInfos[offset]);
dc->drag.rootReceiverInfo = dc->drag.receiverInfos;
return &(dc->drag.receiverInfos[dc->drag.numReceiverInfos++]);
}
/* Find a window with WM_STATE, else return win itself, as per ICCCM */
/*ARGSUSED*/
static void
GetDestinationInfo(
XmDragContext dc,
Window root,
Window win )
{
Window clientWin = win;
Display *dpy = XtDisplayOfObject((Widget) dc);
Atom WM_STATE = XInternAtom(dpy, XmSWM_STATE, True);
unsigned char oldStyle = dc->drag.activeProtocolStyle;
XmDragReceiverInfo currReceiverInfo;
dc->drag.crossingTime = dc->drag.lastChangeTime;
currReceiverInfo =
dc->drag.currReceiverInfo = FindReceiverInfo(dc, win);
/*
* check for bootstrap case
*/
if ((dc->drag.trackingMode == XmDRAG_TRACK_MOTION) &&
(XtWindow(dc->drag.srcShell) == win) &&
(!currReceiverInfo ||
(currReceiverInfo->frame == currReceiverInfo->window))) {
Window currRoot = dc->drag.currWmRoot;
int root_x, root_y;
Position rel_x, rel_y;
/*
* set frame (win) to something reasonable
*/
rel_x = dc->drag.startX - dc->drag.srcShell->core.x;
rel_y = dc->drag.startY - dc->drag.srcShell->core.y;
if (rel_x < 0) rel_x = 0;
if (rel_y < 0) rel_y = 0;
(void) XTranslateCoordinates(XtDisplayOfObject((Widget) dc),
win, currRoot,
rel_x, rel_y,
&root_x, &root_y,
&win);
if (currReceiverInfo)
currReceiverInfo->frame = win;
}
if (currReceiverInfo == NULL) {
if (clientWin == win) {
if ((clientWin = GetClientWindow(dpy, win, WM_STATE)) == 0)
clientWin = win;
}
currReceiverInfo =
dc->drag.currReceiverInfo = _XmAllocReceiverInfo(dc);
currReceiverInfo->frame = win;
currReceiverInfo->window = clientWin;
currReceiverInfo->shell = XtWindowToWidget(dpy, clientWin);
}
/*
* we fetch the root info in NewScreen
*/
if (currReceiverInfo != dc->drag.rootReceiverInfo /* is it the root ? */) {
if (!currReceiverInfo->shell) {
if (_XmGetDragReceiverInfo(dpy,
currReceiverInfo->window,
currReceiverInfo))
{
switch (currReceiverInfo->dragProtocolStyle) {
case XmDRAG_PREREGISTER:
case XmDRAG_PREFER_PREREGISTER:
case XmDRAG_PREFER_DYNAMIC:
break;
case XmDRAG_DYNAMIC:
case XmDRAG_DROP_ONLY:
case XmDRAG_NONE:
/* free the data returned by the icc layer */
_XmFreeDragReceiverInfo(currReceiverInfo->iccInfo);
break;
}
}
} else {
XmDisplay xmDisplay = (XmDisplay)XtParent(dc);
/*
* We only have a protocol style if we have drop sites.
*/
if (_XmDropSiteShell(dc->drag.currReceiverInfo->shell))
currReceiverInfo->dragProtocolStyle =
xmDisplay->display.dragReceiverProtocolStyle;
else
currReceiverInfo->dragProtocolStyle = XmDRAG_NONE;
currReceiverInfo->xOrigin = dc->drag.currReceiverInfo->shell->core.x;
currReceiverInfo->yOrigin = dc->drag.currReceiverInfo->shell->core.y;
currReceiverInfo->width = dc->drag.currReceiverInfo->shell->core.width;
currReceiverInfo->height = dc->drag.currReceiverInfo->shell->core.height;
currReceiverInfo->depth = dc->drag.currReceiverInfo->shell->core.depth;
currReceiverInfo->iccInfo = NULL;
}
}
/*
* If we're still waiting on the window manager, then don't mess
* with the active protocol style.
*/
if (dc->drag.trackingMode != XmDRAG_TRACK_WM_QUERY_PENDING)
{
dc->drag.activeProtocolStyle =
_XmGetActiveProtocolStyle((Widget)dc);
ValidateDragOver(dc, oldStyle, dc->drag.activeProtocolStyle);
}
}
static void
GetScreenInfo(
XmDragContext dc )
{
Display *dpy = XtDisplay(dc);
Window root = RootWindowOfScreen(XtScreen(dc->drag.curDragOver));
XmDragReceiverInfo rootInfo;
/*
* the rootInfo is the first entry in the receiverInfo
* array
*/
if (dc->drag.numReceiverInfos == 0) {
dc->drag.rootReceiverInfo =
rootInfo = _XmAllocReceiverInfo(dc);
} else {
dc->drag.rootReceiverInfo =
rootInfo = dc->drag.receiverInfos;
}
rootInfo->frame = None;
rootInfo->window = root;
rootInfo->shell = XtWindowToWidget(dpy, root);
rootInfo->xOrigin = rootInfo->yOrigin = 0;
rootInfo->width = XWidthOfScreen(dc->drag.currScreen);
rootInfo->height = XHeightOfScreen(dc->drag.currScreen);
rootInfo->depth = DefaultDepthOfScreen(dc->drag.currScreen);
rootInfo->iccInfo = NULL;
if (_XmGetDragReceiverInfo(dpy, root, rootInfo))
{
switch (rootInfo->dragProtocolStyle) {
case XmDRAG_PREREGISTER:
case XmDRAG_PREFER_PREREGISTER:
case XmDRAG_PREFER_DYNAMIC:
break;
case XmDRAG_DYNAMIC:
case XmDRAG_DROP_ONLY:
case XmDRAG_NONE:
/* free the data returned by the icc layer */
_XmFreeDragReceiverInfo(rootInfo->iccInfo);
break;
}
}
}
static void
SendDragMessage(
XmDragContext dc,
Window destination,
unsigned char messageType )
{
XmDropSiteManagerObject dsm = (XmDropSiteManagerObject)
_XmGetDropSiteManagerObject((XmDisplay)(XtParent(dc)));
XmICCCallbackStruct callbackRec;
int reason = _XmMessageTypeToReason(messageType);
callbackRec.any.event = NULL;
if ((dc->drag.activeProtocolStyle == XmDRAG_NONE) ||
((dc->drag.activeProtocolStyle == XmDRAG_DROP_ONLY) &&
(reason != XmCR_DROP_START)))
return;
switch(callbackRec.any.reason = reason) {
case XmCR_TOP_LEVEL_ENTER:
{
XmTopLevelEnterCallback callback =
(XmTopLevelEnterCallback)&callbackRec;
callback->timeStamp = dc->drag.lastChangeTime;
callback->window = dc->drag.srcWindow;
callback->dragProtocolStyle = dc->drag.activeProtocolStyle;
callback->screen = dc->drag.currScreen;
callback->x = dc->drag.currReceiverInfo->xOrigin;
callback->y = dc->drag.currReceiverInfo->yOrigin;
callback->iccHandle = dc->drag.iccHandle;
}
break;
case XmCR_TOP_LEVEL_LEAVE:
{
XmTopLevelLeaveCallback callback =
(XmTopLevelLeaveCallback)&callbackRec;
callback->timeStamp = dc->drag.lastChangeTime;
callback->window = dc->drag.srcWindow;
}
break;
case XmCR_DRAG_MOTION:
{
XmDragMotionCallback callback =
(XmDragMotionCallback)&callbackRec;
callback->timeStamp = dc->drag.lastChangeTime;
callback->x = dc->core.x;
callback->y = dc->core.y;
callback->operation = dc->drag.operation;
callback->operations = dc->drag.operations;
/* Outgoing motion; be conservative */
callback->dropSiteStatus = XmNO_DROP_SITE;
}
break;
case XmCR_OPERATION_CHANGED:
{
XmOperationChangedCallback callback =
(XmOperationChangedCallback)&callbackRec;
callback->timeStamp = dc->drag.lastChangeTime;
callback->operation = dc->drag.operation;
callback->operations = dc->drag.operations;
}
break;
case XmCR_DROP_START:
{
XmDropStartCallback callback =
(XmDropStartCallback)&callbackRec;
callback->timeStamp = dc->drag.dragFinishTime;
callback->operation = dc->drag.operation;
callback->operations = dc->drag.operations;
callback->dropAction = dc->drag.dragCompletionStatus;
callback->dropSiteStatus = dsm->dropManager.curDropSiteStatus;
callback->x = dc->core.x;
callback->y = dc->core.y;
callback->iccHandle = dc->drag.iccHandle;
callback->window = XtWindow(dc->drag.srcShell);
}
break;
default:
break;
}
/*
* if we're the initiator and the destination isn't us and either
* its the drop message or the dynamic protocol send it to the wire
*/
if ((!dc->drag.currReceiverInfo->shell) &&
(!dc->drag.sourceIsExternal /* sanity check */) &&
((dc->drag.activeProtocolStyle == XmDRAG_DYNAMIC) ||
(reason == XmCR_DROP_START)))
{
_XmSendICCCallback(XtDisplayOfObject((Widget) dc), destination,
&callbackRec, XmICC_INITIATOR_EVENT);
}
else {
XtPointer data;
XmDragTopLevelClientDataStruct topLevelData;
XmDragMotionClientDataStruct motionData;
if ((reason == XmCR_TOP_LEVEL_ENTER) ||
(reason == XmCR_TOP_LEVEL_LEAVE) ||
(reason == XmCR_DROP_START)){
topLevelData.destShell = dc->drag.currReceiverInfo->shell;
topLevelData.sourceIsExternal = dc->drag.sourceIsExternal;
topLevelData.iccInfo = dc->drag.currReceiverInfo->iccInfo;
topLevelData.xOrigin =
(Position)(dc->drag.currReceiverInfo->xOrigin);
topLevelData.yOrigin = (Position)
(dc->drag.currReceiverInfo->yOrigin);
topLevelData.width = (Dimension)
(dc->drag.currReceiverInfo->width);
topLevelData.height = (Dimension)
(dc->drag.currReceiverInfo->height);
topLevelData.window = dc->drag.currReceiverInfo->window;
topLevelData.dragOver = (Widget)dc->drag.curDragOver;
data = (XtPointer)&topLevelData;
}
else if ((reason == XmCR_DRAG_MOTION) ||
(reason == XmCR_OPERATION_CHANGED)) {
motionData.window = dc->drag.currReceiverInfo->window;
motionData.dragOver = (Widget)dc->drag.curDragOver;
data = (XtPointer)&motionData;
}
else {
data = NULL;
}
_XmDSMUpdate(dsm,
(XtPointer)data,
(XtPointer)&callbackRec);
}
}
static void
GenerateClientCallback(
XmDragContext dc,
unsigned char reason )
{
XmICCCallbackStruct callbackRec;
XtCallbackList callbackList = NULL;
callbackRec.any.event = NULL;
switch(callbackRec.any.reason = reason) {
case XmCR_TOP_LEVEL_ENTER:
if ((callbackList = dc->drag.topLevelEnterCallback) != NULL) {
XmTopLevelEnterCallback callback =
(XmTopLevelEnterCallback)&callbackRec;
callback->timeStamp = dc->drag.lastChangeTime;
callback->window = dc->drag.currReceiverInfo->window;
callback->dragProtocolStyle =
dc->drag.activeProtocolStyle;
callback->screen = dc->drag.currScreen;
callback->iccHandle = dc->drag.iccHandle;
callback->x = dc->drag.currReceiverInfo->xOrigin;
callback->y = dc->drag.currReceiverInfo->yOrigin;
}
break;
case XmCR_TOP_LEVEL_LEAVE:
if ((callbackList = dc->drag.topLevelLeaveCallback) != NULL) {
XmTopLevelLeaveCallback callback =
(XmTopLevelLeaveCallback)&callbackRec;
callback->timeStamp = dc->drag.lastChangeTime;
callback->screen = dc->drag.currScreen;
callback->window = dc->drag.currReceiverInfo->window;
}
break;
case XmCR_DRAG_MOTION:
if ((callbackList = dc->drag.dragMotionCallback) != NULL) {
XmDragMotionCallback callback =
(XmDragMotionCallback)&callbackRec;
callback->timeStamp = dc->drag.lastChangeTime;
callback->x = dc->core.x;
callback->y = dc->core.y;
callback->operation = dc->drag.operation;
callback->operations = dc->drag.operations;
/*
* If we're over DropOnly client, be optimistic.
*/
if (dc->drag.activeProtocolStyle == XmDRAG_DROP_ONLY)
{
callback->dropSiteStatus = XmVALID_DROP_SITE;
}
else
{
/*
* Otherwise, we're over the root (see
* DragMotionProto), and there's no drop site
* under us.
*/
callback->dropSiteStatus = XmNO_DROP_SITE;
}
}
break;
case XmCR_OPERATION_CHANGED:
if ((callbackList = dc->drag.operationChangedCallback) != NULL) {
XmOperationChangedCallback callback =
(XmOperationChangedCallback)&callbackRec;
callback->timeStamp = dc->drag.lastChangeTime;
callback->operation = dc->drag.operation;
callback->operations = dc->drag.operations;
/*
* If we're over DropOnly client, be optimistic.
*/
if (dc->drag.activeProtocolStyle == XmDRAG_DROP_ONLY)
{
callback->dropSiteStatus = XmVALID_DROP_SITE;
}
else
{
/*
* Otherwise, we're over the root (see
* DragMotionProto), and there's no drop site
* under us.
*/
callback->dropSiteStatus = XmNO_DROP_SITE;
}
}
break;
case XmCR_DROP_SITE_ENTER:
{
XmeWarning((Widget)dc, MESSAGE1);
}
break;
case XmCR_DROP_SITE_LEAVE:
{
XmDropSiteLeaveCallback callback =
(XmDropSiteLeaveCallback)&callbackRec;
callback->timeStamp = dc->drag.lastChangeTime;
}
break;
default:
break;
}
if (callbackList)
{
XtCallCallbackList( (Widget)dc, callbackList, &callbackRec);
if (callbackList == dc->drag.dragMotionCallback)
{
XmDragOverShellWidget dos = dc->drag.curDragOver;
XmDragMotionCallback callback =
(XmDragMotionCallback)&callbackRec;
dc->drag.operation = callback->operation;
dc->drag.operations = callback->operations;
if (dos->drag.cursorState != callback->dropSiteStatus)
{
dos->drag.cursorState = callback->dropSiteStatus;
_XmDragOverChange((Widget)dos, dos->drag.cursorState);
}
}
}
}
/*ARGSUSED*/
static void
DropLoseIncrSelection(
Widget w,
Atom *selection,
XtPointer clientData )
{
DropLoseSelection( w, selection) ;
}
static void
DropLoseSelection(
Widget w,
Atom *selection)
{
XmDragContext dc ;
if (!(dc = (XmDragContext) _XmGetDragContextFromHandle( w, *selection)))
{
XmeWarning(w, MESSAGE2) ;
}
if (dc && dc->drag.dropFinishTime == 0)
{
XmeWarning(w, MESSAGE3) ;
}
}
static void
DragDropFinish(
XmDragContext dc )
{
Widget w = NULL;
XmDropSiteManagerObject dsm = (XmDropSiteManagerObject)
_XmGetDropSiteManagerObject((XmDisplay)(XtParent(dc)));
/* Handle completion */
if (dc->drag.dropFinishCallback) {
XmDropFinishCallbackStruct cb;
cb.reason = XmCR_DROP_FINISH;
cb.event = NULL;
cb.timeStamp = dc->drag.dropFinishTime;
cb.operation = dc->drag.operation;
cb.operations = dc->drag.operations;
cb.dropSiteStatus = dsm->dropManager.curDropSiteStatus;
cb.dropAction = dc->drag.dragCompletionStatus;
cb.completionStatus = dc->drag.dragDropCompletionStatus;
XtCallCallbackList((Widget) dc, dc->drag.dropFinishCallback, &cb);
dc->drag.dragDropCompletionStatus = cb.completionStatus;
}
if (dc->drag.blendModel != XmBLEND_NONE &&
dc->drag.dragDropCancelEffect == False) {
_XmDragOverFinish((Widget)dc->drag.curDragOver,
dc->drag.dragDropCompletionStatus);
}
if (dc->drag.dragDropFinishCallback) {
XmDragDropFinishCallbackStruct cb;
cb.reason = XmCR_DRAG_DROP_FINISH;
cb.event = NULL;
cb.timeStamp = dc->drag.dropFinishTime;
XtCallCallbackList((Widget) dc, dc->drag.dragDropFinishCallback, &cb);
}
/*
* we send this now so that the non-local receiver can clean up
* its dc after everything is done
*/
XtDisownSelection(dc->drag.srcShell,
dc->drag.iccHandle,
dc->drag.dragFinishTime);
_XmFreeMotifAtom((Widget)dc, dc->drag.iccHandle);
XtRemoveEventHandler(dc->drag.srcShell, FocusChangeMask, True,
InitiatorMsgHandler,
(XtPointer)dc);
XtVaGetValues((Widget)dc, XmNsourceWidget, &w, NULL);
if (w)
XtRemoveCallback(w, XmNdestroyCallback, cancelDrag, (XtPointer)dc);
XtDestroyWidget((Widget) dc);
}
/*
* This callback is called when a drag operation needs to be terminated.
* This can occur when the widget whose id is contained in the drag data
* structure is destroyed.
*/
static void
cancelDrag(
Widget w,
XtPointer client,
XtPointer call)
{
Widget dragContext = (Widget)client;
XmDragCancel(dragContext);
}
/*
* This routine is passed as the frontend to the convertProc.
*/
/*VARARGS*/
static Boolean
DropConvertIncrCallback(
Widget w,
Atom *selection,
Atom *target,
Atom *typeRtn,
XtPointer *valueRtn,
unsigned long *lengthRtn,
int *formatRtn,
unsigned long *maxLengthRtn,
XtPointer clientData,
XtRequestId *requestID )
{
enum {
XmATRANSFER_SUCCESS, XmATRANSFER_FAILURE,
XmA_MOTIF_CANCEL_DROP_EFFECT, XmA_MOTIF_DROP, XmATARGETS, NUM_ATOMS };
static char *atom_names[] = {
XmSTRANSFER_SUCCESS, XmSTRANSFER_FAILURE,
XmS_MOTIF_CANCEL_DROP_EFFECT, XmS_MOTIF_DROP, XmSTARGETS };
XmDragContext dc;
Time dropTime;
Boolean returnVal = True;
Boolean success;
Atom atoms[XtNumber(atom_names)];
dropTime = XtGetSelectionRequest(w, *selection, requestID)->time;
if (!(dc = (XmDragContext)
_XmGetDragContextFromHandle(w, *selection))) {
XmeWarning(w, MESSAGE2);
return False;
}
assert(XtNumber(atom_names) == NUM_ATOMS);
XInternAtoms(XtDisplayOfObject((Widget) dc), atom_names,
XtNumber(atom_names), False, atoms);
if ((success = (*target == atoms[XmATRANSFER_SUCCESS])) ||
(*target == atoms[XmATRANSFER_FAILURE]))
{
if (success)
dc->drag.dragDropCompletionStatus = XmDROP_SUCCESS;
else
dc->drag.dragDropCompletionStatus = XmDROP_FAILURE;
*typeRtn = *target;
*lengthRtn = 0;
*formatRtn = 32;
*valueRtn = NULL;
*maxLengthRtn = 0;
/*
* the time is really of the start of the transfer but ...
*/
dc->drag.dropFinishTime = dropTime;
DragDropFinish(dc);
}
else if (*target == atoms[XmA_MOTIF_CANCEL_DROP_EFFECT])
{
dc->drag.dragDropCancelEffect = True;
}
else /* normal transfer */
{
Atom motifDrop = atoms[XmA_MOTIF_DROP];
returnVal = (Boolean)((*(dc->drag.convertProc.sel_incr))
((Widget)dc,
&motifDrop,
target,
typeRtn,
valueRtn,
lengthRtn,
formatRtn,
maxLengthRtn,
clientData,
requestID));
}
/* add code to handle TARGET target automatically if not there yet */
if ((! returnVal) && (*target == atoms[XmATARGETS])) {
int len = sizeof(Atom) * dc->drag.numExportTargets;
if (dc->drag.incremental & 0x2) {
dc->drag.incremental = 1;
*valueRtn = NULL;
*lengthRtn = 0;
} else {
*valueRtn = XtMalloc(len);
memmove(*valueRtn, dc->drag.exportTargets, len);
*lengthRtn = dc->drag.numExportTargets;
dc->drag.incremental = 3;
}
*formatRtn = 32;
*typeRtn = XA_ATOM;
returnVal = True;
}
return returnVal;
}
/*
* This routine is passed as the frontend to the convertProc.
*/
/*VARARGS*/
static Boolean
DropConvertCallback(
Widget w,
Atom *selection,
Atom *target,
Atom *typeRtn,
XtPointer *valueRtn,
unsigned long *lengthRtn,
int *formatRtn )
{
enum {
XmATRANSFER_SUCCESS, XmATRANSFER_FAILURE,
XmA_MOTIF_CANCEL_DROP_EFFECT, XmA_MOTIF_DROP, XmATARGETS, NUM_ATOMS };
static char *atom_names[] = {
XmSTRANSFER_SUCCESS, XmSTRANSFER_FAILURE,
XmS_MOTIF_CANCEL_DROP_EFFECT, XmS_MOTIF_DROP, XmSTARGETS };
XmDragContext dc;
Time dropTime;
Boolean returnVal = True;
Boolean success;
Atom atoms[XtNumber(atom_names)];
dropTime = XtGetSelectionRequest(w, *selection, NULL)->time;
if (!(dc = (XmDragContext)
_XmGetDragContextFromHandle(w, *selection))) {
XmeWarning(w, MESSAGE2);
return False;
}
assert(XtNumber(atom_names) == NUM_ATOMS);
XInternAtoms(XtDisplayOfObject((Widget) dc), atom_names,
XtNumber(atom_names), False, atoms);
if ((success = (*target == atoms[XmATRANSFER_SUCCESS])) ||
(*target == atoms[XmATRANSFER_FAILURE]))
{
if (success)
dc->drag.dragDropCompletionStatus = XmDROP_SUCCESS;
else
dc->drag.dragDropCompletionStatus = XmDROP_FAILURE;
*typeRtn = *target;
*lengthRtn = 0;
*formatRtn = 32;
*valueRtn = NULL;
/*
* the time is really of the start of the transfer but ...
*/
dc->drag.dropFinishTime = dropTime;
DragDropFinish(dc);
}
else if (*target == atoms[XmA_MOTIF_CANCEL_DROP_EFFECT])
{
dc->drag.dragDropCancelEffect = True;
}
else /* normal transfer */
{
Atom motifDrop = atoms[XmA_MOTIF_DROP];
returnVal = (Boolean)
((*(dc->drag.convertProc.sel))
((Widget)dc,
&motifDrop,
target,
typeRtn,
valueRtn,
lengthRtn,
formatRtn));
}
/* add code to handle TARGET target automatically if not there yet */
if ((! returnVal) && (*target == atoms[XmATARGETS])) {
int len = sizeof(Atom) * dc->drag.numExportTargets;
*valueRtn = XtMalloc(len);
memmove(*valueRtn, dc->drag.exportTargets, len);
*lengthRtn = dc->drag.numExportTargets;
*formatRtn = 32;
*typeRtn = XA_ATOM;
returnVal = True;
}
return returnVal;
}
/*ARGSUSED*/
static void
DragStartProto(
XmDragContext dc)
{
/*
* bootstrap the top_level_window code
*/
_XmWriteInitiatorInfo((Widget)dc);
GetDestinationInfo(dc,
RootWindowOfScreen(XtScreen(dc)),
XtWindow(dc->drag.srcShell));
GenerateClientCallback(dc, XmCR_TOP_LEVEL_ENTER);
SendDragMessage(dc, dc->drag.currReceiverInfo->window, XmTOP_LEVEL_ENTER);
SendDragMessage(dc, dc->drag.currReceiverInfo->window, XmDRAG_MOTION);
}
static void
NewScreen(
XmDragContext dc,
Window newRoot)
{
XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(dc));
Cardinal i;
Arg args[8];
Widget old = (Widget) (dc->drag.curDragOver);
/* Find the new screen number */
for (i = 0; i < XScreenCount(XtDisplayOfObject((Widget) dc)); i++)
if (RootWindow(XtDisplayOfObject((Widget) dc), i) == newRoot)
break;
dc->drag.currScreen =
ScreenOfDisplay(XtDisplayOfObject((Widget) dc), i);
dc->drag.currWmRoot = RootWindowOfScreen(dc->drag.currScreen);
/* Build a new one */
i = 0;
/*
* If this is the first call, tracking mode will be querypending
* and we have to come up in cursor mode. Otherwise, we come up
* in cursor for dynamic and pixmap for preregister.
*/
if ((dc->drag.trackingMode == XmDRAG_TRACK_WM_QUERY_PENDING) ||
(dc->drag.activeProtocolStyle == XmDRAG_DYNAMIC))
{
if (dpy -> display.displayHasShapeExtension)
XtSetArg(args[i], XmNdragOverMode, XmDRAG_WINDOW);
else
XtSetArg(args[i], XmNdragOverMode, XmCURSOR);
i++;
}
else
{
XtSetArg(args[i], XmNdragOverMode, XmPIXMAP); i++;
}
XtSetArg(args[i], XmNhotX, dc->core.x); i++;
XtSetArg(args[i], XmNhotY, dc->core.y); i++;
XtSetArg(args[i], XmNbackgroundPixmap, None); i++;
XtSetArg(args[i], XmNscreen, dc->drag.currScreen);i++;
XtSetArg(args[i], XmNdepth, DefaultDepthOfScreen(dc->drag.currScreen));i++;
XtSetArg(args[i], XmNcolormap,
DefaultColormapOfScreen(dc->drag.currScreen));i++;
XtSetArg(args[i], XmNvisual, DefaultVisualOfScreen(dc->drag.currScreen));i++;
/*
* As popup child(ren) of the dc, the drag over(s) will
* automatically destroyed by Xt when the dc is destroyed.
* Isn't that handy?
*/
dc->drag.curDragOver = (XmDragOverShellWidget)
XtCreatePopupShell("dragOver", xmDragOverShellWidgetClass,
(Widget) dc, args, i);
if (dc->drag.currScreen == XtScreen(dc->drag.srcShell))
_XmDragOverSetInitialPosition((Widget)dc->drag.curDragOver,
dc->drag.startX, dc->drag.startY);
if (old != NULL) {
if (old != (Widget) (dc->drag.origDragOver))
XtDestroyWidget(old);
else
_XmDragOverHide((Widget)dc->drag.origDragOver, 0, 0, NULL);
}
GetScreenInfo(dc);
if (dc->drag.origDragOver == NULL)
{
dc->drag.origDragOver = dc->drag.curDragOver;
}
if (dc->drag.trackingMode == XmDRAG_TRACK_MOTION)
{
EventMask mask = _XmDRAG_EVENT_MASK(dc);
if (XGrabPointer(XtDisplayOfObject((Widget) dc->drag.curDragOver),
RootWindowOfScreen(XtScreen(dc->drag.curDragOver)),
False,
mask,
GrabModeSync,
GrabModeAsync,
None,
_XmDragOverGetActiveCursor((Widget)dc->drag.curDragOver),
dc->drag.lastChangeTime) != GrabSuccess)
Warning(MESSAGE4);
XAllowEvents(XtDisplayOfObject((Widget) dc->drag.srcShell),
SyncPointer,
dc->drag.lastChangeTime);
}
}
/*ARGSUSED*/
static void
LocalNotifyHandler(
Widget w,
XtPointer client,
XtPointer call )
{
XmDropSiteManagerObject dsm = (XmDropSiteManagerObject)w;
XmDragContext dc = (XmDragContext)client;
switch(((XmAnyICCCallback)call)->reason) {
case XmCR_DROP_SITE_ENTER:
SiteEnteredWithLocalSource((Widget)dsm, (XtPointer)dc, (XtPointer)call);
break;
case XmCR_DROP_SITE_LEAVE:
/* SiteLeftWithLocalSource expect to find an
* XmDropSiteEnterPendingCallbackStruct, so upgrade the
* XmDropSiteLeaveCallbackStruct.
*/
{
XmDropSiteLeaveCallbackStruct *cb =
(XmDropSiteLeaveCallbackStruct *) call;
XmDropSiteEnterPendingCallbackStruct new_call;
new_call.reason = cb->reason;
new_call.event = cb->event;
new_call.timeStamp = cb->timeStamp;
new_call.enter_pending = False;
SiteLeftWithLocalSource((Widget) dsm, (XtPointer)dc,
(XtPointer) &new_call);
break;
}
case XmCR_DRAG_MOTION:
SiteMotionWithLocalSource((Widget)dsm, (XtPointer)dc, (XtPointer)call);
break;
case XmCR_OPERATION_CHANGED:
OperationChanged((Widget)dsm, (XtPointer)dc, (XtPointer)call);
break;
case XmCR_DROP_START:
DropStartConfirmed((Widget)dsm, (XtPointer)dc, (XtPointer)call);
default:
break;
}
}
/*
* sends replies to drag messages
*/
/*ARGSUSED*/
static void
ExternalNotifyHandler(
Widget w,
XtPointer client,
XtPointer call )
{
XmDragContext dc = (XmDragContext)client;
XmAnyICCCallback cb = (XmAnyICCCallback)call;
switch(cb->reason) {
case XmCR_DROP_SITE_ENTER:
case XmCR_DROP_SITE_LEAVE:
case XmCR_DRAG_MOTION:
case XmCR_OPERATION_CHANGED:
case XmCR_DROP_START:
/*
* send a message to the external source
*/
_XmSendICCCallback(XtDisplayOfObject((Widget) dc),
dc->drag.srcWindow,
(XmICCCallback)cb,
XmICC_RECEIVER_EVENT);
break;
default:
XmeWarning((Widget)dc, MESSAGE5);
break;
}
}
/*
* catches replies on drag messages
*/
/*ARGSUSED*/
static void
InitiatorMsgHandler(
Widget w,
XtPointer clientData,
XEvent *event,
Boolean *dontSwallow )
{
XmDragContext dc =(XmDragContext)clientData;
XmICCCallbackStruct callbackRec;
if ((dc && (event->type != ClientMessage)) ||
(!_XmICCEventToICCCallback((XClientMessageEvent *)event,
&callbackRec, XmICC_RECEIVER_EVENT)) ||
(dc->drag.dragStartTime > callbackRec.any.timeStamp) ||
(dc->drag.crossingTime > callbackRec.any.timeStamp))
return;
LocalNotifyHandler(w, (XtPointer)dc, (XtPointer)&callbackRec);
}
/*ARGSUSED*/
static void
SiteEnteredWithLocalSource(
Widget w,
XtPointer client,
XtPointer call )
{
XmDragContext dc = (XmDragContext)client;
XmDropSiteEnterCallbackStruct *cb = (XmDropSiteEnterCallbackStruct *)call;
CalculateDragOperation(dc);
/* check against the current location of the pointer */
if (dc->drag.siteEnterCallback) {
XtCallCallbackList((Widget) dc, dc->drag.siteEnterCallback, cb);
}
dc->drag.operation = cb->operation;
dc->drag.operations = cb->operations;
dc->drag.inDropSite = True;
_XmDragOverChange((Widget)dc->drag.curDragOver, cb->dropSiteStatus);
}
/*ARGSUSED*/
static void
SiteLeftWithLocalSource(
Widget w,
XtPointer client,
XtPointer call )
{
XmDragContext dc = (XmDragContext)client;
XmDropSiteEnterPendingCallbackStruct *cb =
(XmDropSiteEnterPendingCallbackStruct *)call;
dc->drag.inDropSite = False;
if (dc->drag.siteLeaveCallback) {
XtCallCallbackList((Widget) dc, dc->drag.siteLeaveCallback,
(XmDropSiteLeaveCallbackStruct *)cb);
}
CalculateDragOperation(dc);
/*
* Don't forward laggard echo leaves to dragUnder
*/
if (dc->drag.dragFinishTime == 0 && !cb->enter_pending)
_XmDragOverChange((Widget)dc->drag.curDragOver, XmNO_DROP_SITE);
}
/*ARGSUSED*/
static void
OperationChanged(
Widget w,
XtPointer client,
XtPointer call )
{
XmDragContext dc = (XmDragContext)client;
XmOperationChangedCallbackStruct *cb = (XmOperationChangedCallbackStruct *)call;
if (dc->drag.operationChangedCallback) {
XtCallCallbackList((Widget) dc, dc->drag.operationChangedCallback, cb);
}
dc->drag.operation = cb->operation;
dc->drag.operations = cb->operations;
_XmDragOverChange((Widget)dc->drag.curDragOver, cb->dropSiteStatus);
}
/*ARGSUSED*/
static void
SiteMotionWithLocalSource(
Widget w,
XtPointer client,
XtPointer call )
{
XmDragContext dc = (XmDragContext)client;
XmDragMotionCallbackStruct *cb = (XmDragMotionCallbackStruct *)call;
if (dc->drag.dragMotionCallback) {
XtCallCallbackList((Widget) dc, dc->drag.dragMotionCallback, cb);
}
/* Application should not be able to change callback data so
* don't call _XmDragOverChange(), this will result in better
* drag performance.
*/
}
/*ARGSUSED*/
static void
DropStartConfirmed(
Widget w,
XtPointer client,
XtPointer call )
{
XmDragContext dc = (XmDragContext)client;
XmDropStartCallbackStruct *cb = (XmDropStartCallbackStruct *)call;
XtAppContext appContext = XtWidgetToApplicationContext((Widget)dc);
if (dc->drag.dragTimerId) {
XtRemoveTimeOut(dc->drag.dragTimerId);
dc->drag.dragTimerId = (XtIntervalId) NULL;
}
/* Add a long timeout in case the drop site dies. */
dc->drag.dragTimerId =
XtAppAddTimeOut(appContext,
XtAppGetSelectionTimeout(appContext) * 10,
DropFinishTimeout,
(XtPointer)dc);
if (dc->drag.dropStartCallback) {
XtCallCallbackList( (Widget)dc, dc->drag.dropStartCallback, cb);
}
dc->drag.dragCompletionStatus = cb->dropAction;
switch(dc->drag.dragCompletionStatus) {
case XmDROP:
case XmDROP_INTERRUPT:
case XmDROP_HELP:
break;
case XmDROP_CANCEL:
break;
}
}
static Widget
GetShell(
Widget w )
{
while (w && !XtIsShell(w))
w = XtParent(w);
return w;
}
static void
InitDropSiteManager(
XmDragContext dc )
{
XmDropSiteManagerObject dsm;
Arg args[4];
Cardinal i = 0;
dsm = _XmGetDropSiteManagerObject((XmDisplay)(XtParent(dc)));
XtSetArg(args[i], XmNclientData, dc); i++;
if (dc->drag.sourceIsExternal) {
XtSetArg(args[i], XmNnotifyProc, ExternalNotifyHandler); i++;
}
else {
XtSetArg(args[i], XmNnotifyProc, LocalNotifyHandler); i++;
}
XtSetValues((Widget)dsm, args, i);
}
/*ARGSUSED*/
static void
TopWindowsReceived(
Widget w,
XtPointer client_data,
Atom *selection,
Atom *type,
XtPointer value,
unsigned long *length,
int *format )
{
XmDragContext dc = (XmDragContext)client_data;
XmDisplay dd = (XmDisplay) w;
Cardinal i;
XmDragReceiverInfo currInfo, startInfo;
Window *clientWindows;
unsigned char oldStyle;
if (dd->display.activeDC != dc) {
/* Too late... */
return;
}
/* CR 6337. Must call DragOverChange if the blendModel
changes. This doesn't happen often, only in certain
cases involving PREREGISTER */
if (dc -> drag.blendModel != dc -> drag.activeBlendModel) {
dc->drag.blendModel = dc->drag.activeBlendModel;
_XmDragOverChange((Widget)dc->drag.curDragOver, XmNO_DROP_SITE);
}
#ifdef MULTI_SCREEN_DONE
if ((*length != 0) && (*format == 32) && (*type == XA_WINDOW)) {
/*
* we make a receiverInfo array one larger than the number of
* client windows since we keep the root info in array[0].
*/
if (dc->drag.numReceiverInfos >= 1)
startInfo = dc->drag.receiverInfos;
else
startInfo = NULL;
dc->drag.numReceiverInfos =
dc->drag.maxReceiverInfos = *length + 1;
dc->drag.receiverInfos = (XmDragReceiverInfo)
XtCalloc(dc->drag.maxReceiverInfos, sizeof(XmDragReceiverInfoStruct));
clientWindows = (Window *)value;
if (startInfo) {
memcpy((char *)dc->drag.receiverInfos,
(char *)startInfo,
sizeof(XmDragReceiverInfoStruct));
dc->drag.rootReceiverInfo = dc->drag.receiverInfos;
XtFree((char *)startInfo);
}
#ifdef DEBUG
else
Warning("we don't have startInfo when we should\n");
#endif /* DEBUG */
for (i = 1; i < dc->drag.numReceiverInfos; i++) {
currInfo = &dc->drag.receiverInfos[i];
currInfo->window = clientWindows[i-1];
currInfo->shell = XtWindowToWidget(XtDisplay(dc),
currInfo->window);
if (currInfo->shell == NULL) {
XSelectInput(XtDisplay(dc),
currInfo->window,
EnterWindowMask | LeaveWindowMask);
}
}
/*
* set the currReceiver to the srcShell since that's where
* we're confined to
*/
dc->drag.currReceiverInfo =
FindReceiverInfo(dc, XtWindow(dc->drag.srcShell));
dc->drag.trackingMode = XmDRAG_TRACK_WM_QUERY;
oldStyle = dc->drag.activeProtocolStyle;
dc->drag.activeProtocolStyle =
_XmGetActiveProtocolStyle((Widget)dc);
ValidateDragOver(dc, oldStyle, dc->drag.activeProtocolStyle);
}
else
#endif /* MULTI_SCREEN_DONE */
{
EventMask mask;
Window confineWindow;
Cursor cursor;
dc->drag.trackingMode = XmDRAG_TRACK_MOTION;
GetDestinationInfo(dc,
dc->drag.currWmRoot,
dc->drag.currReceiverInfo->window);
#ifndef MULTI_SCREEN_DONE
confineWindow = RootWindowOfScreen(XtScreen(dc));
#else
confineWindow = None;
#endif /* MULTI_SCREEN_DONE */
/*
* we need to regrab so that the confine window can be changed
* from the source window. If there was another value for
* trackingMode like XmDRAG_TRACK_WM_QUERY_FAILED we could do
* this in DragStartWithTracking
*/
mask = _XmDRAG_EVENT_MASK(dc);
cursor = _XmDragOverGetActiveCursor((Widget)dc->drag.curDragOver);
if (XGrabPointer(XtDisplayOfObject((Widget) dc),
RootWindowOfScreen(XtScreen(dc)),
False,
mask,
GrabModeSync,
GrabModeAsync,
confineWindow,
cursor,
dc->drag.lastChangeTime) != GrabSuccess)
Warning(MESSAGE4);
}
#ifdef MULTI_SCREEN_DONE
if (value)
XtFree((char *)value);
#endif /* MULTI_SCREEN_DONE */
DragStartWithTracking(dc);
}
/* ARGSUSED */
static void
DragStart(
XmDragContext dc,
Widget src,
XEvent *event )
{
XmDisplay dd;
unsigned char activeProtocolStyle;
unsigned int state = event->xbutton.state;
EventMask mask;
Window saveWindow;
Window confineWindow;
Cursor cursor = None;
dd = (XmDisplay)XtParent(dc);
dd->display.activeDC = dc;
dd->display.userGrabbed = True;
dc->drag.crossingTime =
dc->drag.dragStartTime =
dc->drag.lastChangeTime = event->xbutton.time;
dc->drag.startX = dc->core.x = event->xbutton.x_root;
dc->drag.startY = dc->core.y = event->xbutton.y_root;
dc->drag.curDragOver = NULL;
dc->drag.origDragOver = NULL;
dc->drag.srcShell = GetShell(src);
dc->drag.srcWindow = XtWindow(dc->drag.srcShell);
dc->drag.iccHandle = _XmAllocMotifAtom((Widget)dc, dc->drag.dragStartTime);
if (dc->drag.incremental)
XtOwnSelectionIncremental(dc->drag.srcShell,
dc->drag.iccHandle,
dc->drag.dragStartTime,
DropConvertIncrCallback,
DropLoseIncrSelection,
NULL, NULL, dc->drag.clientData);
else
XtOwnSelection(dc->drag.srcShell,
dc->drag.iccHandle,
dc->drag.dragStartTime,
DropConvertCallback,
DropLoseSelection,
NULL);
dc->drag.serverGrabbed = False;
dc->drag.sourceIsExternal = False;
dc->drag.activeProtocolStyle = activeProtocolStyle =
_XmGetActiveProtocolStyle((Widget)dc);
switch (dc->drag.activeProtocolStyle)
{
case XmDRAG_PREREGISTER:
dc->drag.activeProtocolStyle = XmDRAG_DYNAMIC;
case XmDRAG_DYNAMIC:
break;
case XmDRAG_DROP_ONLY:
dc->drag.activeProtocolStyle = XmDRAG_NONE;
case XmDRAG_NONE:
break;
}
/* must be either DYNAMIC or NONE at this point */
/*
* start out with the default operations in effective operations
*/
dc->drag.lastEventState = state;
CalculateDragOperation(dc);
dc->drag.sourceIsExternal = False;
/*
* if we're in query_pending mode then initialize the
* currReceiverInfo to us
*/
if (dc->drag.trackingMode == XmDRAG_TRACK_MOTION) {
dc->drag.activeProtocolStyle = activeProtocolStyle;
#ifndef MULTI_SCREEN_DONE
confineWindow = RootWindowOfScreen(XtScreen(dc));
#else
confineWindow = None;
} else { /* XmDRAG_TRACK_WM_QUERY */
dc->drag.trackingMode = XmDRAG_TRACK_WM_QUERY_PENDING;
confineWindow = XtWindow(dc->drag.srcShell);
}
#endif /* MULTI_SCREEN_DONE */
if (dc->drag.trackingMode == XmDRAG_TRACK_WM_QUERY_PENDING &&
activeProtocolStyle == XmDRAG_PREREGISTER) {
dc->drag.blendModel = XmBLEND_NONE;
}
NewScreen(dc, RootWindowOfScreen(XtScreen(dc)));
XtInsertEventHandler(dc->drag.srcShell, FocusChangeMask, True,
InitiatorMsgHandler,
(XtPointer)dc,
XtListHead);
mask = _XmDRAG_EVENT_MASK(dc);
/*
* we grab on the Xt pointer so that Xt doesn't interfere with us.
* Also once we have the WM_QUERY capability this will work.
* Otherwise we need to grab on the root so we can track the
* changes in sub_window and infer the top_level crossings
*/
/*
* some more sleaze to get around the ungrab. Since we can't rely
* on the caller to have done an owner_events true (for Xt), we need to
* guarantee that the release event goes to us. The grab window
* must be viewable so we can't use the dc window
*/
saveWindow = dc->core.window;
cursor = _XmDragOverGetActiveCursor((Widget)dc->drag.curDragOver);
dc->core.window = RootWindowOfScreen(XtScreen(dc));
if ((XtGrabPointer((Widget)dc,
False,
(unsigned int) mask,
GrabModeSync,
GrabModeAsync,
confineWindow,
cursor,
dc->drag.dragStartTime) != GrabSuccess) ||
(XGrabPointer(XtDisplayOfObject((Widget) dc),
RootWindowOfScreen(XtScreen(dc)),
False,
mask,
GrabModeSync,
GrabModeAsync,
confineWindow,
cursor,
dc->drag.dragStartTime) != GrabSuccess) ||
(XGrabKeyboard(XtDisplayOfObject((Widget) dc),
RootWindowOfScreen(XtScreen(dc)),
False,
GrabModeSync,
GrabModeAsync,
dc->drag.dragStartTime) != GrabSuccess))
Warning(MESSAGE4);
_XmAddGrab((Widget)dc, True, False);
dc->core.window = saveWindow;
/* Begin fixing OSF CR 5556 */
/*
* Add ButtonMotionMask to the already set-up event mask for root window.
* This gets reinstalled in DragContextDestroy()
*/
{
XWindowAttributes xwa;
XGetWindowAttributes(XtDisplay(dc), dc->drag.currWmRoot, &xwa);
dc->drag.SaveEventMask = xwa.your_event_mask;
XSelectInput(XtDisplay(dc),
dc->drag.currWmRoot,
xwa.your_event_mask | ButtonMotionMask);
}
/* End fixing OSF CR 5556 */
if (dc->drag.trackingMode == XmDRAG_TRACK_WM_QUERY_PENDING) {
enum { XmA_MOTIF_WM_QUERY, XmA_MOTIF_WM_ALL_CLIENTS, NUM_ATOMS };
static char *atom_names[] = {
XmS_MOTIF_WM_QUERY, XmS_MOTIF_WM_ALL_CLIENTS };
Atom atoms[XtNumber(atom_names)];
assert(XtNumber(atom_names) == NUM_ATOMS);
XInternAtoms(XtDisplay(dc), atom_names, XtNumber(atom_names),
False, atoms);
XtGetSelectionValue((Widget)dd,
atoms[XmA_MOTIF_WM_QUERY],
atoms[XmA_MOTIF_WM_ALL_CLIENTS],
TopWindowsReceived,
(XtPointer)dc,
dc->drag.dragStartTime);
XAllowEvents(XtDisplayOfObject((Widget) dc->drag.srcShell),
SyncPointer,
dc->drag.dragStartTime);
}
else
DragStartWithTracking(dc);
XSync(XtDisplay(dc), False);
XtAppAddTimeOut( XtWidgetToApplicationContext( (Widget)dc),
0, InitiatorMainLoop,
(XtPointer)(&dd->display.activeDC));
}
/* ARGSUSED */
static void
DragStartWithTracking(
XmDragContext dc)
{
if (dc->drag.dragFinishTime)
return;
if (dc->drag.trackingMode == XmDRAG_TRACK_WM_QUERY) {
EventMask mask = _XmDRAG_EVENT_MASK(dc);
Window confineWindow;
Cursor cursor;
#ifndef MULTI_SCREEN_DONE
confineWindow = RootWindowOfScreen(XtScreen(dc));
#else
confineWindow = None;
#endif
cursor = _XmDragOverGetActiveCursor((Widget)dc->drag.curDragOver);
/*
* set owner events to true so that the crossings and motion
* are reported relative to the destination windows. Don't
* tell Xt about it so we can continue to get everything
* reported to the dragContext via the spring-loaded/XtGrab
* interaction. Blegh
*/
if (XGrabPointer(XtDisplayOfObject((Widget) dc),
RootWindowOfScreen(XtScreen(dc)),
True,
mask,
GrabModeSync,
GrabModeAsync,
confineWindow,
cursor,
dc->drag.lastChangeTime) != GrabSuccess)
Warning(MESSAGE4);
}
XAllowEvents(XtDisplayOfObject((Widget) dc->drag.srcShell),
SyncPointer,
dc->drag.lastChangeTime);
}
static void
UpdateMotionBuffer(
XmDragContext dc,
MotionBuffer mb,
XEvent *event)
{
Time time ;
unsigned int state;
Window window, subwindow;
Position x ;
Position y ;
if (dc->drag.currReceiverInfo == NULL)
return;
dc->drag.lastChangeTime = event->xmotion.time;
/*
* we munged the window and subwindow fields before calling
* XtDispatchEvent so we could get the event thru to the
* DragContext. The subwindow field will hold the interesting
* info. The window field is always set (by us) to the DC window.
*/
switch(event->type) {
case MotionNotify:
if (mb->count && ((mb->count % (STACKMOTIONBUFFERSIZE)) == 0)) {
if (mb->count == (STACKMOTIONBUFFERSIZE)){
MotionBuffer oldMb = mb;
Cardinal size;
size = sizeof(MotionBufferRec) +
(STACKMOTIONBUFFERSIZE * sizeof(MotionEntryRec));
mb = (MotionBuffer) XtMalloc(size);
memcpy((char *)mb, (char *)oldMb, sizeof(MotionBufferRec));
}
else {
mb = (MotionBuffer)
XtRealloc((char *)mb,
(sizeof(MotionBufferRec) +
(mb->count + STACKMOTIONBUFFERSIZE) *sizeof(MotionEntryRec)));
}
}
/*
* for right now use the root although this wont work for
* pseudo-roots
*/
time = event->xmotion.time;
state = event->xmotion.state;
x = event->xmotion.x_root;
y = event->xmotion.y_root;
window = event->xmotion.root;
if (dc->drag.trackingMode != XmDRAG_TRACK_MOTION) {
subwindow = mb->currReceiverInfo->window;
}
else {
subwindow = event->xmotion.subwindow;
}
mb->entries[mb->count].time = time;
mb->entries[mb->count].window = window;
mb->entries[mb->count].subwindow = subwindow;
mb->entries[mb->count].state = state;
mb->entries[mb->count].x = x;
mb->entries[mb->count++].y = y;
break;
case EnterNotify:
if ((event->xcrossing.mode == NotifyNormal) &&
(dc->drag.trackingMode != XmDRAG_TRACK_MOTION)) {
XmDragReceiverInfo rInfo;
if ((rInfo = FindReceiverInfo(dc, event->xcrossing.subwindow))
!= NULL)
mb->currReceiverInfo = rInfo;
}
break;
case LeaveNotify:
if ((event->xcrossing.mode == NotifyNormal) &&
(dc->drag.trackingMode != XmDRAG_TRACK_MOTION)) {
XmDragReceiverInfo rInfo;
if ((rInfo = FindReceiverInfo(dc, event->xcrossing.subwindow))
!= NULL) {
if (rInfo == mb->currReceiverInfo)
mb->currReceiverInfo = dc->drag.rootReceiverInfo;
}
}
break;
default:
break;
}
}
static void
DragMotionProto(
XmDragContext dc,
Window root,
Window subWindow )
{
Boolean incrementTimestamp = False;
/*
* We've selected for motion on the root window. This allows us to
* use the subwindow field to know whenever we have left or
* entered a potential top-level window.
*/
if ((root != dc->drag.currWmRoot) ||
((((dc->drag.trackingMode == XmDRAG_TRACK_MOTION) &&
(dc->drag.currReceiverInfo->frame != subWindow))) ||
((dc->drag.trackingMode == XmDRAG_TRACK_WM_QUERY) &&
(dc->drag.currReceiverInfo->window != subWindow))))
{
if (dc->drag.currReceiverInfo->window)
{
if ((dc->drag.activeProtocolStyle != XmDRAG_NONE) &&
(dc->drag.activeProtocolStyle != XmDRAG_DROP_ONLY))
{
/*
* Assumes the root window doesn't contain drop-sites !!!
* Send motion to old window.
*
* ** Old stuff for bootstrap
* ** if (dc->drag.currReceiverInfo->frame)
* ** only send to non-initial windows
*/
/*
* if the receiver is dynamic and we've been
* informed that we're in a drop-site then
* generate a dropsite leave to the initiator. If
* we haven't yet been informed of a drop-site
* enter (due to latency) but one is in the pipes,
* it will be ignored once it gets in based on the
* timestamp being stale.
*
* We'll make sure it's stale by incrementing the
* timestamp by one millisecond. This is a no-no but
* it makes it easy to identify the echo events from
* the receiver. Its also relatively safe until we
* get micro-second response times :-)
*/
if ((dc->drag.activeProtocolStyle == XmDRAG_DYNAMIC) &&
(!dc->drag.currReceiverInfo->shell) &&
(dc->drag.inDropSite))
{
GenerateClientCallback(dc, XmCR_DROP_SITE_LEAVE);
dc->drag.inDropSite = False;
incrementTimestamp = True;
}
SendDragMessage(dc, dc->drag.currReceiverInfo->window,
XmDRAG_MOTION);
SendDragMessage(dc, dc->drag.currReceiverInfo->window,
XmTOP_LEVEL_LEAVE);
}
GenerateClientCallback(dc, XmCR_TOP_LEVEL_LEAVE);
}
if (root != dc->drag.currWmRoot)
NewScreen(dc, root);
GetDestinationInfo(dc, root, subWindow);
/* we should special-case the root window */
if (dc->drag.currReceiverInfo->window)
{
if ((dc->drag.activeProtocolStyle != XmDRAG_NONE) &&
(dc->drag.activeProtocolStyle != XmDRAG_DROP_ONLY))
{
SendDragMessage(dc, dc->drag.currReceiverInfo->window,
XmTOP_LEVEL_ENTER);
}
/* clear iccInfo for dsm's sanity */
dc->drag.currReceiverInfo->iccInfo = NULL;
GenerateClientCallback(dc, XmCR_TOP_LEVEL_ENTER);
}
}
if (dc->drag.currReceiverInfo->window)
{
if ((dc->drag.activeProtocolStyle != XmDRAG_NONE) &&
(dc->drag.activeProtocolStyle != XmDRAG_DROP_ONLY))
SendDragMessage(dc, dc->drag.currReceiverInfo->window,
XmDRAG_MOTION);
else
GenerateClientCallback(dc, XmCR_DRAG_MOTION);
}
else
GenerateClientCallback(dc, XmCR_DRAG_MOTION);
if (incrementTimestamp)
dc->drag.lastChangeTime++;
}
static void
ProcessMotionBuffer(
XmDragContext dc,
MotionBuffer mb )
{
Cardinal incr, i, j, max;
Window protoWindow = None;
incr = (mb->count / MOTIONFILTER);
if (incr == 0) incr = 1;
max = mb->count / incr;
j = (mb->count + incr - 1) % incr;
for (i = 0; i < max; i++, j += incr) {
dc->core.x = mb->entries[j].x;
dc->core.y = mb->entries[j].y;
if (mb->entries[j].state != dc->drag.lastEventState)
CheckModifiers(dc, mb->entries[j].state);
if (dc->drag.currWmRoot != mb->entries[j].window) {
/*
* cause the callbacks to get called so the client can
* change the dragOver visuals
*/
DragMotionProto(dc, mb->entries[j].window, None);
protoWindow = None;
}
else
protoWindow = mb->entries[j].subwindow;
}
_XmDragOverMove((Widget)dc->drag.curDragOver, dc->core.x, dc->core.y);
/* if the protoWindow gotten above is the drag window,
* we can use XTranslateCoordinates to look through the
* one pixel hole (which has just been moved to be under where
* the pointer was), and determine what real window we are over
*/
if (protoWindow == XtWindow(dc->drag.curDragOver))
{
Window currRoot = dc->drag.currWmRoot;
int dummyx, dummyy;
(void) XTranslateCoordinates(XtDisplay(dc), currRoot, currRoot,
dc->core.x, dc->core.y,
&dummyx, &dummyy,
&protoWindow);
}
/*
* actually inform the receiver/initiator that movement has
* occurred
*/
DragMotionProto(dc, dc->drag.currWmRoot, protoWindow);
if (mb->count > STACKMOTIONBUFFERSIZE)
XtFree( (char *)mb);
}
#define IsGrabEvent(ev) \
((ev->type == ButtonPress) ||\
(ev->type == ButtonRelease) ||\
(ev->type == KeyPress) ||\
(ev->type == KeyRelease))
/* ARGSUSED */
static void
DragMotion(
Widget w,
XEvent *event,
String *params,
Cardinal *numParams )
{
XmDragContext dc = (XmDragContext)w;
MotionBufferRec stackBuffer;
MotionBuffer motionBuffer = &stackBuffer;
Boolean grabEvent = False;
stackBuffer.count = 0;
stackBuffer.currReceiverInfo = dc->drag.currReceiverInfo;
UpdateMotionBuffer(dc, motionBuffer,event);
/*
* We need to process all outstanding events of interest
* inline and flush out any stale motion events. Need to
* check for state change events like modifier or button press.
*/
/*
* get any that came in after
*/
while (!grabEvent &&
XCheckMaskEvent(XtDisplayOfObject((Widget) w),
_XmDRAG_EVENT_MASK(dc),
event)) {
grabEvent = IsGrabEvent(event);
if (!grabEvent) {
if (dc->drag.trackingMode != XmDRAG_TRACK_MOTION)
event->xmotion.subwindow = event->xmotion.window;
UpdateMotionBuffer(dc, motionBuffer, event);
}
else
XPutBackEvent(XtDisplay(dc), event);
}
ProcessMotionBuffer(dc, motionBuffer);
XFlush(XtDisplayOfObject((Widget) dc));
}
/* ARGSUSED */
static void
DragKey(
Widget w,
XEvent *event,
String *params,
Cardinal *numParams )
{
char *direction;
int dx, dy;
XKeyEvent *keyevent = (XKeyEvent *) event;
XEvent motionEvent;
XmDisplay dd;
unsigned int state = 0;
dd = (XmDisplay) XtParent(w);
direction = params[0];
if (event == NULL) return;
if (strcmp(direction, "Up") == 0)
{ dx = 0; dy = -1; }
else if (strcmp(direction, "Down") == 0)
{ dx = 0; dy = 1; }
else if (strcmp(direction, "Left") == 0)
{ dx = -1; dy = 0; }
else if (strcmp(direction, "Right") == 0)
{ dx = 1; dy = 0; }
else { /* Update on modifier key changes */
dx = 0; dy = 0;
if (event -> type == KeyPress)
state = keyevent -> state;
}
if (keyevent -> state & ControlMask)
{ dx *= 16; dy *= 16; }
if (dd -> display.enable_warp == False) {
dx = 0; dy = 0;
} else {
XWarpPointer(XtDisplay(w), None, None, 0, 0, 0, 0, dx, dy);
}
/* Send a button2 motion event so that the drag
feedback will happen within DragMotion */
motionEvent.xmotion.type = MotionNotify;
motionEvent.xmotion.window = keyevent -> window;
motionEvent.xmotion.subwindow = keyevent -> subwindow;
motionEvent.xmotion.time = keyevent -> time;
motionEvent.xmotion.root = keyevent -> root;
motionEvent.xmotion.x = XtX(w) + dx;
motionEvent.xmotion.y = XtY(w) + dy;
motionEvent.xmotion.x_root = keyevent -> x_root;
motionEvent.xmotion.y_root = keyevent -> y_root;
motionEvent.xmotion.same_screen = keyevent -> same_screen;
/* Or in the modifier bits if this is an update */
motionEvent.xmotion.state = Button2Mask | state;
motionEvent.xmotion.is_hint = 0;
DragMotion(w, (XEvent *) &motionEvent, NULL, 0);
}
/*ARGSUSED*/
static void
DropStartTimeout(
XtPointer clientData,
XtIntervalId *id )
{
XmDragContext dc = (XmDragContext)clientData;
XmDropStartCallbackStruct callbackRec, *callback = &callbackRec;
XmDropSiteManagerObject dsm = (XmDropSiteManagerObject)
_XmGetDropSiteManagerObject((XmDisplay)(XtParent(dc)));
if (dc->drag.dropStartCallback) {
callback->reason = XmCR_DROP_START;
callback->event = NULL;
callback->timeStamp = dc->drag.dragFinishTime;
callback->operation = dc->drag.operation;
callback->operations = dc->drag.operations;
callback->dropAction = XmDROP_CANCEL;
callback->dropSiteStatus = dsm->dropManager.curDropSiteStatus;
callback->x = dc->core.x;
callback->y = dc->core.y;
callback->iccHandle = dc->drag.iccHandle;
callback->window = XtWindow(dc->drag.srcShell);
XtCallCallbackList((Widget)dc, dc->drag.dropStartCallback, callback);
dc->drag.dragCompletionStatus = callback->dropAction;
dsm->dropManager.curDropSiteStatus = callback->dropSiteStatus;
}
dc->drag.dragDropCompletionStatus = XmDROP_FAILURE;
dc->drag.dropFinishTime = dc->drag.dragFinishTime;
DragDropFinish(dc);
}
/*ARGSUSED*/
static void
DropFinishTimeout(
XtPointer clientData,
XtIntervalId *id )
{
XmDragContext dc = (XmDragContext)clientData;
dc->drag.dragDropCompletionStatus = XmDROP_FAILURE;
dc->drag.dropFinishTime = dc->drag.dragFinishTime;
DragDropFinish(dc);
}
/*ARGSUSED*/
static void
FinishAction(
XmDragContext dc,
XEvent *ev )
{
unsigned int state = 0;
Arg args[4];
Cardinal i = 0;
XmDisplay dd = (XmDisplay) XmGetXmDisplay(XtDisplay(dc));
dd->display.activeDC = NULL;
dd->display.userGrabbed = False;
if (ev) {
switch(ev->type) {
case ButtonRelease:
state = ev->xbutton.state;
dc->drag.lastChangeTime = ev->xbutton.time;
dc->core.x = ev->xbutton.x_root;
dc->core.y = ev->xbutton.y_root;
break;
case KeyPress:
state = ev->xkey.state;
dc->drag.lastChangeTime = ev->xkey.time;
dc->core.x = ev->xkey.x_root;
dc->core.y = ev->xkey.y_root;
break;
}
/*
* start out with the default operations in effective operations
*/
dc->drag.lastEventState = state;
CalculateDragOperation(dc);
}
/*
* change the dragOver to a window in so it can persist after the
* ungrab
*/
if (dc->drag.curDragOver) {
unsigned char currentMode;
unsigned char currentActiveMode;
XtSetArg(args[0], XmNdragOverMode, ¤tMode);
XtSetArg(args[1], XmNdragOverActiveMode, ¤tActiveMode);
XtGetValues((Widget) dc->drag.curDragOver, args, 2);
i = 0;
XtSetArg(args[i], XmNhotX, dc->core.x); i++;
XtSetArg(args[i], XmNhotY, dc->core.y); i++;
if (currentActiveMode == XmCURSOR ||
(currentMode != XmDRAG_WINDOW && currentMode != XmWINDOW) ) {
XtSetArg(args[i], XmNdragOverMode, XmWINDOW); i++;
}
XtSetValues((Widget) dc->drag.curDragOver, args, i);
XUngrabPointer(XtDisplayOfObject((Widget) dc), dc->drag.lastChangeTime);
XtUngrabPointer((Widget) dc, dc->drag.dragFinishTime);
XUngrabKeyboard(XtDisplayOfObject((Widget) dc), dc->drag.lastChangeTime);
_XmRemoveGrab((Widget)dc);
}
if (dc->drag.serverGrabbed)
XUngrabServer(XtDisplay((Widget) dc));
/*
* if we're in pre-register with a non-local raeceiver then we need
* to flush a top-level leave to the local dsm.
*/
dc->drag.dragFinishTime = dc->drag.lastChangeTime;
if (dc->drag.inDropSite) {
GenerateClientCallback(dc, XmCR_DROP_SITE_LEAVE);
dc->drag.inDropSite = False;
}
if (dc->drag.currReceiverInfo) {
if (dc->drag.currReceiverInfo->window) {
SendDragMessage(dc, dc->drag.currReceiverInfo->window,
XmTOP_LEVEL_LEAVE);
GenerateClientCallback(dc, XmCR_TOP_LEVEL_LEAVE);
if ((dc->drag.activeProtocolStyle != XmDRAG_NONE) &&
((dc->drag.dragCompletionStatus == XmDROP) ||
(dc->drag.dragCompletionStatus == XmDROP_HELP))) {
XtAppContext appContext= XtWidgetToApplicationContext((Widget)dc);
/*
* we send the leave message in the dragDropFinish so
* that a non-local receiver can cleanup its dc
*/
dc->drag.dragTimerId =
XtAppAddTimeOut(appContext,
XtAppGetSelectionTimeout(appContext),
DropStartTimeout,
(XtPointer)dc);
SendDragMessage(dc, dc->drag.currReceiverInfo->window,
XmDROP_START);
}
else {
dc->drag.dragDropCompletionStatus = XmDROP_FAILURE;
dc->drag.dropFinishTime = dc->drag.dragFinishTime;
DropStartTimeout((XtPointer)dc, NULL);
}
}
dc->drag.currReceiverInfo->frame = 0;
} else {
/* Cleanup anyway */
DropStartTimeout((XtPointer)dc, NULL);
}
}
/* ARGSUSED */
static void
CheckModifiers(
XmDragContext dc,
unsigned int state)
{
unsigned char oldOperation = dc->drag.operation;
unsigned char oldOperations = dc->drag.operations;
dc->drag.lastEventState = state;
CalculateDragOperation(dc);
if ((oldOperations != dc->drag.operations) ||
(oldOperation != dc->drag.operation)) {
if ((dc->drag.currReceiverInfo->window) &&
(dc->drag.activeProtocolStyle != XmDRAG_NONE) &&
(dc->drag.activeProtocolStyle != XmDRAG_DROP_ONLY)) {
SendDragMessage(dc,
dc->drag.currReceiverInfo->window,
XmOPERATION_CHANGED);
}
else {
GenerateClientCallback(dc, XmCR_OPERATION_CHANGED);
}
}
}
/* ARGSUSED */
static void
IgnoreButtons(
Widget w,
XEvent *event,
String *params,
Cardinal *numParams )
{
XmDragContext dc = (XmDragContext)w;
/*
* the user has pressed some other buttons and caused the server
* to synch up. Swallow and continue
*/
XAllowEvents(XtDisplayOfObject((Widget) dc->drag.srcShell),
SyncPointer,
dc->drag.lastChangeTime);
}
/* ARGSUSED */
static void
CancelDrag(
Widget w,
XEvent *event,
String *params,
Cardinal *numParams )
{
XmDragContext dc = (XmDragContext)w;
/*
* only cancel if drag has not yet completed
*/
if (dc->drag.dragFinishTime == 0) {
dc->drag.dragCompletionStatus = XmDROP_CANCEL;
FinishAction(dc, event);
}
}
/* ARGSUSED */
static void
HelpDrag(
Widget w,
XEvent *event,
String *params,
Cardinal *numParams )
{
XmDragContext dc = (XmDragContext)w;
dc->drag.dragCompletionStatus = XmDROP_HELP;
FinishAction(dc, event);
}
/* ARGSUSED */
static void
FinishDrag(
Widget w,
XEvent *event,
String *params,
Cardinal *numParams )
{
XmDragContext dc = (XmDragContext)w;
dc->drag.dragCompletionStatus = XmDROP;
FinishAction(dc, event);
}
static void
noMoreShell(
Widget w,
XtPointer client,
XtPointer call)
{
Boolean *contAction = (Boolean *)client;
*contAction = False;
}
/*ARGSUSED*/
static void
InitiatorMainLoop(
XtPointer clientData,
XtIntervalId *id )
{
XmDragContext *activeDC = (XmDragContext *)clientData;
XtAppContext appContext;
XEvent event;
Widget focusWidget, shell;
Boolean contAction = True;
if (*activeDC) {
appContext = XtWidgetToApplicationContext((Widget) *activeDC);
shell = (*activeDC)->drag.srcShell;
focusWidget = XmGetFocusWidget((Widget)((*activeDC)->drag.srcShell));
if (_XmGetFocusPolicy(shell) == XmEXPLICIT) {
XtSetKeyboardFocus(shell, None);
} else {
XmFocusData focusData = _XmGetFocusData(shell);
if(focusData)
focusData->needToFlush = False;
/* CR 6384, check for null focusWidget */
if (focusWidget != (Widget) NULL) {
if (XmIsPrimitive(focusWidget)) {
if (((XmPrimitiveWidgetClass) XtClass(focusWidget))
->primitive_class.border_unhighlight)
(*(((XmPrimitiveWidgetClass) XtClass(focusWidget))
->primitive_class.border_unhighlight))(focusWidget);
} else if (XmIsGadget(focusWidget)) {
if (((XmGadgetClass) XtClass(focusWidget))
->gadget_class.border_unhighlight)
(*(((XmGadgetClass) XtClass(focusWidget))
->gadget_class.border_unhighlight))(focusWidget);
}
}
}
DragStartProto(*activeDC);
}
else return;
XtAddCallback (shell, XmNdestroyCallback, noMoreShell,
(XtPointer)&contAction);
while ( (*activeDC) && (XtAppGetExitFlag(appContext) == False) ) {
XmDragContext dc = *activeDC;
#ifdef XTHREADS
XtInputMask mask;
while(!(mask = XtAppPending(appContext)))
; /* busy wait */
if (mask & XtIMXEvent)
{
#endif
XtAppNextEvent(appContext, &event);
/*
* make sure evil Focus outs don't confuse Xt and cause the
* unhighlighting of the source hierarchy.
*/
switch(event.type) {
case FocusIn:
case FocusOut:
break;
case KeyPress:
case KeyRelease:
case ButtonPress:
case ButtonRelease:
case EnterNotify:
case LeaveNotify:
case MotionNotify:
{
/* dispatch it onto the dc */
switch(dc->drag.trackingMode) {
case XmDRAG_TRACK_MOTION:
break;
#ifdef MULTI_SCREEN_DONE
case XmDRAG_TRACK_WM_QUERY:
event.xmotion.subwindow = event.xmotion.window;
break;
#endif /* MULTI_SCREEN_DONE */
case XmDRAG_TRACK_WM_QUERY_PENDING:
event.xmotion.subwindow = event.xmotion.window;
break;
}
}
event.xmotion.window = XtWindow(dc);
break;
}
if ((event.type == MotionNotify ||
event.type == LeaveNotify ||
event.type == EnterNotify) &&
event.xmotion.state == dc->drag.lastEventState)
DragMotion((Widget)dc, &event, NULL, 0);
else
XtDispatchEvent(&event);
#ifdef XTHREADS
}
else
XtAppProcessEvent(appContext, mask);
#endif
}
/* guard against the possibility that shell was destroyed in the last event
* loop while the drag operation was going on (e.g. by a timer)
*/
if (contAction) {
XtRemoveCallback (shell, XmNdestroyCallback, noMoreShell,
(XtPointer)&contAction);
if (_XmGetFocusPolicy(shell) == XmEXPLICIT) {
XtSetKeyboardFocus(shell, focusWidget);
}
}
}
Widget
XmDragStart(
Widget w,
XEvent *event,
ArgList args,
Cardinal numArgs )
{
XmDragContext dc;
XmDisplay dd = (XmDisplay) XmGetXmDisplay(XtDisplay(w));
Arg lclArgs[1];
Arg *mergedArgs;
XmDragStartCallbackStruct cb;
_XmWidgetToAppContext(w);
_XmAppLock(app);
if (dd->display.dragInitiatorProtocolStyle == XmDRAG_NONE) {
_XmAppUnlock(app);
return(NULL);
}
if (event->type != ButtonPress &&
event->type != ButtonRelease &&
event->type != KeyRelease &&
event->type != KeyPress &&
event->type != MotionNotify ) {
XmeWarning(w, MESSAGE6);
_XmAppUnlock(app);
return NULL;
}
cb.reason = XmCR_DRAG_START;
cb.event = event;
cb.widget = w;
cb.doit = True;
XtCallCallbackList((Widget)dd, dd->display.dragStartCallback,
(XtPointer) &cb);
if (!cb.doit) {
_XmAppUnlock(app);
return NULL;
}
/*
* check if the menu system is already active
*/
if (dd->display.userGrabbed) {
#ifdef DEBUG
Warning("can't drag; menu system active\n");
#endif
_XmAppUnlock(app);
return NULL;
}
XtSetArg(lclArgs[0], XmNsourceWidget, w);
if (numArgs) {
mergedArgs = XtMergeArgLists(args, numArgs, lclArgs, 1);
}
else {
mergedArgs = lclArgs;
}
dc = (XmDragContext)
XtCreateWidget("dragContext", xmDragContextClass,
(Widget) dd, mergedArgs, numArgs + 1);
XtAddCallback(w, XmNdestroyCallback, cancelDrag, (XtPointer)dc);
_XmDragStart(dc, w, event);
if (numArgs)
XtFree( (char *)mergedArgs);
_XmAppUnlock(app);
return (Widget)dc;
}
static void
DragCancel(
XmDragContext dc )
{
dc->drag.dragCompletionStatus = XmDROP_CANCEL;
FinishAction(dc, NULL);
}
void
XmDragCancel(
Widget dragContext )
{
_XmWidgetToAppContext(dragContext);
_XmAppLock(app);
DragCancel((XmDragContext)dragContext);
_XmAppUnlock(app);
}
/*ARGSUSED*/
Boolean
XmTargetsAreCompatible(
Display *dpy,
Atom *exportTargets,
Cardinal numExportTargets,
Atom *importTargets,
Cardinal numImportTargets )
{
Cardinal j, k;
_XmDisplayToAppContext(dpy);
_XmAppLock(app);
for (j = 0; j < numExportTargets; j++)
for (k = 0; k < numImportTargets; k++)
if (exportTargets[j] == importTargets[k]) {
_XmAppUnlock(app);
return True;
}
_XmAppUnlock(app);
return False;
}
unsigned char
_XmGetActiveProtocolStyle(
Widget w )
{
unsigned char initiator = XmDRAG_NONE,
receiver = XmDRAG_NONE,
active = XmDRAG_NONE;
XmDragContext dc = (XmDragContext)w;
XmDisplay xmDisplay = (XmDisplay)XtParent(dc);
initiator = xmDisplay->display.dragInitiatorProtocolStyle;
receiver = xmDisplay->display.dragReceiverProtocolStyle;
if (!dc->drag.sourceIsExternal)
{
/* We are the initiator. Find the receiver. */
if (dc->drag.currReceiverInfo)
{
receiver = dc->drag.currReceiverInfo->dragProtocolStyle;
}
else
{
/*
* This function is sometimes called before we have
* set up the receiver info struct on the dc. In these
* cases, we are still in the initiating client, and so
* we will use the initiating client's receiver protocol
* style. In order to do this we have to emulate the
* protocol style decision made in GetDestinationInfo.
* But we can't, since we don't really know the shell
* widget--the particular shell widget may not have a dnd
* property attached to it.
*
* There are a number of different guesses that we could
* make. None of them is substantially better than
* not guessing at all. Not guessing only messes up if the
* shell really doesn't have any drop sites--we should be
* returning NONE, but we might return something else.
*/
/*EMPTY*/
}
active = protocolMatrix[initiator][receiver];
}
else
{
/* We are the receiver, so we can't be preregister. (Since
* the receiver doesn't hear about the drag during the drag,
* and so get ACTIVE protocol makes no sense.)
*/
switch(receiver)
{
case XmDRAG_NONE:
active = XmDRAG_NONE;
break;
case XmDRAG_DROP_ONLY:
/* this must be post drop emulation of drag */
case XmDRAG_PREREGISTER:
case XmDRAG_DYNAMIC:
case XmDRAG_PREFER_DYNAMIC:
case XmDRAG_PREFER_PREREGISTER:
case XmDRAG_PREFER_RECEIVER:
active = XmDRAG_DYNAMIC;
break;
}
}
return active;
}
static void
CalculateDragOperation(XmDragContext dc)
{
/*
* Re-set to the initial settings of operation and operations
*/
dc->drag.operations = dc->drag.dragOperations;
if ((dc->drag.lastEventState & ShiftMask) &&
(dc->drag.lastEventState & ControlMask)) {
dc->drag.operations =
dc->drag.operation = (unsigned char)
(XmDROP_LINK & dc->drag.dragOperations);
}
else if (dc->drag.lastEventState & ShiftMask) {
dc->drag.operations =
dc->drag.operation = (unsigned char)
(XmDROP_MOVE & dc->drag.dragOperations);
}
else if (dc->drag.lastEventState & ControlMask) {
dc->drag.operations =
dc->drag.operation = (unsigned char)
(XmDROP_COPY & dc->drag.dragOperations);
}
else if (XmDROP_MOVE &dc->drag.dragOperations)
dc->drag.operation = (unsigned char)XmDROP_MOVE;
else if (XmDROP_COPY &dc->drag.dragOperations)
dc->drag.operation = (unsigned char)XmDROP_COPY;
else if (XmDROP_LINK &dc->drag.dragOperations)
dc->drag.operation = (unsigned char)XmDROP_LINK;
else {
dc->drag.operations = dc->drag.operation = 0;
}
}