DndDrag.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /* $XConsortium: DndDrag.c /main/5 1996/09/27 19:00:40 drk $ */
  24. /*********************************************************************
  25. *
  26. * File: DndDrag.c
  27. *
  28. * Description: Implemenation of DND Drag Initator
  29. *
  30. *********************************************************************
  31. *
  32. *+SNOTICE
  33. *
  34. * RESTRICTED CONFIDENTIAL INFORMATION:
  35. *
  36. * The information in this document is subject to special
  37. * restrictions in a confidential disclosure agreement between
  38. * HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
  39. * document outside HP, IBM, Sun, USL, SCO, or Univel without
  40. * Sun's specific written approval. This documment and all copies
  41. * and derivative works thereof must be returned or destroyed at
  42. * Sun's request.
  43. *
  44. * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
  45. *
  46. * (c) Copyright 1993, 1994 Hewlett-Packard Company
  47. * (c) Copyright 1993, 1994 International Business Machines Corp.
  48. * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
  49. * (c) Copyright 1993, 1994 Novell, Inc.
  50. *
  51. *+ENOTICE
  52. */
  53. #include <stdio.h>
  54. #include <stdlib.h>
  55. #include <stdarg.h>
  56. #include <X11/Intrinsic.h>
  57. #include <Xm/AtomMgr.h>
  58. #include <Xm/DragDrop.h>
  59. #include <Xm/DragC.h>
  60. #include <Xm/DragCP.h>
  61. #include <Xm/DragOverSP.h>
  62. #include <Dt/Wsm.h>
  63. #include "Dnd.h"
  64. #include "DndP.h"
  65. #include "DtSvcLock.h"
  66. /*
  67. * Drag Initiator Callbacks
  68. */
  69. static Boolean dndConvertProc(Widget, Atom*, Atom*, Atom*, XtPointer *,
  70. unsigned long*, int*);
  71. static void dndAppConvert(Widget, int, XEvent*, DtDragInfo*);
  72. static void dndDropStartCallback(Widget, XtPointer, XtPointer);
  73. static void dndDropFinishCallback(Widget, XtPointer, XtPointer);
  74. static void dndDragDropFinishCallback(Widget, XtPointer, XtPointer);
  75. static void dndTopLevelEnterCallback(Widget, XtPointer, XtPointer);
  76. static void dndTopLevelLeaveCallback(Widget, XtPointer, XtPointer);
  77. extern int _DtDndCountVarArgs(va_list vaList);
  78. extern void _DtDndArgListFromVarArgs(va_list vaList,
  79. Cardinal maxArgs,
  80. ArgList *argListReturn,
  81. Cardinal *argCountReturn);
  82. extern void _XmDragOverChange(Widget w,
  83. unsigned char dropSiteStatus);
  84. /*
  85. * Drag Initiator Resources
  86. */
  87. typedef struct {
  88. XtCallbackList dropOnRootCallback;
  89. Widget sourceIcon;
  90. Boolean bufferIsText;
  91. } DragSettings;
  92. #define Offset(field) XtOffsetOf(DragSettings, field)
  93. static XtResource dragResources[] = {
  94. { DtNdropOnRootCallback, DtCDropOnRootCallback,
  95. XtRCallback, sizeof(XtCallbackList), Offset(dropOnRootCallback),
  96. XtRImmediate, (XtPointer)NULL},
  97. { DtNsourceIcon, DtCSourceIcon,
  98. XtRWidget, sizeof(Widget), Offset(sourceIcon),
  99. XtRImmediate, (XtPointer)NULL },
  100. { DtNbufferIsText, DtCBufferIsText,
  101. XtRBoolean, sizeof(Boolean), Offset(bufferIsText),
  102. XtRImmediate, (XtPointer)False },
  103. };
  104. #undef Offset
  105. /*
  106. * DtDndVaDragStart
  107. *
  108. * Drag Start - varargs version
  109. */
  110. Widget
  111. DtDndVaDragStart(
  112. Widget dragInitiator,
  113. XEvent* event,
  114. DtDndProtocol protocol,
  115. Cardinal numItems,
  116. unsigned char operations,
  117. XtCallbackList dragConvertCallback,
  118. XtCallbackList dragFinishCallback,
  119. ...)
  120. {
  121. Widget dragContext;
  122. va_list vaList;
  123. ArgList argList;
  124. Cardinal argCount;
  125. _DtSvcWidgetToAppContext(dragInitiator);
  126. _DtSvcAppLock(app);
  127. va_start(vaList, dragFinishCallback);
  128. argCount = _DtDndCountVarArgs(vaList);
  129. va_end(vaList);
  130. va_start(vaList, dragFinishCallback);
  131. _DtDndArgListFromVarArgs(vaList, argCount, &argList, &argCount);
  132. va_end(vaList);
  133. dragContext = DtDndDragStart(dragInitiator, event, protocol,
  134. numItems, operations,
  135. dragConvertCallback, dragFinishCallback,
  136. argList, argCount);
  137. XtFree((char *)argList);
  138. _DtSvcAppUnlock(app);
  139. return dragContext;
  140. }
  141. /*
  142. * DtDndVaDragStart
  143. *
  144. * Drag Start - arglist version
  145. */
  146. Widget
  147. DtDndDragStart(
  148. Widget dragInitiator,
  149. XEvent* event,
  150. DtDndProtocol protocol,
  151. Cardinal numItems,
  152. unsigned char operations,
  153. XtCallbackList dragConvertCallback,
  154. XtCallbackList dragFinishCallback,
  155. ArgList argList,
  156. Cardinal argCount)
  157. {
  158. XtCallbackRec dragDropFinishCbRec[] = { {dndDragDropFinishCallback,
  159. NULL}, {NULL, NULL} };
  160. XtCallbackRec topLevelEnterCbRec[] = { {dndTopLevelEnterCallback,
  161. NULL}, {NULL, NULL} };
  162. XtCallbackRec topLevelLeaveCbRec[] = { {dndTopLevelLeaveCallback,
  163. NULL}, {NULL, NULL} };
  164. XtCallbackRec dropStartCbRec[] = { {dndDropStartCallback,
  165. NULL}, {NULL, NULL} };
  166. XtCallbackRec dropFinishCbRec[] = { {dndDropFinishCallback,
  167. NULL}, {NULL, NULL} };
  168. Display * display = XtDisplayOfObject(dragInitiator);
  169. Screen * screen = XtScreenOfObject(dragInitiator);
  170. Window rootWindow = RootWindowOfScreen(screen);
  171. DtDragInfo * dtDragInfo;
  172. DragSettings settings;
  173. DtDndDragSource sourceType;
  174. DtDndTransfer * transfer;
  175. Arg * args;
  176. int ii, nn, savedEventType;
  177. Atom * exportTargets;
  178. Cardinal numExportTargets;
  179. _DtSvcWidgetToAppContext(dragInitiator);
  180. _DtSvcAppLock(app);
  181. /*
  182. * Reject the drag if noop or multiple protocols specified
  183. */
  184. switch (protocol) {
  185. case DtDND_BUFFER_TRANSFER:
  186. case DtDND_FILENAME_TRANSFER:
  187. case DtDND_TEXT_TRANSFER:
  188. break;
  189. case DtDND_NOOP_TRANSFER:
  190. default:
  191. _DtSvcAppUnlock(app);
  192. return (Widget)NULL;
  193. }
  194. /*
  195. * Parse resources into dragResources
  196. */
  197. XtGetSubresources(dragInitiator, &settings,
  198. (String)NULL, (String)NULL,
  199. dragResources, XtNumber(dragResources),
  200. argList, argCount);
  201. /*
  202. * Initialize DragInfo
  203. */
  204. dtDragInfo = (DtDragInfo *) XtMalloc(sizeof(DtDragInfo));
  205. dtDragInfo->dragInitiator = dragInitiator;
  206. dtDragInfo->dragContext = NULL;
  207. dtDragInfo->protocol = protocol;
  208. dtDragInfo->numItems = numItems;
  209. dtDragInfo->operations = operations;
  210. dtDragInfo->sourceIcon = settings.sourceIcon;
  211. dtDragInfo->bufferIsText = settings.bufferIsText;
  212. dtDragInfo->dragData = NULL;
  213. dtDragInfo->inRoot = False;
  214. dtDragInfo->status = DtDND_SUCCESS;
  215. dtDragInfo->clientData = NULL;
  216. dtDragInfo->backdropWindow
  217. = DtWsmGetCurrentBackdropWindow(display, rootWindow);
  218. dtDragInfo->dragConvertCallback
  219. = _DtDndCopyCallbackList(dragConvertCallback);
  220. dtDragInfo->dragFinishCallback
  221. = _DtDndCopyCallbackList(dragFinishCallback);
  222. dtDragInfo->dropOnRootCallback
  223. = _DtDndCopyCallbackList(settings.dropOnRootCallback);
  224. dtDragInfo->dragData = (DtDndContext *)XtCalloc(1,sizeof(DtDndContext));
  225. dtDragInfo->dragData->protocol = dtDragInfo->protocol;
  226. dtDragInfo->dragData->numItems = 0;
  227. /*
  228. * Get data transfer method
  229. * Use the transfer targets as export targets
  230. */
  231. dtDragInfo->transfer = _DtDndCreateExportTransfer(dtDragInfo);
  232. exportTargets = dtDragInfo->transfer->targets;
  233. numExportTargets = dtDragInfo->transfer->numTargets;
  234. #ifdef DEBUG
  235. printf("DtDndDragStart: drag from widget 0x%p\n", dragInitiator);
  236. _DtDndPrintTransfers(display,dtDragInfo->transfer,1);
  237. #endif
  238. /*
  239. * Set up drag icon
  240. */
  241. if (numItems > 1) {
  242. sourceType = DtDND_DRAG_SOURCE_MULTIPLE;
  243. } else {
  244. sourceType = dtDragInfo->transfer->methods->sourceType;
  245. }
  246. _DtDndSelectDragSource(dragInitiator, sourceType,
  247. dtDragInfo->sourceIcon);
  248. /*
  249. * Construct argument list
  250. */
  251. #define NUM_DRAG_ARGS 30
  252. args = (Arg *) XtMalloc(sizeof(Arg) * (NUM_DRAG_ARGS + argCount));
  253. #undef NUM_DRAG_ARGS
  254. /*
  255. * Copy in passed arguments
  256. */
  257. nn = 0;
  258. for (ii = 0; ii < argCount; ii++) {
  259. XtSetArg(args[nn], argList[ii].name, argList[ii].value); nn++;
  260. }
  261. /*
  262. * Set basic drag start arguments
  263. */
  264. XtSetArg(args[nn], XmNexportTargets, exportTargets);
  265. nn++;
  266. XtSetArg(args[nn], XmNnumExportTargets, numExportTargets);
  267. nn++;
  268. XtSetArg(args[nn], XmNdragOperations, operations);
  269. nn++;
  270. XtSetArg(args[nn], XmNblendModel, XmBLEND_ALL);
  271. nn++;
  272. XtSetArg(args[nn], XmNcursorBackground, WhitePixelOfScreen(screen));
  273. nn++;
  274. XtSetArg(args[nn], XmNcursorForeground, BlackPixelOfScreen(screen));
  275. nn++;
  276. XtSetArg(args[nn], XmNclientData, dtDragInfo);
  277. nn++;
  278. if (dtDragInfo->sourceIcon != NULL) {
  279. XtSetArg(args[nn],XmNsourcePixmapIcon, dtDragInfo->sourceIcon);
  280. nn++;
  281. XtSetArg(args[nn],XmNsourceCursorIcon, dtDragInfo->sourceIcon);
  282. nn++;
  283. }
  284. /*
  285. * Set up DnD callbacks for Motif
  286. */
  287. XtSetArg(args[nn], XmNconvertProc, dndConvertProc);
  288. nn++;
  289. dragDropFinishCbRec[0].closure = (XtPointer) dtDragInfo;
  290. dropFinishCbRec[0].closure = (XtPointer) dtDragInfo;
  291. dtDragInfo->dragDropFinishCallback
  292. = _DtDndCopyCallbackList(dragDropFinishCbRec);
  293. dtDragInfo->dropFinishCallback
  294. = _DtDndCopyCallbackList(dropFinishCbRec);
  295. XtSetArg(args[nn], XmNdragDropFinishCallback, dtDragInfo->dragDropFinishCallback);
  296. nn++;
  297. XtSetArg(args[nn], XmNdropFinishCallback, dtDragInfo->dropFinishCallback);
  298. nn++;
  299. /*
  300. * Only use top-level-enter/leave callbacks if also doing drop-on-root
  301. */
  302. if (dtDragInfo->dropOnRootCallback != NULL) {
  303. topLevelEnterCbRec[0].closure = (XtPointer) dtDragInfo;
  304. topLevelLeaveCbRec[0].closure = (XtPointer) dtDragInfo;
  305. dropStartCbRec[0].closure = (XtPointer) dtDragInfo;
  306. dtDragInfo->topLevelEnterCallback
  307. = _DtDndCopyCallbackList(topLevelEnterCbRec);
  308. dtDragInfo->topLevelLeaveCallback
  309. = _DtDndCopyCallbackList(topLevelLeaveCbRec);
  310. dtDragInfo->dropStartCallback
  311. = _DtDndCopyCallbackList(dropStartCbRec);
  312. XtSetArg(args[nn], XmNtopLevelEnterCallback, dtDragInfo->topLevelEnterCallback);
  313. nn++;
  314. XtSetArg(args[nn], XmNtopLevelLeaveCallback, dtDragInfo->topLevelLeaveCallback);
  315. nn++;
  316. XtSetArg(args[nn], XmNdropStartCallback, dtDragInfo->dropStartCallback);
  317. nn++;
  318. }
  319. /*
  320. * Fake a button press. This is necessary because Motif requires
  321. * a drag to start on a button press. We need to be able to start
  322. * a drag on a mouse motion event when Bselect is held down. Since
  323. * the motion event has the fields necessary for Motif this works.
  324. */
  325. savedEventType = event->type;
  326. if (event->type == MotionNotify) {
  327. event->type = ButtonPress;
  328. }
  329. /*
  330. * Start the drag
  331. */
  332. dtDragInfo->dragContext = XmDragStart(dragInitiator, event, args, nn);
  333. XtFree((char *)args);
  334. event->type = savedEventType;
  335. _DtSvcAppUnlock(app);
  336. return (dtDragInfo->dragContext);
  337. }
  338. /*********************************************************************
  339. *
  340. * Drag Initiator Callbacks
  341. *
  342. *********************************************************************/
  343. /*
  344. * dndDropStartCallback
  345. *
  346. *
  347. */
  348. static void
  349. dndDropStartCallback(
  350. Widget dragContext,
  351. XtPointer clientData,
  352. XtPointer callData)
  353. {
  354. DtDragInfo *dtDragInfo = (DtDragInfo *) clientData;
  355. DtDndContext *dragData;
  356. XmDragContext xmDragContext = (XmDragContext)dtDragInfo->dragContext;
  357. XmDropStartCallbackStruct *xmDropInfo = (XmDropStartCallback) callData;
  358. DtDndTransferCallbackStruct dropCallData;
  359. int posOffsetX, posOffsetY;
  360. /*
  361. * If the user has cancelled the drop, or the drop isn't on the
  362. * root, or there are no dropOnRoot or convert callbacks
  363. * then reject the drop.
  364. */
  365. if (xmDragContext->drag.dragCompletionStatus == XmDROP_CANCEL ||
  366. dtDragInfo->inRoot == False ||
  367. dtDragInfo->dropOnRootCallback == NULL ||
  368. dtDragInfo->dragConvertCallback == NULL ) {
  369. xmDropInfo->dropSiteStatus = XmINVALID_DROP_SITE;
  370. xmDropInfo->dropAction = XmDROP_CANCEL;
  371. return;
  372. }
  373. /*
  374. * The following is to handle the dropOnRoot situation.
  375. * We handle both the convert and transfer sides of the
  376. * transaction here. First we get the application drag data
  377. * and then we call the application dropOnRoot callback.
  378. */
  379. /*
  380. * Initialize protocol specific dragData
  381. */
  382. dtDragInfo->dragData->numItems = dtDragInfo->numItems;
  383. (*dtDragInfo->transfer->methods->convertInit)(dtDragInfo);
  384. /*
  385. * Invoke the application convert callback
  386. */
  387. dndAppConvert(dragContext, DtCR_DND_CONVERT_DATA,
  388. xmDropInfo->event, dtDragInfo);
  389. if (dtDragInfo->status == DtDND_FAILURE) {
  390. return;
  391. }
  392. /*
  393. * Setup dropOnRootcall data and invoke the dropOnroot callback
  394. */
  395. _DtDndGetIconOffset(dtDragInfo->dragContext,
  396. dtDragInfo->transfer->methods->sourceType,
  397. &posOffsetX, &posOffsetY);
  398. dropCallData.reason = DtCR_DND_ROOT_TRANSFER;
  399. dropCallData.event = xmDropInfo->event;
  400. dropCallData.x = xmDropInfo->x + posOffsetX;
  401. dropCallData.y = xmDropInfo->y + posOffsetY;
  402. dropCallData.operation = xmDropInfo->operation;
  403. dropCallData.dropData = dtDragInfo->dragData;
  404. dropCallData.completeMove = False;
  405. dropCallData.status = DtDND_SUCCESS;
  406. _DtDndCallCallbackList(dragContext, dtDragInfo->dropOnRootCallback,
  407. (XtPointer)&dropCallData);
  408. /*
  409. * Tell Motif that the root is a valid drop site
  410. */
  411. xmDropInfo->dropSiteStatus = XmVALID_DROP_SITE;
  412. xmDropInfo->dropAction = XmDROP;
  413. }
  414. /*
  415. * dndConvertProc
  416. *
  417. *
  418. */
  419. static Boolean
  420. dndConvertProc(
  421. Widget dragContext,
  422. Atom *selection,
  423. Atom *target,
  424. Atom *returnType,
  425. XtPointer *returnValue,
  426. unsigned long *returnLength,
  427. int *returnFormat)
  428. {
  429. Atom realSelectionAtom; /* Motif hides the selection atom */
  430. DtDragInfo *dtDragInfo = NULL;
  431. XSelectionRequestEvent *selectionRequestEvent;
  432. Boolean status;
  433. #ifdef DEBUG
  434. {
  435. Display *display = XtDisplayOfObject(dragContext);
  436. char *atomname = XGetAtomName(display,*target);
  437. printf("dndConvertProc: target = %s\n",(atomname ? atomname : "Null"));
  438. if (atomname) XFree(atomname);
  439. }
  440. #endif
  441. /*
  442. * Get the DtDragInfo
  443. */
  444. XtVaGetValues(dragContext, XmNclientData, &dtDragInfo, NULL);
  445. if (dtDragInfo == NULL || dtDragInfo->status == DtDND_FAILURE) {
  446. return False;
  447. }
  448. /*
  449. * Get selection request event
  450. */
  451. XtVaGetValues(dragContext, XmNiccHandle, &realSelectionAtom, NULL);
  452. selectionRequestEvent = XtGetSelectionRequest(dragContext,
  453. realSelectionAtom, NULL); /* REMIND: NULL for atomic transfer */
  454. /*
  455. * Get the application drag data if necessary
  456. */
  457. if (dtDragInfo->dragData->numItems == 0) {
  458. dtDragInfo->dragData->numItems = dtDragInfo->numItems;
  459. (*dtDragInfo->transfer->methods->convertInit)(dtDragInfo);
  460. dndAppConvert(dragContext, DtCR_DND_CONVERT_DATA,
  461. (XEvent *)selectionRequestEvent, dtDragInfo);
  462. if (dtDragInfo->status == DtDND_FAILURE) {
  463. return False;
  464. }
  465. }
  466. /*
  467. * Handle transfer protocol independent target conversions
  468. */
  469. if (*target == XA_TARGETS) {
  470. /*
  471. * TARGETS Construct a list of targets consisting of those
  472. * the dnd library supports plus those supported by
  473. * the drag initiator.
  474. */
  475. int ii, LIBRARY_TARGETS = 6;
  476. Atom * availTargets;
  477. Atom * allTargets;
  478. Cardinal numAvailTargets;
  479. Cardinal numAllTargets;
  480. (*dtDragInfo->transfer->methods->getAvailTargets)(dtDragInfo,
  481. &availTargets, &numAvailTargets);
  482. numAllTargets = numAvailTargets + LIBRARY_TARGETS;
  483. allTargets = (Atom *)XtMalloc(sizeof(Atom) * numAllTargets);
  484. for (ii = 0; ii < numAvailTargets; ii++) {
  485. allTargets[ii] = availTargets[ii];
  486. }
  487. XtFree((char *)availTargets);
  488. ii = numAvailTargets;
  489. allTargets[ii++] = XA_TARGETS;
  490. allTargets[ii++] = XA_TIMESTAMP;
  491. allTargets[ii++] = XA_MULTIPLE;
  492. allTargets[ii++] = XA_HOST_NAME;
  493. allTargets[ii++] = XA_SUN_FILE_HOST_NAME;
  494. allTargets[ii++] = XA_DELETE;
  495. *returnType = XA_ATOM;
  496. *returnFormat = 32;
  497. *returnValue = (XtPointer)allTargets;
  498. *returnLength = numAllTargets * sizeof(Atom)/4;
  499. status = True;
  500. } else if (*target == XA_TIMESTAMP || *target == XA_MULTIPLE) {
  501. /*
  502. * TIMESTAMP and MULTIPLE are handled by the Intrinsics
  503. */
  504. status = True;
  505. } else if (*target == XA_HOST_NAME ||
  506. *target == XA_SUN_FILE_HOST_NAME) {
  507. /*
  508. * HOST_NAME, _SUN_FILE_HOST_NAME The name of this host
  509. */
  510. *returnType = XA_STRING;
  511. *returnValue = (XtPointer)XtNewString(_DtDndGetHostName());
  512. *returnLength = strlen((char *)*returnValue) + 1;
  513. *returnFormat = 8;
  514. status = True;
  515. } else if (*target == XA_DELETE) {
  516. /*
  517. * DELETE Set up convert callback data to specify
  518. * deletion and invoke the application-defined
  519. * convertCallback() to perform the delete.
  520. */
  521. *returnType = XA_NULL;
  522. *returnFormat = 32;
  523. *returnValue = (XtPointer) NULL;
  524. *returnLength = 0;
  525. dndAppConvert(dragContext, DtCR_DND_CONVERT_DELETE,
  526. (XEvent *)selectionRequestEvent, dtDragInfo);
  527. status = True;
  528. } else if (*target == XA_SUN_ENUM_COUNT) {
  529. /*
  530. * _SUN_ENUMERATION_COUNT The number of items available
  531. */
  532. int *count = XtNew(int);
  533. if (dtDragInfo->dragData->numItems == 1) {
  534. count[0] = 1;
  535. } else {
  536. count[0] = 0;
  537. dtDragInfo->status = DtDND_FAILURE;
  538. }
  539. *returnType = XA_INTEGER;
  540. *returnValue = (XtPointer)count;
  541. *returnLength = 1;
  542. *returnFormat = 32;
  543. status = True;
  544. } else {
  545. /*
  546. * Invoke protocol specific convert method
  547. */
  548. status = (*dtDragInfo->transfer->methods->convert)(
  549. dragContext, dtDragInfo,
  550. selection, target,
  551. returnType, returnValue,
  552. returnLength, returnFormat,
  553. selectionRequestEvent);
  554. }
  555. return status;
  556. }
  557. /*
  558. * dndAppConvert
  559. *
  560. * Call the application convert callback
  561. */
  562. static void
  563. dndAppConvert(
  564. Widget dragContext,
  565. int reason,
  566. XEvent * event,
  567. DtDragInfo * dtDragInfo)
  568. {
  569. DtDndConvertCallbackStruct convertCallData;
  570. convertCallData.reason = reason;
  571. convertCallData.event = event;
  572. convertCallData.dragData = dtDragInfo->dragData;
  573. convertCallData.status = DtDND_SUCCESS;
  574. _DtDndCallCallbackList(dragContext, dtDragInfo->dragConvertCallback,
  575. (XtPointer)&convertCallData);
  576. dtDragInfo->status = convertCallData.status;
  577. if (reason == DtCR_DND_CONVERT_DATA &&
  578. dtDragInfo->dragData->numItems <= 0) {
  579. dtDragInfo->status = DtDND_FAILURE;
  580. }
  581. }
  582. /*
  583. * dndDropFinishCallback
  584. *
  585. * Handle drop-on-root case
  586. */
  587. static void
  588. dndDropFinishCallback(
  589. Widget dragContext,
  590. XtPointer clientData,
  591. XtPointer callData)
  592. {
  593. DtDragInfo *dtDragInfo = (DtDragInfo *) clientData;
  594. XmDropFinishCallbackStruct *xmDropFinishCallData =
  595. (XmDropFinishCallbackStruct *) callData;
  596. if (dtDragInfo->dropOnRootCallback != NULL &&
  597. dtDragInfo->inRoot &&
  598. xmDropFinishCallData->dropSiteStatus == XmVALID_DROP_SITE) {
  599. xmDropFinishCallData->completionStatus = XmDROP_SUCCESS;
  600. XtVaSetValues(dtDragInfo->dragContext,
  601. XmNblendModel, XmBLEND_NONE, NULL);
  602. }
  603. }
  604. /*
  605. * dndDragDropFinishCallback
  606. *
  607. * Call the application dragFinishCallback
  608. */
  609. static void
  610. dndDragDropFinishCallback(
  611. Widget dragContext,
  612. XtPointer clientData,
  613. XtPointer callData)
  614. {
  615. XmDragDropFinishCallbackStruct *xmDndFinishInfo =
  616. (XmDragDropFinishCallbackStruct *)callData;
  617. DtDragInfo *dtDragInfo = (DtDragInfo *)clientData;
  618. DtDndDragFinishCallbackStruct dragFinishCallData;
  619. /*
  620. * Invoke application dragFinishCallback
  621. */
  622. dragFinishCallData.reason = DtCR_DND_DRAG_FINISH;
  623. dragFinishCallData.event = xmDndFinishInfo->event;
  624. dragFinishCallData.sourceIcon = dtDragInfo->sourceIcon;
  625. dragFinishCallData.dragData = dtDragInfo->dragData;
  626. _DtDndCallCallbackList(dragContext, dtDragInfo->dragFinishCallback,
  627. (XtPointer)&dragFinishCallData);
  628. /*
  629. * Restore motif default drag cursors
  630. */
  631. _DtDndSelectDragSource(dragContext, DtDND_DRAG_SOURCE_DEFAULT, NULL);
  632. /*
  633. * Invoke protocol specific convertFinish
  634. */
  635. (*dtDragInfo->transfer->methods->convertFinish)(dtDragInfo);
  636. /*
  637. * Free data structures allocated during the drag
  638. */
  639. XtFree((char *)dtDragInfo->transfer->targets);
  640. XtFree((char *)dtDragInfo->transfer);
  641. XtFree((char *)dtDragInfo->dragConvertCallback);
  642. XtFree((char *)dtDragInfo->dragFinishCallback);
  643. XtFree((char *)dtDragInfo->dragDropFinishCallback);
  644. XtFree((char *)dtDragInfo->dropFinishCallback);
  645. if (dtDragInfo->dropOnRootCallback != NULL) {
  646. XtFree((char *)dtDragInfo->topLevelEnterCallback);
  647. XtFree((char *)dtDragInfo->topLevelLeaveCallback);
  648. XtFree((char *)dtDragInfo->dropStartCallback);
  649. }
  650. XtFree((char *)dtDragInfo->dropOnRootCallback);
  651. XtFree((char *)dtDragInfo->dragData);
  652. XtFree((char *)dtDragInfo);
  653. }
  654. /*
  655. * dndTopLevelEnterCallback -- Support for drop-on-root callback.
  656. * When a drop-on-root callback has been set, determines if
  657. * the drag has entered the root window (or equivalents)
  658. * and sneakily changes Motif's idea that the root is an
  659. * invalid drop site to think that it's really a valid one.
  660. * Also updates dtDragInfo.inRoot as needed.
  661. */
  662. static void
  663. dndTopLevelEnterCallback(
  664. Widget dragContext,
  665. XtPointer clientData,
  666. XtPointer callData)
  667. {
  668. XmTopLevelEnterCallbackStruct *xmEnterInfo =
  669. (XmTopLevelEnterCallbackStruct *) callData;
  670. DtDragInfo *dtDragInfo = (DtDragInfo *) clientData;
  671. XmDragContext xmDragContext = (XmDragContext) dragContext;
  672. XmDragOverShellWidget dragOverShell = xmDragContext->drag.curDragOver;
  673. if (xmEnterInfo->window == RootWindowOfScreen(xmEnterInfo->screen) ||
  674. dtDragInfo->backdropWindow == xmEnterInfo->window ) {
  675. dragOverShell->drag.cursorState = XmVALID_DROP_SITE;
  676. _XmDragOverChange((Widget)dragOverShell,
  677. dragOverShell->drag.cursorState);
  678. dtDragInfo->inRoot = True;
  679. } else {
  680. dtDragInfo->inRoot = False;
  681. }
  682. }
  683. /*
  684. * dndTopLevelLeaveCallback -- Support for drop-on-root callback.
  685. * When a drop-on-root callback has been set, determines if
  686. * the drag is exiting the root window and restores Motif's
  687. * internal state back to thinking that the root window is
  688. * an invalid drop site. We don't update dtDragInfo->inRoot
  689. * here since the top-level-leave callback is called before
  690. * the drop callback which needs to know if we're in the root
  691. * or not.
  692. */
  693. static void
  694. dndTopLevelLeaveCallback(
  695. Widget dragContext,
  696. XtPointer clientData,
  697. XtPointer callData)
  698. {
  699. XmTopLevelLeaveCallbackStruct *xmLeaveInfo =
  700. (XmTopLevelLeaveCallbackStruct *) callData;
  701. DtDragInfo *dtDragInfo = (DtDragInfo *) clientData;
  702. XmDragContext xmDragContext = (XmDragContext) dragContext;
  703. XmDragOverShellWidget dragOverShell = xmDragContext->drag.curDragOver;
  704. if (xmLeaveInfo->window == RootWindowOfScreen(xmLeaveInfo->screen) ||
  705. dtDragInfo->backdropWindow == xmLeaveInfo->window ) {
  706. dragOverShell->drag.cursorState = XmINVALID_DROP_SITE;
  707. _XmDragOverChange((Widget)dragOverShell,
  708. dragOverShell->drag.cursorState);
  709. }
  710. }