1 /*
2  * Motif
3  *
4  * Copyright (c) 1987-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 librararies 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 #ifdef REV_INFO
24 #ifndef lint
25 static char rcsid[] = "$TOG: DragC.c /main/29 1997/10/07 12:19:52 cshi $"
26 #endif
27 #endif
28 
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32 
33 
34 #ifndef DEFAULT_WM_TIMEOUT
35 #define DEFAULT_WM_TIMEOUT 5000
36 #endif
37 
38 #include <X11/Xatom.h>
39 #include <X11/cursorfont.h>
40 #include <Xm/AtomMgr.h>
41 #include <Xm/DisplayP.h>
42 #include <Xm/DragOverSP.h>
43 #include <Xm/GadgetP.h>
44 #include <Xm/ManagerP.h>
45 #include <Xm/PrimitiveP.h>
46 #include <Xm/TransltnsP.h>
47 #include <Xm/VendorSP.h>
48 #include "XmI.h"
49 #include "DisplayI.h"
50 #include "DragBSI.h"
51 #include "DragCI.h"
52 #include "DragICCI.h"
53 #include "DragOverSI.h"
54 #include "MessagesI.h"
55 #include "TraversalI.h"
56 #include "VendorSI.h"
57 
58 #include <stdio.h>
59 #ifndef X_NOT_STDC_ENV
60 #include <stdlib.h>
61 #endif
62 
63 /* force the multi screen support on */
64 #define MULTI_SCREEN_DONE
65 
66 #ifdef DEBUG
67 #define Warning(str)	XmeWarning(NULL, str)
68 #else
69 #define Warning(str)	/*EMPTY*/
70 #endif
71 
72 #define BIGSIZE ((Dimension)32767)
73 
74 #define MESSAGE1 _XmMMsgDragC_0001
75 #define MESSAGE2 _XmMMsgDragC_0002
76 #define MESSAGE3 _XmMMsgDragC_0003
77 #define MESSAGE4 _XmMMsgDragC_0004
78 #define MESSAGE5 _XmMMsgDragC_0005
79 #define MESSAGE6 _XmMMsgDragC_0006
80 
81 typedef struct _MotionEntryRec{
82     int		type;
83     Time	time;
84     Window	window;
85     Window	subwindow;
86     Position	x, y;
87     unsigned int state;
88 } MotionEntryRec, *MotionEntry;
89 
90 #define STACKMOTIONBUFFERSIZE 	120
91 
92 typedef struct _MotionBufferRec{
93     XmDragReceiverInfo currReceiverInfo;
94     Cardinal		count;
95     MotionEntryRec      entries[STACKMOTIONBUFFERSIZE];
96 } MotionBufferRec, *MotionBuffer;
97 
98 #define MOTIONFILTER		16
99 
100 /********    Static Function Declarations    ********/
101 
102 static void GetRefForeground(
103                         Widget widget,
104                         int offset,
105                         XrmValue *value) ;
106 static void CopyRefForeground(
107                         Widget widget,
108                         int offset,
109                         XrmValue *value) ;
110 static void GetRefBackground(
111                         Widget widget,
112                         int offset,
113                         XrmValue *value) ;
114 static void DragContextInitialize(
115                         Widget req,
116                         Widget new_w,
117                         ArgList args,
118                         Cardinal *numArgs) ;
119 static Boolean DragContextSetValues(
120                         Widget old,
121                         Widget ref,
122                         Widget new_w,
123                         Arg *args,
124                         Cardinal *numArgs) ;
125 static void DragContextDestroy(
126                         Widget w) ;
127 static void DragContextClassInitialize( void ) ;
128 static void DragContextClassPartInitialize( WidgetClass ) ;
129 static Window GetClientWindow(
130                         Display *dpy,
131                         Window win,
132                         Atom atom) ;
133 static void ValidateDragOver(
134                         XmDragContext dc,
135                         unsigned char oldStyle,
136                         unsigned char newStyle) ;
137 static XmDragReceiverInfo FindReceiverInfo(
138                         XmDragContext dc,
139                         Window win) ;
140 static void GetDestinationInfo(
141                         XmDragContext dc,
142                         Window root,
143                         Window win) ;
144 static void GetScreenInfo(
145                         XmDragContext dc) ;
146 static void SendDragMessage(
147                         XmDragContext dc,
148                         Window destination,
149                         unsigned char messageType) ;
150 static void GenerateClientCallback(
151                         XmDragContext dc,
152                         unsigned char reason) ;
153 static void DropLoseIncrSelection(
154                         Widget w,
155                         Atom *selection,
156                         XtPointer clientData) ;
157 static void DropLoseSelection(
158                         Widget w,
159                         Atom *selection) ;
160 static void DragDropFinish(
161                         XmDragContext dc) ;
162 static Boolean DropConvertIncrCallback(
163                         Widget w,
164                         Atom *selection,
165                         Atom *target,
166                         Atom *typeRtn,
167                         XtPointer *valueRtn,
168                         unsigned long *lengthRtn,
169                         int *formatRtn,
170                         unsigned long *maxLengthRtn,
171                         XtPointer clientData,
172                         XtRequestId *requestID) ;
173 static Boolean DropConvertCallback(
174                         Widget w,
175                         Atom *selection,
176                         Atom *target,
177                         Atom *typeRtn,
178                         XtPointer *valueRtn,
179                         unsigned long *lengthRtn,
180                         int *formatRtn) ;
181 static void DragStartProto(
182                         XmDragContext dc) ;
183 static void NewScreen(
184                         XmDragContext dc,
185                         Window newRoot) ;
186 static void LocalNotifyHandler(
187                         Widget w,
188                         XtPointer client,
189                         XtPointer call) ;
190 static void ExternalNotifyHandler(
191                         Widget w,
192                         XtPointer client,
193                         XtPointer call) ;
194 static void InitiatorMsgHandler(
195                         Widget w,
196                         XtPointer clientData,
197                         XEvent *event,
198                         Boolean *dontSwallow) ;
199 static void SiteEnteredWithLocalSource(
200                         Widget w,
201                         XtPointer client,
202                         XtPointer call) ;
203 static void SiteLeftWithLocalSource(
204                         Widget w,
205                         XtPointer client,
206                         XtPointer call) ;
207 static void OperationChanged(
208                         Widget w,
209                         XtPointer client,
210                         XtPointer call) ;
211 static void SiteMotionWithLocalSource(
212                         Widget w,
213                         XtPointer client,
214                         XtPointer call) ;
215 static void DropStartConfirmed(
216                         Widget w,
217                         XtPointer client,
218                         XtPointer call) ;
219 static Widget GetShell(
220                         Widget w) ;
221 static void InitDropSiteManager(
222                         XmDragContext dc) ;
223 static void TopWindowsReceived(
224                         Widget w,
225                         XtPointer client_data,
226                         Atom *selection,
227                         Atom *type,
228                         XtPointer value,
229                         unsigned long *length,
230                         int *format) ;
231 static void DragStart(
232                         XmDragContext dc,
233                         Widget src,
234                         XEvent *event) ;
235 static void DragStartWithTracking(
236                         XmDragContext dc) ;
237 static void UpdateMotionBuffer(
238 			XmDragContext dc,
239                         MotionBuffer mb,
240                         XEvent *event) ;
241 static void DragMotionProto(
242                         XmDragContext dc,
243                         Window root,
244                         Window subWindow) ;
245 static void ProcessMotionBuffer(
246                         XmDragContext dc,
247                         MotionBuffer mb) ;
248 static void DragMotion(
249                         Widget w,
250                         XEvent *event,
251                         String *params,
252                         Cardinal *numParams) ;
253 static void DragKey(
254                         Widget w,
255                         XEvent *event,
256                         String *params,
257                         Cardinal *numParams) ;
258 static void DropStartTimeout(
259                         XtPointer clientData,
260                         XtIntervalId *id) ;
261 static void DropFinishTimeout(
262                         XtPointer clientData,
263                         XtIntervalId *id) ;
264 static void FinishAction(
265                         XmDragContext dc,
266                         XEvent *ev) ;
267 static void CheckModifiers(
268                         XmDragContext dc,
269                         unsigned int state) ;
270 static void IgnoreButtons(
271                         Widget w,
272                         XEvent *event,
273                         String *params,
274                         Cardinal *numParams) ;
275 static void CancelDrag(
276                         Widget w,
277                         XEvent *event,
278                         String *params,
279                         Cardinal *numParams) ;
280 static void HelpDrag(
281                         Widget w,
282                         XEvent *event,
283                         String *params,
284                         Cardinal *numParams) ;
285 static void FinishDrag(
286                         Widget w,
287                         XEvent *event,
288                         String *params,
289                         Cardinal *numParams) ;
290 static void InitiatorMainLoop(
291                         XtPointer clientData,
292                         XtIntervalId *id) ;
293 static void DragCancel(
294                         XmDragContext dc) ;
295 static void CalculateDragOperation(
296 			XmDragContext dc) ;
297 static void cancelDrag(
298                         Widget w,
299                         XtPointer client,
300                         XtPointer call) ;
301 static void noMoreShell (
302                         Widget w,
303                         XtPointer client,
304                         XtPointer call) ;
305 
306 /********    End Static Function Declarations    ********/
307 
308 
309 static XtActionsRec	dragContextActions[] =
310 {
311     {"FinishDrag"	, FinishDrag	},
312     {"CancelDrag"	, CancelDrag	},
313     {"HelpDrag"		, HelpDrag	},
314     {"DragMotion"	, DragMotion	},
315     {"DragKey"		, DragKey	},
316     {"IgnoreButtons"	, IgnoreButtons	},
317 };
318 
319 static XmConst unsigned char	protocolMatrix[7][6] = {
320 
321     /*
322      *
323      * Rows are initiator styles, Columns are receiver styles.
324      *
325      * Receiver     NO   DO   PP   P    PD   D
326      * Initiator  -------------------------------
327      *      NO    | NO | NO | NO | NO | NO | NO |
328      *      DO    | NO | DO | DO | DO | DO | DO |
329      *      PP    | NO | DO | P  | P  | P  | D  |
330      *      P     | NO | DO | P  | P  | P  | DO |
331      *      PD    | NO | DO | D  | P  | D  | D  |
332      *      D     | NO | DO | D  | DO | D  | D  |
333      *      PR    | NO | DO | P  | P  | D  | D  |
334      */
335 
336 
337     { /* Initiator == XmDRAG_NONE ==   0 */
338 	XmDRAG_NONE,        XmDRAG_NONE,        XmDRAG_NONE,
339 	XmDRAG_NONE,        XmDRAG_NONE,        XmDRAG_NONE,
340     },
341     { /* Initiator == DROP_ONLY ==      1 */
342 	XmDRAG_NONE,        XmDRAG_DROP_ONLY,   XmDRAG_DROP_ONLY,
343 	XmDRAG_DROP_ONLY,   XmDRAG_DROP_ONLY,   XmDRAG_DROP_ONLY,
344     },
345     { /* Initiator == PREFER_PREREG ==  2 */
346 	XmDRAG_NONE,        XmDRAG_DROP_ONLY,   XmDRAG_PREREGISTER,
347 	XmDRAG_PREREGISTER, XmDRAG_PREREGISTER, XmDRAG_DYNAMIC,
348     },
349     { /* Initiator == PREREG ==         3 */
350 	 XmDRAG_NONE,        XmDRAG_DROP_ONLY,   XmDRAG_PREREGISTER,
351 	 XmDRAG_PREREGISTER, XmDRAG_PREREGISTER, XmDRAG_DROP_ONLY,
352     },
353     { /* Initiator == PREFER_DYNAMIC == 4 */
354 	 XmDRAG_NONE,        XmDRAG_DROP_ONLY,   XmDRAG_DYNAMIC,
355 	 XmDRAG_PREREGISTER, XmDRAG_DYNAMIC,     XmDRAG_DYNAMIC,
356     },
357     { /* Initiator == XmDRAG_DYNAMIC == 5 */
358 	 XmDRAG_NONE,        XmDRAG_DROP_ONLY,   XmDRAG_DYNAMIC,
359 	 XmDRAG_DROP_ONLY,   XmDRAG_DYNAMIC,     XmDRAG_DYNAMIC,
360     },
361     { /* Initiator == DRAG_RECEIVER ==  6 */
362 	 XmDRAG_NONE,        XmDRAG_DROP_ONLY,   XmDRAG_PREREGISTER,
363 	 XmDRAG_PREREGISTER, XmDRAG_DYNAMIC,     XmDRAG_DYNAMIC,
364     },
365 };
366 
367 /***************************************************************************
368  *
369  * Default values for resource lists
370  *
371  ***************************************************************************/
372 
373 #define Offset(x)	(XtOffsetOf(XmDragContextRec, x))
374 
375 static XtResource dragContextResources[] =
376 {
377     {
378 	XmNsourceWidget, XmCSourceWidget, XmRWidget,
379 	sizeof(Widget), Offset(drag.sourceWidget),
380 	XmRImmediate, (XtPointer)NULL,
381     },
382     {
383 	XmNexportTargets, XmCExportTargets, XmRAtomList,
384 	sizeof(Atom *), Offset(drag.exportTargets),
385 	XmRImmediate, (XtPointer)NULL,
386     },
387     {
388 	XmNnumExportTargets, XmCNumExportTargets, XmRInt,
389 	sizeof(Cardinal), Offset(drag.numExportTargets),
390 	XmRImmediate, (XtPointer)0,
391     },
392     {
393 	XmNconvertProc, XmCConvertProc, XmRFunction,
394 	sizeof(XmConvertSelectionRec), Offset(drag.convertProc),
395 	XmRImmediate, (XtPointer)NULL,
396     },
397     {
398 	XmNclientData, XmCClientData, XmRPointer,
399 	sizeof(XtPointer), Offset(drag.clientData),
400 	XmRImmediate, (XtPointer)NULL,
401     },
402     {
403 	XmNincremental, XmCIncremental, XmRBoolean,
404 	sizeof(Boolean), Offset(drag.incremental),
405 	XmRImmediate, (XtPointer)NULL,
406     },
407     {
408 	XmNdragOperations, XmCDragOperations, XmRUnsignedChar,
409 	sizeof(unsigned char), Offset(drag.dragOperations),
410 	XmRImmediate, (XtPointer)(XmDROP_COPY | XmDROP_MOVE),
411     },
412     {
413 	XmNsourceCursorIcon, XmCSourceCursorIcon,
414 	XmRWidget, sizeof(Widget),
415 	Offset(drag.sourceCursorIcon), XmRImmediate, (XtPointer)NULL,
416     },
417     {
418 	XmNsourcePixmapIcon, XmCSourcePixmapIcon,
419 	XmRWidget, sizeof(Widget),
420 	Offset(drag.sourcePixmapIcon), XmRImmediate, (XtPointer)NULL,
421     },
422     {
423 	XmNstateCursorIcon, XmCStateCursorIcon,
424 	XmRWidget, sizeof(Widget),
425 	Offset(drag.stateCursorIcon), XmRImmediate, (XtPointer)NULL,
426     },
427     {
428 	XmNoperationCursorIcon, XmCOperationCursorIcon,
429 	XmRWidget, sizeof(Widget),
430 	Offset(drag.operationCursorIcon), XmRImmediate, (XtPointer)NULL,
431     },
432     {
433 	XmNcursorBackground, XmCCursorBackground, XmRPixel,
434 	sizeof(Pixel), Offset(drag.cursorBackground), XmRCallProc,
435 	(XtPointer)GetRefBackground,
436     },
437     {
438 	XmNcursorForeground, XmCCursorForeground, XmRPixel,
439 	sizeof(Pixel), Offset(drag.cursorForeground), XmRCallProc, (XtPointer)GetRefForeground,
440     },
441     {
442 	XmNvalidCursorForeground, XmCValidCursorForeground, XmRPixel,
443 	sizeof(Pixel), Offset(drag.validCursorForeground), XmRCallProc, (XtPointer)CopyRefForeground,
444     },
445     {
446 	XmNinvalidCursorForeground, XmCInvalidCursorForeground,
447 	XmRPixel, sizeof(Pixel), Offset(drag.invalidCursorForeground),
448 	XmRCallProc, (XtPointer)CopyRefForeground,
449     },
450     {
451 	XmNnoneCursorForeground, XmCNoneCursorForeground, XmRPixel,
452 	sizeof(Pixel), Offset(drag.noneCursorForeground),
453 	XmRCallProc, (XtPointer)CopyRefForeground,
454     },
455     {
456 	XmNdropSiteEnterCallback, XmCCallback, XmRCallback,
457         sizeof(XtCallbackList), Offset(drag.siteEnterCallback),
458         XmRImmediate, (XtPointer)NULL,
459     },
460     {
461 	XmNdropSiteLeaveCallback, XmCCallback, XmRCallback,
462         sizeof(XtCallbackList), Offset(drag.siteLeaveCallback),
463         XmRImmediate, (XtPointer)NULL,
464     },
465     {
466 	XmNtopLevelEnterCallback, XmCCallback, XmRCallback,
467         sizeof(XtCallbackList), Offset(drag.topLevelEnterCallback),
468         XmRImmediate, (XtPointer)NULL,
469     },
470     {
471 	XmNdragMotionCallback, XmCCallback, XmRCallback,
472         sizeof(XtCallbackList), Offset(drag.dragMotionCallback),
473         XmRImmediate, (XtPointer)NULL,
474     },
475     {
476 	XmNtopLevelLeaveCallback, XmCCallback, XmRCallback,
477         sizeof(XtCallbackList), Offset(drag.topLevelLeaveCallback),
478         XmRImmediate, (XtPointer)NULL,
479     },
480     {
481 	XmNdropStartCallback, XmCCallback, XmRCallback,
482         sizeof(XtCallbackList), Offset(drag.dropStartCallback),
483         XmRImmediate, (XtPointer)NULL,
484     },
485     {
486 	XmNdragDropFinishCallback, XmCCallback, XmRCallback,
487         sizeof(XtCallbackList), Offset(drag.dragDropFinishCallback),
488         XmRImmediate, (XtPointer)NULL,
489     },
490     {
491 	XmNdropFinishCallback, XmCCallback, XmRCallback,
492         sizeof(XtCallbackList), Offset(drag.dropFinishCallback),
493         XmRImmediate, (XtPointer)NULL,
494     },
495     {
496 	XmNoperationChangedCallback, XmCCallback, XmRCallback,
497         sizeof(XtCallbackList), Offset(drag.operationChangedCallback),
498         XmRImmediate, (XtPointer)NULL,
499     },
500     {
501 	XmNblendModel, XmCBlendModel,
502 	XmRBlendModel,
503         sizeof(unsigned char), Offset(drag.blendModel),
504         XmRImmediate, (XtPointer)XmBLEND_ALL,
505     },
506     {
507 	XmNsourceIsExternal, XmCSourceIsExternal, XmRBoolean,
508         sizeof(Boolean), Offset(drag.sourceIsExternal),
509         XmRImmediate, (XtPointer)False,
510     },
511     {
512 	XmNsourceWindow, XmCSourceWindow, XmRWindow,
513         sizeof(Window), Offset(drag.srcWindow),
514         XmRImmediate, (XtPointer)None,
515     },
516     {
517 	XmNstartTime, XmCStartTime, XmRInt,
518         sizeof(Time), Offset(drag.dragStartTime),
519         XmRImmediate, (XtPointer)0,
520     },
521     {
522 	XmNiccHandle, XmCICCHandle, XmRAtom,
523         sizeof(Atom), Offset(drag.iccHandle),
524         XmRImmediate, (XtPointer)None,
525     },
526 };
527 
528 
529 
530 externaldef(xmdragcontextclassrec)
531 XmDragContextClassRec xmDragContextClassRec = {
532     {
533 	(WidgetClass) &coreClassRec,	/* superclass	*/
534 	"XmDragContext",		/* class_name 		*/
535 	sizeof(XmDragContextRec),	/* size 		*/
536 	DragContextClassInitialize,	/* Class Initializer 	*/
537 	DragContextClassPartInitialize,	/* class_part_init 	*/
538 	FALSE, 				/* Class init'ed ? 	*/
539 	DragContextInitialize,		/* initialize         	*/
540 	NULL, 				/* initialize_notify    */
541 	XtInheritRealize,		/* realize            	*/
542 	dragContextActions,		/* actions		*/
543 	XtNumber(dragContextActions),	/* num_actions        	*/
544 	dragContextResources,		/* resources          	*/
545 	XtNumber(dragContextResources),/* resource_count    	*/
546 	NULLQUARK, 			/* xrm_class          	*/
547 	FALSE, 				/* compress_motion    	*/
548 	XtExposeNoCompress, 		/* compress_exposure  	*/
549 	FALSE, 				/* compress_enterleave	*/
550 	FALSE, 				/* visible_interest   	*/
551 	DragContextDestroy,		/* destroy            	*/
552 	NULL,		 		/* resize             	*/
553 	NULL, 				/* expose             	*/
554 	DragContextSetValues,		/* set_values         	*/
555 	NULL, 				/* set_values_hook      */
556 	NULL,			 	/* set_values_almost    */
557 	NULL,				/* get_values_hook      */
558 	NULL, 				/* accept_focus       	*/
559 	XtVersion, 			/* intrinsics version 	*/
560 	NULL, 				/* callback offsets   	*/
561 	_XmDragC_defaultTranslations,	/* tm_table           	*/
562 	NULL, 				/* query_geometry       */
563 	NULL, 				/* display_accelerator  */
564 	NULL, 				/* extension            */
565     },
566     {					/* dragContext	*/
567 	DragStart,			/* start		*/
568 	DragCancel,			/* cancel		*/
569 	NULL,				/* extension record	*/
570     },
571 };
572 
573 externaldef(dragContextclass) WidgetClass
574       xmDragContextClass = (WidgetClass) &xmDragContextClassRec;
575 
576 /*ARGSUSED*/
577 static void
GetRefForeground(Widget widget,int offset,XrmValue * value)578 GetRefForeground(
579         Widget widget,
580         int offset,
581         XrmValue *value )
582 {
583     static Pixel	pixel;
584 
585     XmDragContext	dc = (XmDragContext)widget;
586     Widget		sw = dc->drag.sourceWidget;
587 
588     pixel = BlackPixelOfScreen(XtScreen(widget));
589 
590     value->addr = (XPointer)(&pixel);
591     value->size = sizeof(Pixel);
592 
593     if (sw) {
594 	if (XmIsGadget(sw))
595 	  pixel = ((XmManagerWidget)(XtParent(sw)))->manager.foreground;
596 	else if (XmIsPrimitive(sw))
597 	  pixel = ((XmPrimitiveWidget)sw)->primitive.foreground;
598 	else if (XmIsManager(sw))
599 	  pixel = ((XmManagerWidget)sw)->manager.foreground;
600     }
601 } /* GetRefForeground */
602 
603 
604 /*ARGSUSED*/
605 static void
CopyRefForeground(Widget widget,int offset,XrmValue * value)606 CopyRefForeground(
607         Widget widget,
608         int offset,
609         XrmValue *value )
610 {
611     XmDragContext	dc = (XmDragContext)widget;
612 
613     value->addr = (XPointer)(&dc->drag.cursorForeground);
614     value->size = sizeof(Pixel);
615 } /* CopyRefForeground */
616 
617 
618 /*ARGSUSED*/
619 static void
GetRefBackground(Widget widget,int offset,XrmValue * value)620 GetRefBackground(
621         Widget widget,
622         int offset,
623         XrmValue *value )
624 {
625     static Pixel	pixel;
626 
627     XmDragContext	dc = (XmDragContext)widget;
628     Widget		sw = dc->drag.sourceWidget;
629 
630     pixel = WhitePixelOfScreen(XtScreen(dc));
631 
632     value->addr = (XPointer)(&pixel);
633     value->size = sizeof(Pixel);
634 
635     if (sw) {
636 	if (XmIsGadget(sw))
637 	  pixel = ((XmManagerWidget)(XtParent(sw)))->core.background_pixel;
638 	else
639 	  pixel = sw->core.background_pixel;
640     }
641 } /* GetRefBackground */
642 
643 
644 /*ARGSUSED*/
645 static void
DragContextInitialize(Widget req,Widget new_w,ArgList args,Cardinal * numArgs)646 DragContextInitialize(
647         Widget req,
648         Widget new_w,
649         ArgList args,
650         Cardinal *numArgs )
651 {
652     XmDragContext	dc = (XmDragContext)new_w;
653 
654     dc->drag.roundOffTime = 50;
655 
656     dc->drag.dragFinishTime =
657       dc->drag.dropFinishTime = 0;
658 
659     dc->drag.inDropSite = False;
660     dc->drag.dragTimerId = (XtIntervalId) NULL;
661     dc->drag.activeBlendModel = dc->drag.blendModel;
662     dc->drag.trackingMode = XmDRAG_TRACK_MOTION ;
663     dc->drag.curDragOver = dc->drag.origDragOver = NULL;
664     dc->drag.startX = dc->drag.startY = 0;
665 
666     dc->drag.SaveEventMask = 0L;
667 
668     InitDropSiteManager(dc);
669 
670     if (dc->drag.exportTargets) {
671 	unsigned int 	size;
672 	size = sizeof(Atom) * dc->drag.numExportTargets;
673 	dc->drag.exportTargets = (Atom *)
674 	  _XmAllocAndCopy(dc->drag.exportTargets, size);
675     }
676     dc->core.x =
677       dc->core.y = 0;
678     dc->core.width =
679       dc->core.height = 16;
680 
681     /* pixel values in drag context refer to the source widget's colormap */
682     if (dc->drag.sourceWidget)  {
683 	Widget sw = dc->drag.sourceWidget;
684 	dc->core.colormap = XmIsGadget(sw) ?
685 	    XtParent(sw)->core.colormap : sw->core.colormap;
686     }
687 
688    XtRealizeWidget((Widget)dc);
689 
690     dc->drag.currReceiverInfo =
691       dc->drag.receiverInfos = NULL;
692     dc->drag.numReceiverInfos =
693       dc->drag.maxReceiverInfos = 0;
694 
695     dc->drag.dragDropCancelEffect = False;
696 }
697 
698 /*ARGSUSED*/
699 static Boolean
DragContextSetValues(Widget old,Widget ref,Widget new_w,Arg * args,Cardinal * numArgs)700 DragContextSetValues(
701         Widget old,
702         Widget ref,
703         Widget new_w,
704         Arg *args,
705         Cardinal *numArgs )
706 {
707     XmDragContext	oldDC = (XmDragContext)old;
708     XmDragContext	newDC = (XmDragContext)new_w;
709     XmDragOverShellWidget dos = newDC->drag.curDragOver;
710 
711     if (oldDC->drag.exportTargets != newDC->drag.exportTargets) {
712 	if (oldDC->drag.exportTargets) /* should have been freed */
713 	  XtFree( (char *)oldDC->drag.exportTargets);
714 	if (newDC->drag.exportTargets) {
715 	    unsigned int 	size;
716 	    size = sizeof(Atom) * newDC->drag.numExportTargets;
717 	    newDC->drag.exportTargets = (Atom *)
718 	      _XmAllocAndCopy(newDC->drag.exportTargets, size);
719 	}
720     }
721     if ( oldDC->drag.operationCursorIcon != newDC->drag.operationCursorIcon ||
722       oldDC->drag.sourceCursorIcon != newDC->drag.sourceCursorIcon ||
723       oldDC->drag.sourcePixmapIcon != newDC->drag.sourcePixmapIcon ||
724       oldDC->drag.stateCursorIcon != newDC->drag.stateCursorIcon ||
725       oldDC->drag.cursorBackground != newDC->drag.cursorBackground ||
726       oldDC->drag.cursorForeground != newDC->drag.cursorForeground ||
727       oldDC->drag.noneCursorForeground != newDC->drag.noneCursorForeground ||
728       oldDC->drag.invalidCursorForeground !=
729                                newDC->drag.invalidCursorForeground ||
730       oldDC->drag.validCursorForeground !=
731                                newDC->drag.validCursorForeground) {
732       _XmDragOverChange((Widget)dos, dos->drag.cursorState);
733     }
734     return False;
735 }
736 
737 static void
DragContextDestroy(Widget w)738 DragContextDestroy(
739         Widget w )
740 {
741   XmDragContext	dc = (XmDragContext)w;
742   Cardinal		i;
743 
744   /* Fix CR 5556:  Restore root event mask saved at DragStart time */
745    if (0 != dc->drag.SaveEventMask)
746       XSelectInput(XtDisplay(dc), dc->drag.currWmRoot, dc->drag.SaveEventMask);
747 
748   if (dc->drag.exportTargets)
749     XtFree((char *)dc->drag.exportTargets);
750 
751   dc->drag.exportTargets = NULL;
752 
753   if (dc->drag.dragTimerId)
754     {
755       XtRemoveTimeOut(dc->drag.dragTimerId);
756       dc->drag.dragTimerId = (XtIntervalId) NULL;
757     }
758 
759   if (dc->drag.receiverInfos)
760     {
761 #ifdef MULTI_SCREEN_DONE
762       if (dc->drag.trackingMode != XmDRAG_TRACK_MOTION)
763 	{
764 	  EventMask mask;
765 	  XmDragReceiverInfo info;
766 
767 	  for (i = 1; i < dc->drag.numReceiverInfos; i++)
768 	    {
769 	      info = &(dc->drag.receiverInfos[i]);
770 
771 	      if (info->shell)
772 		mask = XtBuildEventMask(info->shell);
773 	      else
774 		mask = 0;
775 
776 	      XSelectInput(XtDisplay(w), info->window, mask);
777 	    }
778 	}
779 #endif /* MULTI_SCREEN_DONE */
780       XtFree((char *)dc->drag.receiverInfos);
781     }
782 }
783 
784 static void
DragContextClassInitialize(void)785 DragContextClassInitialize( void )
786 {
787   /* The applications should call XtRegisterGrabAction. */
788 }
789 
790 static void
DragContextClassPartInitialize(WidgetClass wc)791 DragContextClassPartInitialize( WidgetClass wc )
792 {
793   _XmFastSubclassInit (wc, XmDRAG_CONTEXT_BIT);
794 }
795 
796 static Window
GetClientWindow(Display * dpy,Window win,Atom atom)797 GetClientWindow(
798         Display *dpy,
799         Window win,
800         Atom atom )
801 {
802     Window 		root, parent;
803     Window 		*children;
804     unsigned int 	nchildren;
805     int		 	i;
806     Atom 		type = None;
807     int 		format;
808     unsigned long 	nitems, after;
809     unsigned char 	*data = NULL;
810     Window 		inf = 0;
811 
812     XGetWindowProperty(dpy, win, atom, 0, 0, False, AnyPropertyType,
813 		       &type, &format, &nitems, &after, &data);
814     if (data)
815 	XFree(data);
816 
817     if (type)
818       return win;
819     else {
820 	if (!XQueryTree(dpy, win, &root, &parent, &children, &nchildren) ||
821 	    (nchildren == 0))
822 	  return 0;
823 	for (i = nchildren - 1; i >= 0; i--) {
824 	    if ((inf = GetClientWindow(dpy, children[i], atom)) != 0) {
825 	      XFree(children);
826 	      return inf;
827 	    }
828 	}
829 	XFree(children);
830     }
831     return 0;
832 }
833 
834 static void
ValidateDragOver(XmDragContext dc,unsigned char oldStyle,unsigned char newStyle)835 ValidateDragOver(
836         XmDragContext dc,
837         unsigned char oldStyle,
838         unsigned char newStyle )
839 {
840   Arg		args[1];
841   XmDisplay	xmDisplay = (XmDisplay)XtParent(dc);
842   unsigned char initiator = XmDRAG_NONE;
843 
844   initiator = xmDisplay->display.dragInitiatorProtocolStyle;
845 
846   if (newStyle != oldStyle)
847     {
848       /*
849        * If we're not still waiting to hear from the window manager,
850        * and we're not running dynamic, then we can grab.
851        */
852       if ((dc->drag.trackingMode != XmDRAG_TRACK_WM_QUERY_PENDING) &&
853 	  (newStyle != XmDRAG_DYNAMIC) &&
854 	  (initiator != XmDRAG_DYNAMIC) &&
855 	  (initiator != XmDRAG_PREFER_DYNAMIC))
856 	{
857 	  if (!dc->drag.serverGrabbed)
858 	    {
859 	      XGrabServer(XtDisplay(dc));
860 	      dc->drag.serverGrabbed = True;
861 	      XtSetArg(args[0], XmNdragOverMode, XmPIXMAP);
862 	      XtSetValues( (Widget)dc->drag.curDragOver, args, 1);
863 	    }
864 	}
865       else
866 	{
867 	  if (dc->drag.serverGrabbed)
868 	    {
869 	      XUngrabServer(XtDisplay(dc));
870 	      dc->drag.serverGrabbed = False;
871 	      if (xmDisplay -> display.displayHasShapeExtension)
872 		XtSetArg(args[0], XmNdragOverMode, XmDRAG_WINDOW);
873 	      else
874 		XtSetArg(args[0], XmNdragOverMode, XmCURSOR);
875 	      XtSetValues( (Widget)dc->drag.curDragOver, args, 1);
876 	    }
877 	}
878     }
879 }
880 
881 
882 static XmDragReceiverInfo
FindReceiverInfo(XmDragContext dc,Window win)883 FindReceiverInfo(
884         XmDragContext dc,
885         Window win )
886 {
887     Cardinal	i;
888     XmDragReceiverInfo info = NULL;
889 
890     for (i = 0; i < dc->drag.numReceiverInfos; i++) {
891 	info = &dc->drag.receiverInfos[i];
892 	if ((info->frame == win) || (info->window == win))
893 	  break;
894     }
895     if (i < dc->drag.numReceiverInfos)
896       return info;
897     else
898       return NULL;
899 }
900 
901 XmDragReceiverInfo
_XmAllocReceiverInfo(XmDragContext dc)902 _XmAllocReceiverInfo(
903         XmDragContext dc )
904 {
905     Cardinal	offset = 0;
906 
907     if (dc->drag.currReceiverInfo) {
908 	offset = (Cardinal) (dc->drag.currReceiverInfo -
909 			     dc->drag.receiverInfos);
910     }
911     if (dc->drag.numReceiverInfos == dc->drag.maxReceiverInfos) {
912 	dc->drag.maxReceiverInfos = dc->drag.maxReceiverInfos*2 + 2;
913 	dc->drag.receiverInfos = (XmDragReceiverInfoStruct *)
914 	  XtRealloc((char*)dc->drag.receiverInfos,
915 		    dc->drag.maxReceiverInfos *
916 		    sizeof(XmDragReceiverInfoStruct));
917     }
918     if (offset)
919       dc->drag.currReceiverInfo = &(dc->drag.receiverInfos[offset]);
920     dc->drag.rootReceiverInfo = dc->drag.receiverInfos;
921     return &(dc->drag.receiverInfos[dc->drag.numReceiverInfos++]);
922 }
923 
924 /* Find a window with WM_STATE, else return win itself, as per ICCCM */
925 /*ARGSUSED*/
926 static void
GetDestinationInfo(XmDragContext dc,Window root,Window win)927 GetDestinationInfo(
928         XmDragContext dc,
929 	Window root,
930         Window win )
931 {
932     Window	 	clientWin = win;
933     Display		*dpy = XtDisplayOfObject((Widget) dc);
934     Atom 		WM_STATE =  XInternAtom(dpy, XmSWM_STATE, True);
935     unsigned char 	oldStyle = dc->drag.activeProtocolStyle;
936     XmDragReceiverInfo 	currReceiverInfo;
937 
938     dc->drag.crossingTime = dc->drag.lastChangeTime;
939 
940     currReceiverInfo =
941       dc->drag.currReceiverInfo = FindReceiverInfo(dc, win);
942 
943     /*
944      * check for bootstrap case
945      */
946     if ((dc->drag.trackingMode == XmDRAG_TRACK_MOTION) &&
947 	(XtWindow(dc->drag.srcShell) == win) &&
948 	(!currReceiverInfo ||
949 	 (currReceiverInfo->frame == currReceiverInfo->window))) {
950 	Window		currRoot = dc->drag.currWmRoot;
951 	int 		root_x, root_y;
952         Position	rel_x, rel_y;
953 	/*
954 	 * set frame (win) to something reasonable
955 	 */
956         rel_x = dc->drag.startX - dc->drag.srcShell->core.x;
957         rel_y = dc->drag.startY - dc->drag.srcShell->core.y;
958 
959         if (rel_x < 0) rel_x = 0;
960 	if (rel_y < 0) rel_y = 0;
961 
962 	(void) XTranslateCoordinates(XtDisplayOfObject((Widget) dc),
963 				     win, currRoot,
964 				     rel_x, rel_y,
965 				     &root_x, &root_y,
966 				     &win);
967 	if (currReceiverInfo)
968 	  currReceiverInfo->frame = win;
969     }
970 
971     if (currReceiverInfo == NULL) {
972 	if (clientWin == win) {
973 	    if ((clientWin = GetClientWindow(dpy, win, WM_STATE)) == 0)
974 	      clientWin = win;
975 	}
976 	currReceiverInfo =
977 	  dc->drag.currReceiverInfo = _XmAllocReceiverInfo(dc);
978 	currReceiverInfo->frame = win;
979 	currReceiverInfo->window = clientWin;
980 	currReceiverInfo->shell = XtWindowToWidget(dpy, clientWin);
981     }
982 
983     /*
984      * we fetch the root info in NewScreen
985      */
986     if (currReceiverInfo != dc->drag.rootReceiverInfo /* is it the root ? */) {
987       if (!currReceiverInfo->shell) {
988 	if (_XmGetDragReceiverInfo(dpy,
989 				   currReceiverInfo->window,
990 				   currReceiverInfo))
991 	  {
992 	    switch (currReceiverInfo->dragProtocolStyle) {
993 	    case XmDRAG_PREREGISTER:
994 	    case XmDRAG_PREFER_PREREGISTER:
995 	    case XmDRAG_PREFER_DYNAMIC:
996 	      break;
997 	    case XmDRAG_DYNAMIC:
998 	    case XmDRAG_DROP_ONLY:
999 	    case XmDRAG_NONE:
1000 	      /* free the data returned by the icc layer */
1001 	      _XmFreeDragReceiverInfo(currReceiverInfo->iccInfo);
1002 	      break;
1003 	    }
1004 	  }
1005       } else {
1006 	XmDisplay	xmDisplay = (XmDisplay)XtParent(dc);
1007 
1008 	/*
1009 	 * We only have a protocol style if we have drop sites.
1010 	 */
1011 	if (_XmDropSiteShell(dc->drag.currReceiverInfo->shell))
1012 	  currReceiverInfo->dragProtocolStyle =
1013 	    xmDisplay->display.dragReceiverProtocolStyle;
1014 	else
1015 	  currReceiverInfo->dragProtocolStyle = XmDRAG_NONE;
1016 
1017 	currReceiverInfo->xOrigin = dc->drag.currReceiverInfo->shell->core.x;
1018 	currReceiverInfo->yOrigin = dc->drag.currReceiverInfo->shell->core.y;
1019 	currReceiverInfo->width = dc->drag.currReceiverInfo->shell->core.width;
1020 	currReceiverInfo->height = dc->drag.currReceiverInfo->shell->core.height;
1021 	currReceiverInfo->depth = dc->drag.currReceiverInfo->shell->core.depth;
1022 	currReceiverInfo->iccInfo = NULL;
1023       }
1024     }
1025 
1026     /*
1027      * If we're still waiting on the window manager, then don't mess
1028      * with the active protocol style.
1029      */
1030     if (dc->drag.trackingMode != XmDRAG_TRACK_WM_QUERY_PENDING)
1031       {
1032 	dc->drag.activeProtocolStyle =
1033 	  _XmGetActiveProtocolStyle((Widget)dc);
1034 
1035 	ValidateDragOver(dc, oldStyle, dc->drag.activeProtocolStyle);
1036       }
1037 }
1038 
1039 
1040 static void
GetScreenInfo(XmDragContext dc)1041 GetScreenInfo(
1042         XmDragContext dc )
1043 {
1044     Display	*dpy = XtDisplay(dc);
1045     Window	root = RootWindowOfScreen(XtScreen(dc->drag.curDragOver));
1046     XmDragReceiverInfo rootInfo;
1047 
1048     /*
1049      * the rootInfo is the first entry in the receiverInfo
1050      * array
1051      */
1052 
1053     if (dc->drag.numReceiverInfos == 0) {
1054 	dc->drag.rootReceiverInfo =
1055 	  rootInfo = _XmAllocReceiverInfo(dc);
1056     } else {
1057 	dc->drag.rootReceiverInfo =
1058 	  rootInfo = dc->drag.receiverInfos;
1059     }
1060 
1061     rootInfo->frame = None;
1062     rootInfo->window = root;
1063     rootInfo->shell = XtWindowToWidget(dpy, root);
1064     rootInfo->xOrigin = rootInfo->yOrigin = 0;
1065     rootInfo->width = XWidthOfScreen(dc->drag.currScreen);
1066     rootInfo->height = XHeightOfScreen(dc->drag.currScreen);
1067     rootInfo->depth = DefaultDepthOfScreen(dc->drag.currScreen);
1068     rootInfo->iccInfo = NULL;
1069 
1070     if (_XmGetDragReceiverInfo(dpy, root, rootInfo))
1071       {
1072 	  switch (rootInfo->dragProtocolStyle) {
1073 	    case XmDRAG_PREREGISTER:
1074 	    case XmDRAG_PREFER_PREREGISTER:
1075 	    case XmDRAG_PREFER_DYNAMIC:
1076 	      break;
1077 	    case XmDRAG_DYNAMIC:
1078 	    case XmDRAG_DROP_ONLY:
1079 	    case XmDRAG_NONE:
1080 	      /* free the data returned by the icc layer */
1081 	      _XmFreeDragReceiverInfo(rootInfo->iccInfo);
1082 	      break;
1083 	  }
1084       }
1085 }
1086 
1087 
1088 static void
SendDragMessage(XmDragContext dc,Window destination,unsigned char messageType)1089 SendDragMessage(
1090         XmDragContext dc,
1091         Window destination,
1092         unsigned char messageType )
1093 {
1094     XmDropSiteManagerObject dsm = (XmDropSiteManagerObject)
1095 		_XmGetDropSiteManagerObject((XmDisplay)(XtParent(dc)));
1096     XmICCCallbackStruct	callbackRec;
1097     int			reason = _XmMessageTypeToReason(messageType);
1098 
1099     callbackRec.any.event = NULL;
1100 
1101     if ((dc->drag.activeProtocolStyle == XmDRAG_NONE) ||
1102 	((dc->drag.activeProtocolStyle == XmDRAG_DROP_ONLY) &&
1103 	 (reason != XmCR_DROP_START)))
1104       return;
1105 
1106     switch(callbackRec.any.reason = reason) {
1107       case XmCR_TOP_LEVEL_ENTER:
1108 	{
1109 	    XmTopLevelEnterCallback	callback =
1110 	      (XmTopLevelEnterCallback)&callbackRec;
1111 
1112 	    callback->timeStamp = dc->drag.lastChangeTime;
1113 	    callback->window = dc->drag.srcWindow;
1114 	    callback->dragProtocolStyle = dc->drag.activeProtocolStyle;
1115 	    callback->screen = dc->drag.currScreen;
1116 	    callback->x = dc->drag.currReceiverInfo->xOrigin;
1117 	    callback->y = dc->drag.currReceiverInfo->yOrigin;
1118 	    callback->iccHandle = dc->drag.iccHandle;
1119 	}
1120 	break;
1121       case XmCR_TOP_LEVEL_LEAVE:
1122 	{
1123 	    XmTopLevelLeaveCallback	callback =
1124 	      (XmTopLevelLeaveCallback)&callbackRec;
1125 
1126 	    callback->timeStamp = dc->drag.lastChangeTime;
1127 	    callback->window = dc->drag.srcWindow;
1128 	}
1129 	break;
1130       case XmCR_DRAG_MOTION:
1131 	{
1132 	    XmDragMotionCallback	callback =
1133 	      (XmDragMotionCallback)&callbackRec;
1134 
1135 	    callback->timeStamp = dc->drag.lastChangeTime;
1136 	    callback->x = dc->core.x;
1137 	    callback->y = dc->core.y;
1138 	    callback->operation = dc->drag.operation;
1139 	    callback->operations = dc->drag.operations;
1140 
1141 	    /* Outgoing motion; be conservative */
1142 	    callback->dropSiteStatus = XmNO_DROP_SITE;
1143 	}
1144 	break;
1145       case XmCR_OPERATION_CHANGED:
1146 	{
1147 	    XmOperationChangedCallback	callback =
1148 	      (XmOperationChangedCallback)&callbackRec;
1149 
1150 	    callback->timeStamp = dc->drag.lastChangeTime;
1151 	    callback->operation = dc->drag.operation;
1152 	    callback->operations = dc->drag.operations;
1153 	}
1154 	break;
1155       case XmCR_DROP_START:
1156 	{
1157 	    XmDropStartCallback 	callback =
1158 	      (XmDropStartCallback)&callbackRec;
1159 
1160 	    callback->timeStamp = dc->drag.dragFinishTime;
1161 	    callback->operation = dc->drag.operation;
1162 	    callback->operations = dc->drag.operations;
1163 	    callback->dropAction = dc->drag.dragCompletionStatus;
1164 	    callback->dropSiteStatus = dsm->dropManager.curDropSiteStatus;
1165 	    callback->x = dc->core.x;
1166 	    callback->y = dc->core.y;
1167 	    callback->iccHandle = dc->drag.iccHandle;
1168 	    callback->window = XtWindow(dc->drag.srcShell);
1169 	}
1170 	break;
1171       default:
1172 	break;
1173     }
1174 
1175     /*
1176      * if we're the initiator and the destination isn't us and either
1177      * its the drop message or the dynamic protocol send it to the wire
1178      */
1179     if ((!dc->drag.currReceiverInfo->shell) &&
1180 	(!dc->drag.sourceIsExternal /* sanity check */) &&
1181 	((dc->drag.activeProtocolStyle == XmDRAG_DYNAMIC) ||
1182 	 (reason == XmCR_DROP_START)))
1183       {
1184 	  _XmSendICCCallback(XtDisplayOfObject((Widget) dc), destination,
1185 			     &callbackRec, XmICC_INITIATOR_EVENT);
1186       }
1187     else {
1188 	XtPointer			data;
1189 	XmDragTopLevelClientDataStruct	topLevelData;
1190 	XmDragMotionClientDataStruct	motionData;
1191 
1192 	if ((reason == XmCR_TOP_LEVEL_ENTER)   ||
1193 	    (reason == XmCR_TOP_LEVEL_LEAVE)   ||
1194 	    (reason == XmCR_DROP_START)){
1195 
1196 	    topLevelData.destShell = dc->drag.currReceiverInfo->shell;
1197 	    topLevelData.sourceIsExternal = dc->drag.sourceIsExternal;
1198 	    topLevelData.iccInfo = dc->drag.currReceiverInfo->iccInfo;
1199 	    topLevelData.xOrigin =
1200 			(Position)(dc->drag.currReceiverInfo->xOrigin);
1201 	    topLevelData.yOrigin = (Position)
1202 			(dc->drag.currReceiverInfo->yOrigin);
1203 	    topLevelData.width = (Dimension)
1204 			(dc->drag.currReceiverInfo->width);
1205 	    topLevelData.height = (Dimension)
1206 			(dc->drag.currReceiverInfo->height);
1207 	    topLevelData.window = dc->drag.currReceiverInfo->window;
1208 	    topLevelData.dragOver = (Widget)dc->drag.curDragOver;
1209 	    data = (XtPointer)&topLevelData;
1210 	}
1211 	else if ((reason == XmCR_DRAG_MOTION) ||
1212 	    (reason == XmCR_OPERATION_CHANGED)) {
1213 	    motionData.window = dc->drag.currReceiverInfo->window;
1214 	    motionData.dragOver = (Widget)dc->drag.curDragOver;
1215 	    data = (XtPointer)&motionData;
1216 	}
1217 	else {
1218 		data = NULL;
1219 	}
1220 
1221 	_XmDSMUpdate(dsm,
1222 		     (XtPointer)data,
1223 		     (XtPointer)&callbackRec);
1224     }
1225 }
1226 
1227 static void
GenerateClientCallback(XmDragContext dc,unsigned char reason)1228 GenerateClientCallback(
1229         XmDragContext dc,
1230         unsigned char reason )
1231 {
1232     XmICCCallbackStruct	callbackRec;
1233     XtCallbackList	callbackList = NULL;
1234 
1235     callbackRec.any.event = NULL;
1236 
1237     switch(callbackRec.any.reason = reason) {
1238       case XmCR_TOP_LEVEL_ENTER:
1239 	if ((callbackList = dc->drag.topLevelEnterCallback) != NULL) {
1240 	    XmTopLevelEnterCallback	callback =
1241 	      (XmTopLevelEnterCallback)&callbackRec;
1242 
1243 	    callback->timeStamp = dc->drag.lastChangeTime;
1244 	    callback->window = dc->drag.currReceiverInfo->window;
1245 	    callback->dragProtocolStyle =
1246 	      dc->drag.activeProtocolStyle;
1247 	    callback->screen = dc->drag.currScreen;
1248 	    callback->iccHandle = dc->drag.iccHandle;
1249 	    callback->x = dc->drag.currReceiverInfo->xOrigin;
1250 	    callback->y = dc->drag.currReceiverInfo->yOrigin;
1251 	}
1252 	break;
1253       case XmCR_TOP_LEVEL_LEAVE:
1254 	if ((callbackList = dc->drag.topLevelLeaveCallback) != NULL) {
1255 	    XmTopLevelLeaveCallback	callback =
1256 	      (XmTopLevelLeaveCallback)&callbackRec;
1257 
1258 	    callback->timeStamp = dc->drag.lastChangeTime;
1259 	    callback->screen = dc->drag.currScreen;
1260 	    callback->window = dc->drag.currReceiverInfo->window;
1261 	}
1262 	break;
1263       case XmCR_DRAG_MOTION:
1264 	if ((callbackList = dc->drag.dragMotionCallback) != NULL) {
1265 	    XmDragMotionCallback	callback =
1266 	      (XmDragMotionCallback)&callbackRec;
1267 
1268 	    callback->timeStamp = dc->drag.lastChangeTime;
1269 	    callback->x = dc->core.x;
1270 	    callback->y = dc->core.y;
1271 	    callback->operation = dc->drag.operation;
1272 	    callback->operations = dc->drag.operations;
1273 
1274 	    /*
1275 	     * If we're over DropOnly client, be optimistic.
1276 	     */
1277 	    if (dc->drag.activeProtocolStyle == XmDRAG_DROP_ONLY)
1278 	      {
1279 		callback->dropSiteStatus = XmVALID_DROP_SITE;
1280 	      }
1281 	    else
1282 	      {
1283 		/*
1284 		 * Otherwise, we're over the root (see
1285 		 * DragMotionProto), and there's no drop site
1286 		 * under us.
1287 		 */
1288 		callback->dropSiteStatus = XmNO_DROP_SITE;
1289 	      }
1290 	}
1291 	break;
1292       case XmCR_OPERATION_CHANGED:
1293 	if ((callbackList = dc->drag.operationChangedCallback) != NULL) {
1294 	    XmOperationChangedCallback	callback =
1295 	      (XmOperationChangedCallback)&callbackRec;
1296 
1297 	    callback->timeStamp = dc->drag.lastChangeTime;
1298 	    callback->operation = dc->drag.operation;
1299 	    callback->operations = dc->drag.operations;
1300 
1301             /*
1302 	     * If we're over DropOnly client, be optimistic.
1303 	     */
1304 	    if (dc->drag.activeProtocolStyle == XmDRAG_DROP_ONLY)
1305               {
1306 		callback->dropSiteStatus = XmVALID_DROP_SITE;
1307               }
1308 	    else
1309               {
1310 		/*
1311 		 * Otherwise, we're over the root (see
1312 		 * DragMotionProto), and there's no drop site
1313 		 * under us.
1314 		 */
1315 		callback->dropSiteStatus = XmNO_DROP_SITE;
1316               }
1317 	}
1318 	break;
1319       case XmCR_DROP_SITE_ENTER:
1320 	{
1321 	    XmeWarning((Widget)dc, MESSAGE1);
1322 	}
1323 	break;
1324       case XmCR_DROP_SITE_LEAVE:
1325 	{
1326 	    XmDropSiteLeaveCallback	callback =
1327 	      (XmDropSiteLeaveCallback)&callbackRec;
1328 
1329 	    callback->timeStamp = dc->drag.lastChangeTime;
1330 	}
1331 	break;
1332       default:
1333 	break;
1334     }
1335     if (callbackList)
1336     {
1337       XtCallCallbackList( (Widget)dc, callbackList, &callbackRec);
1338 
1339       if (callbackList == dc->drag.dragMotionCallback)
1340       {
1341          XmDragOverShellWidget dos = dc->drag.curDragOver;
1342          XmDragMotionCallback  callback =
1343                        (XmDragMotionCallback)&callbackRec;
1344 
1345          dc->drag.operation = callback->operation;
1346          dc->drag.operations = callback->operations;
1347          if (dos->drag.cursorState != callback->dropSiteStatus)
1348          {
1349             dos->drag.cursorState = callback->dropSiteStatus;
1350             _XmDragOverChange((Widget)dos, dos->drag.cursorState);
1351          }
1352       }
1353     }
1354 }
1355 
1356 /*ARGSUSED*/
1357 static void
DropLoseIncrSelection(Widget w,Atom * selection,XtPointer clientData)1358 DropLoseIncrSelection(
1359         Widget w,
1360         Atom *selection,
1361         XtPointer clientData )
1362 {
1363     DropLoseSelection( w, selection) ;
1364 }
1365 
1366 
1367 static void
DropLoseSelection(Widget w,Atom * selection)1368 DropLoseSelection(
1369         Widget w,
1370         Atom *selection)
1371 {
1372   XmDragContext	dc ;
1373 
1374   if (!(dc = (XmDragContext) _XmGetDragContextFromHandle( w, *selection)))
1375     {
1376       XmeWarning(w, MESSAGE2) ;
1377     }
1378 
1379   if (dc && dc->drag.dropFinishTime == 0)
1380     {
1381       XmeWarning(w, MESSAGE3) ;
1382     }
1383 }
1384 
1385 static void
DragDropFinish(XmDragContext dc)1386 DragDropFinish(
1387         XmDragContext dc )
1388 {
1389     Widget w = NULL;
1390 
1391     XmDropSiteManagerObject dsm = (XmDropSiteManagerObject)
1392 		_XmGetDropSiteManagerObject((XmDisplay)(XtParent(dc)));
1393 
1394     /* Handle completion */
1395     if (dc->drag.dropFinishCallback) {
1396 	XmDropFinishCallbackStruct cb;
1397 
1398 	cb.reason = XmCR_DROP_FINISH;
1399 	cb.event = NULL;
1400 	cb.timeStamp = dc->drag.dropFinishTime;
1401 	cb.operation = dc->drag.operation;
1402 	cb.operations = dc->drag.operations;
1403 	cb.dropSiteStatus = dsm->dropManager.curDropSiteStatus;
1404 	cb.dropAction = dc->drag.dragCompletionStatus;
1405 	cb.completionStatus = dc->drag.dragDropCompletionStatus;
1406 	XtCallCallbackList((Widget) dc, dc->drag.dropFinishCallback, &cb);
1407 	dc->drag.dragDropCompletionStatus = cb.completionStatus;
1408     }
1409 
1410     if (dc->drag.blendModel != XmBLEND_NONE &&
1411 	dc->drag.dragDropCancelEffect == False) {
1412       _XmDragOverFinish((Widget)dc->drag.curDragOver,
1413 			dc->drag.dragDropCompletionStatus);
1414     }
1415 
1416     if (dc->drag.dragDropFinishCallback) {
1417 	XmDragDropFinishCallbackStruct cb;
1418 
1419 	cb.reason = XmCR_DRAG_DROP_FINISH;
1420 	cb.event = NULL;
1421 	cb.timeStamp = dc->drag.dropFinishTime;
1422 	XtCallCallbackList((Widget) dc, dc->drag.dragDropFinishCallback, &cb);
1423     }
1424     /*
1425      * we send this now so that the non-local receiver can clean up
1426      * its dc after everything is done
1427      */
1428 
1429     XtDisownSelection(dc->drag.srcShell,
1430 		      dc->drag.iccHandle,
1431 		      dc->drag.dragFinishTime);
1432 
1433     _XmFreeMotifAtom((Widget)dc, dc->drag.iccHandle);
1434 
1435     XtRemoveEventHandler(dc->drag.srcShell, FocusChangeMask, True,
1436 			 InitiatorMsgHandler,
1437 			 (XtPointer)dc);
1438 
1439     XtVaGetValues((Widget)dc, XmNsourceWidget, &w, NULL);
1440     if (w)
1441 	XtRemoveCallback(w, XmNdestroyCallback, cancelDrag, (XtPointer)dc);
1442 
1443     XtDestroyWidget((Widget) dc);
1444 }
1445 
1446 
1447 
1448 /*
1449  * This callback is called when a drag operation needs to be terminated.
1450  * This can occur when the widget whose id is contained in the drag data
1451  * structure is destroyed.
1452  */
1453 static void
cancelDrag(Widget w,XtPointer client,XtPointer call)1454 cancelDrag(
1455         Widget w,
1456  	XtPointer client,
1457  	XtPointer call)
1458 {
1459     Widget dragContext = (Widget)client;
1460     XmDragCancel(dragContext);
1461 }
1462 
1463 /*
1464  * This routine is passed as the frontend to the convertProc.
1465  */
1466 /*VARARGS*/
1467 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)1468 DropConvertIncrCallback(
1469         Widget w,
1470         Atom *selection,
1471         Atom *target,
1472         Atom *typeRtn,
1473         XtPointer *valueRtn,
1474         unsigned long *lengthRtn,
1475         int *formatRtn,
1476         unsigned long *maxLengthRtn,
1477         XtPointer clientData,
1478         XtRequestId *requestID )
1479 {
1480     enum {
1481       XmATRANSFER_SUCCESS, XmATRANSFER_FAILURE,
1482       XmA_MOTIF_CANCEL_DROP_EFFECT, XmA_MOTIF_DROP, XmATARGETS, NUM_ATOMS };
1483     static char *atom_names[] = {
1484       XmSTRANSFER_SUCCESS, XmSTRANSFER_FAILURE,
1485       XmS_MOTIF_CANCEL_DROP_EFFECT, XmS_MOTIF_DROP, XmSTARGETS };
1486 
1487     XmDragContext	dc;
1488     Time		dropTime;
1489     Boolean 		returnVal = True;
1490     Boolean 		success;
1491     Atom		atoms[XtNumber(atom_names)];
1492 
1493     dropTime = XtGetSelectionRequest(w, *selection, requestID)->time;
1494 
1495     if (!(dc = (XmDragContext)
1496 	  _XmGetDragContextFromHandle(w, *selection))) {
1497 	XmeWarning(w, MESSAGE2);
1498 	return False;
1499     }
1500     assert(XtNumber(atom_names) == NUM_ATOMS);
1501     XInternAtoms(XtDisplayOfObject((Widget) dc), atom_names,
1502 		 XtNumber(atom_names), False, atoms);
1503     if ((success = (*target == atoms[XmATRANSFER_SUCCESS])) ||
1504 	(*target == atoms[XmATRANSFER_FAILURE]))
1505 	{
1506 	  if (success)
1507 	    dc->drag.dragDropCompletionStatus = XmDROP_SUCCESS;
1508 	  else
1509 	    dc->drag.dragDropCompletionStatus = XmDROP_FAILURE;
1510 	  *typeRtn = *target;
1511 	  *lengthRtn = 0;
1512 	  *formatRtn = 32;
1513 	  *valueRtn = NULL;
1514 	  *maxLengthRtn = 0;
1515 	  /*
1516 	   * the time is really of the start of the transfer but ...
1517 	   */
1518 	  dc->drag.dropFinishTime = dropTime;
1519 	  DragDropFinish(dc);
1520       }
1521     else if (*target == atoms[XmA_MOTIF_CANCEL_DROP_EFFECT])
1522       {
1523 	dc->drag.dragDropCancelEffect = True;
1524       }
1525     else /* normal transfer */
1526       {
1527 	  Atom		motifDrop = atoms[XmA_MOTIF_DROP];
1528 	  returnVal =  (Boolean)((*(dc->drag.convertProc.sel_incr))
1529 				 ((Widget)dc,
1530 				  &motifDrop,
1531 				  target,
1532 				  typeRtn,
1533 				  valueRtn,
1534 				  lengthRtn,
1535 				  formatRtn,
1536 				  maxLengthRtn,
1537 				  clientData,
1538 				  requestID));
1539       }
1540 
1541     /* add code to handle TARGET target automatically if not there yet */
1542     if ((! returnVal) && (*target == atoms[XmATARGETS])) {
1543 	int len = sizeof(Atom) * dc->drag.numExportTargets;
1544 
1545 	if (dc->drag.incremental & 0x2) {
1546 	    dc->drag.incremental = 1;
1547 	    *valueRtn = NULL;
1548 	    *lengthRtn = 0;
1549 	} else {
1550 	    *valueRtn = XtMalloc(len);
1551 	    memmove(*valueRtn, dc->drag.exportTargets, len);
1552 	    *lengthRtn = dc->drag.numExportTargets;
1553 	    dc->drag.incremental = 3;
1554 	}
1555 	*formatRtn = 32;
1556 	*typeRtn = XA_ATOM;
1557 	returnVal = True;
1558     }
1559 
1560     return returnVal;
1561 }
1562 
1563 /*
1564  * This routine is passed as the frontend to the convertProc.
1565  */
1566 /*VARARGS*/
1567 static Boolean
DropConvertCallback(Widget w,Atom * selection,Atom * target,Atom * typeRtn,XtPointer * valueRtn,unsigned long * lengthRtn,int * formatRtn)1568 DropConvertCallback(
1569         Widget w,
1570         Atom *selection,
1571         Atom *target,
1572         Atom *typeRtn,
1573         XtPointer *valueRtn,
1574         unsigned long *lengthRtn,
1575         int *formatRtn )
1576 {
1577     enum {
1578       XmATRANSFER_SUCCESS, XmATRANSFER_FAILURE,
1579       XmA_MOTIF_CANCEL_DROP_EFFECT, XmA_MOTIF_DROP, XmATARGETS, NUM_ATOMS };
1580     static char *atom_names[] = {
1581       XmSTRANSFER_SUCCESS, XmSTRANSFER_FAILURE,
1582       XmS_MOTIF_CANCEL_DROP_EFFECT, XmS_MOTIF_DROP, XmSTARGETS };
1583 
1584     XmDragContext	dc;
1585     Time		dropTime;
1586     Boolean 		returnVal = True;
1587     Boolean		success;
1588     Atom		atoms[XtNumber(atom_names)];
1589 
1590     dropTime = XtGetSelectionRequest(w, *selection, NULL)->time;
1591 
1592     if (!(dc = (XmDragContext)
1593 	  _XmGetDragContextFromHandle(w, *selection))) {
1594 	XmeWarning(w, MESSAGE2);
1595 	return False;
1596     }
1597     assert(XtNumber(atom_names) == NUM_ATOMS);
1598     XInternAtoms(XtDisplayOfObject((Widget) dc), atom_names,
1599 		 XtNumber(atom_names), False, atoms);
1600     if ((success = (*target == atoms[XmATRANSFER_SUCCESS])) ||
1601 	(*target == atoms[XmATRANSFER_FAILURE]))
1602       {
1603 	  if (success)
1604 	    dc->drag.dragDropCompletionStatus = XmDROP_SUCCESS;
1605 	  else
1606 	    dc->drag.dragDropCompletionStatus = XmDROP_FAILURE;
1607 	  *typeRtn = *target;
1608 	  *lengthRtn = 0;
1609 	  *formatRtn = 32;
1610 	  *valueRtn = NULL;
1611 	  /*
1612 	   * the time is really of the start of the transfer but ...
1613 	   */
1614 	  dc->drag.dropFinishTime = dropTime;
1615 	  DragDropFinish(dc);
1616       }
1617     else if (*target == atoms[XmA_MOTIF_CANCEL_DROP_EFFECT])
1618       {
1619 	dc->drag.dragDropCancelEffect = True;
1620       }
1621     else /* normal transfer */
1622       {
1623 	  Atom		motifDrop = atoms[XmA_MOTIF_DROP];
1624 	  returnVal =  (Boolean)
1625 		       ((*(dc->drag.convertProc.sel))
1626 				 ((Widget)dc,
1627 				  &motifDrop,
1628 				  target,
1629 				  typeRtn,
1630 				  valueRtn,
1631 				  lengthRtn,
1632 				  formatRtn));
1633       }
1634 
1635     /* add code to handle TARGET target automatically if not there yet */
1636     if ((! returnVal) && (*target == atoms[XmATARGETS])) {
1637 	int len = sizeof(Atom) * dc->drag.numExportTargets;
1638 	*valueRtn = XtMalloc(len);
1639 	memmove(*valueRtn, dc->drag.exportTargets, len);
1640 	*lengthRtn = dc->drag.numExportTargets;
1641 	*formatRtn = 32;
1642 	*typeRtn = XA_ATOM;
1643 	returnVal = True;
1644     }
1645 
1646     return returnVal;
1647 }
1648 
1649 /*ARGSUSED*/
1650 static void
DragStartProto(XmDragContext dc)1651 DragStartProto(
1652         XmDragContext dc)
1653 {
1654     /*
1655      * bootstrap the top_level_window code
1656      */
1657     _XmWriteInitiatorInfo((Widget)dc);
1658     GetDestinationInfo(dc,
1659 		       RootWindowOfScreen(XtScreen(dc)),
1660 		       XtWindow(dc->drag.srcShell));
1661     GenerateClientCallback(dc, XmCR_TOP_LEVEL_ENTER);
1662     SendDragMessage(dc, dc->drag.currReceiverInfo->window, XmTOP_LEVEL_ENTER);
1663     SendDragMessage(dc, dc->drag.currReceiverInfo->window, XmDRAG_MOTION);
1664 }
1665 
1666 
1667 static void
NewScreen(XmDragContext dc,Window newRoot)1668 NewScreen(
1669 	  XmDragContext	dc,
1670 	  Window	newRoot)
1671 {
1672   XmDisplay	dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(dc));
1673   Cardinal	i;
1674   Arg		args[8];
1675   Widget  old = (Widget) (dc->drag.curDragOver);
1676 
1677   /* Find the new screen number */
1678   for (i = 0; i < XScreenCount(XtDisplayOfObject((Widget) dc)); i++)
1679     if (RootWindow(XtDisplayOfObject((Widget) dc), i) == newRoot)
1680       break;
1681 
1682   dc->drag.currScreen =
1683     ScreenOfDisplay(XtDisplayOfObject((Widget) dc), i);
1684   dc->drag.currWmRoot = RootWindowOfScreen(dc->drag.currScreen);
1685 
1686 
1687   /* Build a new one */
1688   i = 0;
1689   /*
1690    * If this is the first call, tracking mode will be querypending
1691    * and we have to come up in cursor mode.  Otherwise, we come up
1692    * in cursor for dynamic and pixmap for preregister.
1693    */
1694   if ((dc->drag.trackingMode == XmDRAG_TRACK_WM_QUERY_PENDING) ||
1695       (dc->drag.activeProtocolStyle == XmDRAG_DYNAMIC))
1696     {
1697       if (dpy -> display.displayHasShapeExtension)
1698 	XtSetArg(args[i], XmNdragOverMode, XmDRAG_WINDOW);
1699       else
1700 	XtSetArg(args[i], XmNdragOverMode, XmCURSOR);
1701       i++;
1702     }
1703   else
1704     {
1705       XtSetArg(args[i], XmNdragOverMode, XmPIXMAP); i++;
1706     }
1707 
1708   XtSetArg(args[i], XmNhotX, dc->core.x); i++;
1709   XtSetArg(args[i], XmNhotY, dc->core.y); i++;
1710   XtSetArg(args[i], XmNbackgroundPixmap, None); i++;
1711   XtSetArg(args[i], XmNscreen, dc->drag.currScreen);i++;
1712   XtSetArg(args[i], XmNdepth, DefaultDepthOfScreen(dc->drag.currScreen));i++;
1713   XtSetArg(args[i], XmNcolormap,
1714 	   DefaultColormapOfScreen(dc->drag.currScreen));i++;
1715   XtSetArg(args[i], XmNvisual, DefaultVisualOfScreen(dc->drag.currScreen));i++;
1716 
1717   /*
1718    * As popup child(ren) of the dc, the drag over(s) will
1719    * automatically destroyed by Xt when the dc is destroyed.
1720    * Isn't that handy?
1721    */
1722   dc->drag.curDragOver = (XmDragOverShellWidget)
1723     XtCreatePopupShell("dragOver", xmDragOverShellWidgetClass,
1724 		       (Widget) dc, args, i);
1725 
1726   if (dc->drag.currScreen == XtScreen(dc->drag.srcShell))
1727     _XmDragOverSetInitialPosition((Widget)dc->drag.curDragOver,
1728 				  dc->drag.startX, dc->drag.startY);
1729 
1730   if (old != NULL) {
1731     if (old != (Widget) (dc->drag.origDragOver))
1732       XtDestroyWidget(old);
1733     else
1734       _XmDragOverHide((Widget)dc->drag.origDragOver, 0, 0, NULL);
1735   }
1736 
1737   GetScreenInfo(dc);
1738 
1739   if (dc->drag.origDragOver == NULL)
1740     {
1741       dc->drag.origDragOver = dc->drag.curDragOver;
1742     }
1743 
1744   if (dc->drag.trackingMode == XmDRAG_TRACK_MOTION)
1745     {
1746       EventMask	mask = _XmDRAG_EVENT_MASK(dc);
1747 
1748       if (XGrabPointer(XtDisplayOfObject((Widget) dc->drag.curDragOver),
1749 		       RootWindowOfScreen(XtScreen(dc->drag.curDragOver)),
1750 		       False,
1751 		       mask,
1752 		       GrabModeSync,
1753 		       GrabModeAsync,
1754 		       None,
1755 		       _XmDragOverGetActiveCursor((Widget)dc->drag.curDragOver),
1756 		       dc->drag.lastChangeTime) != GrabSuccess)
1757 	Warning(MESSAGE4);
1758 
1759       XAllowEvents(XtDisplayOfObject((Widget) dc->drag.srcShell),
1760 		   SyncPointer,
1761 		   dc->drag.lastChangeTime);
1762     }
1763 }
1764 
1765 
1766 /*ARGSUSED*/
1767 static void
LocalNotifyHandler(Widget w,XtPointer client,XtPointer call)1768 LocalNotifyHandler(
1769         Widget w,
1770         XtPointer client,
1771         XtPointer call )
1772 {
1773     XmDropSiteManagerObject 	dsm = (XmDropSiteManagerObject)w;
1774     XmDragContext	dc = (XmDragContext)client;
1775 
1776     switch(((XmAnyICCCallback)call)->reason) {
1777       case XmCR_DROP_SITE_ENTER:
1778 	SiteEnteredWithLocalSource((Widget)dsm, (XtPointer)dc, (XtPointer)call);
1779 	break;
1780 
1781       case XmCR_DROP_SITE_LEAVE:
1782 	/* SiteLeftWithLocalSource expect to find an
1783          * XmDropSiteEnterPendingCallbackStruct, so upgrade the
1784 	 * XmDropSiteLeaveCallbackStruct.
1785 	 */
1786         {
1787 	XmDropSiteLeaveCallbackStruct *cb =
1788 	    (XmDropSiteLeaveCallbackStruct *) call;
1789         XmDropSiteEnterPendingCallbackStruct new_call;
1790 	new_call.reason = cb->reason;
1791 	new_call.event = cb->event;
1792 	new_call.timeStamp = cb->timeStamp;
1793 	new_call.enter_pending = False;
1794 	SiteLeftWithLocalSource((Widget) dsm, (XtPointer)dc,
1795 				(XtPointer) &new_call);
1796 	break;
1797 	}
1798 
1799       case XmCR_DRAG_MOTION:
1800 	SiteMotionWithLocalSource((Widget)dsm, (XtPointer)dc, (XtPointer)call);
1801 	break;
1802 
1803       case XmCR_OPERATION_CHANGED:
1804 	OperationChanged((Widget)dsm, (XtPointer)dc, (XtPointer)call);
1805 	break;
1806 
1807       case XmCR_DROP_START:
1808 	DropStartConfirmed((Widget)dsm, (XtPointer)dc, (XtPointer)call);
1809 
1810       default:
1811 	break;
1812     }
1813 }
1814 
1815 /*
1816  * sends replies to drag messages
1817  */
1818 /*ARGSUSED*/
1819 static void
ExternalNotifyHandler(Widget w,XtPointer client,XtPointer call)1820 ExternalNotifyHandler(
1821         Widget w,
1822         XtPointer client,
1823         XtPointer call )
1824 {
1825     XmDragContext	dc = (XmDragContext)client;
1826     XmAnyICCCallback	cb = (XmAnyICCCallback)call;
1827 
1828     switch(cb->reason) {
1829       case XmCR_DROP_SITE_ENTER:
1830       case XmCR_DROP_SITE_LEAVE:
1831       case XmCR_DRAG_MOTION:
1832       case XmCR_OPERATION_CHANGED:
1833       case XmCR_DROP_START:
1834 	/*
1835 	 * send a message to the external source
1836 	 */
1837 	_XmSendICCCallback(XtDisplayOfObject((Widget) dc),
1838 			   dc->drag.srcWindow,
1839 			   (XmICCCallback)cb,
1840 			   XmICC_RECEIVER_EVENT);
1841 	break;
1842 
1843       default:
1844 	XmeWarning((Widget)dc, MESSAGE5);
1845 	break;
1846     }
1847 }
1848 
1849 
1850 /*
1851  * catches replies on drag messages
1852  */
1853 /*ARGSUSED*/
1854 static void
InitiatorMsgHandler(Widget w,XtPointer clientData,XEvent * event,Boolean * dontSwallow)1855 InitiatorMsgHandler(
1856         Widget w,
1857         XtPointer clientData,
1858         XEvent *event,
1859         Boolean *dontSwallow )
1860 {
1861   XmDragContext	dc =(XmDragContext)clientData;
1862   XmICCCallbackStruct		callbackRec;
1863 
1864   if ((dc && (event->type != ClientMessage)) ||
1865       (!_XmICCEventToICCCallback((XClientMessageEvent *)event,
1866 				 &callbackRec, XmICC_RECEIVER_EVENT)) ||
1867       (dc->drag.dragStartTime > callbackRec.any.timeStamp) ||
1868       (dc->drag.crossingTime > callbackRec.any.timeStamp))
1869     return;
1870 
1871   LocalNotifyHandler(w, (XtPointer)dc, (XtPointer)&callbackRec);
1872 }
1873 
1874 /*ARGSUSED*/
1875 static void
SiteEnteredWithLocalSource(Widget w,XtPointer client,XtPointer call)1876 SiteEnteredWithLocalSource(
1877         Widget w,
1878         XtPointer client,
1879         XtPointer call )
1880 {
1881     XmDragContext	dc = (XmDragContext)client;
1882     XmDropSiteEnterCallbackStruct  *cb = (XmDropSiteEnterCallbackStruct *)call;
1883 
1884     CalculateDragOperation(dc);
1885 
1886     /* check against the current location of the pointer */
1887 
1888     if (dc->drag.siteEnterCallback) {
1889 	XtCallCallbackList((Widget) dc, dc->drag.siteEnterCallback, cb);
1890     }
1891     dc->drag.operation = cb->operation;
1892     dc->drag.operations = cb->operations;
1893     dc->drag.inDropSite = True;
1894 
1895     _XmDragOverChange((Widget)dc->drag.curDragOver, cb->dropSiteStatus);
1896 }
1897 
1898 /*ARGSUSED*/
1899 static void
SiteLeftWithLocalSource(Widget w,XtPointer client,XtPointer call)1900 SiteLeftWithLocalSource(
1901         Widget w,
1902         XtPointer client,
1903         XtPointer call )
1904 {
1905     XmDragContext	dc = (XmDragContext)client;
1906     XmDropSiteEnterPendingCallbackStruct  *cb =
1907 			 (XmDropSiteEnterPendingCallbackStruct *)call;
1908 
1909     dc->drag.inDropSite = False;
1910 
1911     if (dc->drag.siteLeaveCallback) {
1912 	XtCallCallbackList((Widget) dc, dc->drag.siteLeaveCallback,
1913 			   (XmDropSiteLeaveCallbackStruct *)cb);
1914     }
1915 
1916     CalculateDragOperation(dc);
1917 
1918     /*
1919      * Don't forward laggard echo leaves to dragUnder
1920      */
1921     if (dc->drag.dragFinishTime == 0 && !cb->enter_pending)
1922       _XmDragOverChange((Widget)dc->drag.curDragOver, XmNO_DROP_SITE);
1923 }
1924 
1925 /*ARGSUSED*/
1926 static void
OperationChanged(Widget w,XtPointer client,XtPointer call)1927 OperationChanged(
1928         Widget w,
1929         XtPointer client,
1930         XtPointer call )
1931 {
1932     XmDragContext	dc = (XmDragContext)client;
1933     XmOperationChangedCallbackStruct  *cb = (XmOperationChangedCallbackStruct *)call;
1934 
1935     if (dc->drag.operationChangedCallback) {
1936 	XtCallCallbackList((Widget) dc, dc->drag.operationChangedCallback, cb);
1937     }
1938     dc->drag.operation = cb->operation;
1939     dc->drag.operations = cb->operations;
1940     _XmDragOverChange((Widget)dc->drag.curDragOver, cb->dropSiteStatus);
1941 }
1942 
1943 /*ARGSUSED*/
1944 static void
SiteMotionWithLocalSource(Widget w,XtPointer client,XtPointer call)1945 SiteMotionWithLocalSource(
1946         Widget w,
1947         XtPointer client,
1948         XtPointer call )
1949 {
1950     XmDragContext	dc = (XmDragContext)client;
1951     XmDragMotionCallbackStruct  *cb = (XmDragMotionCallbackStruct *)call;
1952 
1953     if (dc->drag.dragMotionCallback) {
1954 	XtCallCallbackList((Widget) dc, dc->drag.dragMotionCallback, cb);
1955     }
1956 
1957     /* Application should not be able to change callback data so
1958      * don't call _XmDragOverChange(), this will result in better
1959      * drag performance.
1960      */
1961 }
1962 
1963 
1964 /*ARGSUSED*/
1965 static void
DropStartConfirmed(Widget w,XtPointer client,XtPointer call)1966 DropStartConfirmed(
1967         Widget w,
1968         XtPointer client,
1969         XtPointer call )
1970 {
1971     XmDragContext	dc = (XmDragContext)client;
1972     XmDropStartCallbackStruct  *cb = (XmDropStartCallbackStruct *)call;
1973     XtAppContext	appContext = XtWidgetToApplicationContext((Widget)dc);
1974 
1975     if (dc->drag.dragTimerId) {
1976 	XtRemoveTimeOut(dc->drag.dragTimerId);
1977 	dc->drag.dragTimerId = (XtIntervalId) NULL;
1978     }
1979 
1980     /* Add a long timeout in case the drop site dies. */
1981     dc->drag.dragTimerId =
1982       XtAppAddTimeOut(appContext,
1983 		      XtAppGetSelectionTimeout(appContext) * 10,
1984 		      DropFinishTimeout,
1985 		      (XtPointer)dc);
1986 
1987     if (dc->drag.dropStartCallback) {
1988 	XtCallCallbackList( (Widget)dc, dc->drag.dropStartCallback, cb);
1989     }
1990     dc->drag.dragCompletionStatus = cb->dropAction;
1991 
1992     switch(dc->drag.dragCompletionStatus) {
1993       case XmDROP:
1994       case XmDROP_INTERRUPT:
1995       case XmDROP_HELP:
1996 	break;
1997       case XmDROP_CANCEL:
1998 	break;
1999     }
2000 }
2001 
2002 
2003 static Widget
GetShell(Widget w)2004 GetShell(
2005         Widget w )
2006 {
2007     while (w && !XtIsShell(w))
2008       w = XtParent(w);
2009     return w;
2010 }
2011 
2012 static void
InitDropSiteManager(XmDragContext dc)2013 InitDropSiteManager(
2014         XmDragContext dc )
2015 {
2016     XmDropSiteManagerObject	dsm;
2017     Arg				args[4];
2018     Cardinal			i = 0;
2019 
2020     dsm = _XmGetDropSiteManagerObject((XmDisplay)(XtParent(dc)));
2021 
2022     XtSetArg(args[i], XmNclientData, dc); i++;
2023     if (dc->drag.sourceIsExternal) {
2024 	XtSetArg(args[i], XmNnotifyProc, ExternalNotifyHandler); i++;
2025     }
2026     else {
2027 	XtSetArg(args[i], XmNnotifyProc, LocalNotifyHandler); i++;
2028     }
2029     XtSetValues((Widget)dsm, args, i);
2030 }
2031 
2032 /*ARGSUSED*/
2033 static void
TopWindowsReceived(Widget w,XtPointer client_data,Atom * selection,Atom * type,XtPointer value,unsigned long * length,int * format)2034 TopWindowsReceived(
2035         Widget w,
2036         XtPointer client_data,
2037         Atom *selection,
2038         Atom *type,
2039         XtPointer value,
2040         unsigned long *length,
2041         int *format )
2042 {
2043     XmDragContext dc = (XmDragContext)client_data;
2044 	XmDisplay dd = (XmDisplay) w;
2045     Cardinal	i;
2046     XmDragReceiverInfo	currInfo, startInfo;
2047     Window	*clientWindows;
2048     unsigned char	oldStyle;
2049 
2050     if (dd->display.activeDC != dc) {
2051       /* Too late... */
2052       return;
2053     }
2054 
2055     /* CR 6337.  Must call DragOverChange if the blendModel
2056        changes.  This doesn't happen often,  only in certain
2057        cases involving PREREGISTER */
2058 
2059     if (dc -> drag.blendModel != dc -> drag.activeBlendModel) {
2060       dc->drag.blendModel = dc->drag.activeBlendModel;
2061       _XmDragOverChange((Widget)dc->drag.curDragOver, XmNO_DROP_SITE);
2062     }
2063 
2064 
2065 #ifdef MULTI_SCREEN_DONE
2066     if ((*length != 0) && (*format == 32) && (*type == XA_WINDOW)) {
2067 	/*
2068 	 * we make a receiverInfo array one larger than the number of
2069 	 * client windows since we keep the root info in array[0].
2070 	 */
2071 	if (dc->drag.numReceiverInfos >= 1)
2072 	  startInfo = dc->drag.receiverInfos;
2073 	else
2074 	  startInfo = NULL;
2075 
2076 	dc->drag.numReceiverInfos =
2077 	  dc->drag.maxReceiverInfos = *length + 1;
2078 	dc->drag.receiverInfos = (XmDragReceiverInfo)
2079 	  XtCalloc(dc->drag.maxReceiverInfos, sizeof(XmDragReceiverInfoStruct));
2080 	clientWindows = (Window *)value;
2081 
2082 	if (startInfo) {
2083 	    memcpy((char *)dc->drag.receiverInfos,
2084 		   (char *)startInfo,
2085 		   sizeof(XmDragReceiverInfoStruct));
2086 	    dc->drag.rootReceiverInfo = dc->drag.receiverInfos;
2087 	    XtFree((char *)startInfo);
2088 	}
2089 #ifdef DEBUG
2090 	else
2091 	  Warning("we don't have startInfo when we should\n");
2092 #endif /* DEBUG */
2093 	for (i = 1; i < dc->drag.numReceiverInfos; i++) {
2094 	    currInfo = &dc->drag.receiverInfos[i];
2095 	    currInfo->window = clientWindows[i-1];
2096 	    currInfo->shell = XtWindowToWidget(XtDisplay(dc),
2097 					       currInfo->window);
2098 	    if (currInfo->shell == NULL) {
2099 		XSelectInput(XtDisplay(dc),
2100 			     currInfo->window,
2101 			     EnterWindowMask | LeaveWindowMask);
2102 	    }
2103 
2104 	}
2105 	/*
2106 	 * set the currReceiver to the srcShell since that's where
2107 	 * we're confined to
2108 	 */
2109 	dc->drag.currReceiverInfo =
2110 	  FindReceiverInfo(dc, XtWindow(dc->drag.srcShell));
2111 	dc->drag.trackingMode = XmDRAG_TRACK_WM_QUERY;
2112 
2113 	oldStyle = dc->drag.activeProtocolStyle;
2114 	dc->drag.activeProtocolStyle =
2115 		_XmGetActiveProtocolStyle((Widget)dc);
2116 	ValidateDragOver(dc, oldStyle, dc->drag.activeProtocolStyle);
2117     }
2118     else
2119 #endif /* MULTI_SCREEN_DONE */
2120     {
2121 	EventMask	mask;
2122 	Window		confineWindow;
2123 	Cursor		cursor;
2124 
2125 	dc->drag.trackingMode = XmDRAG_TRACK_MOTION;
2126 	GetDestinationInfo(dc,
2127 			   dc->drag.currWmRoot,
2128 			   dc->drag.currReceiverInfo->window);
2129 #ifndef MULTI_SCREEN_DONE
2130 	confineWindow = RootWindowOfScreen(XtScreen(dc));
2131 #else
2132 	confineWindow = None;
2133 #endif /* MULTI_SCREEN_DONE */
2134 
2135 	/*
2136 	 * we need to regrab so that the confine window can be changed
2137 	 * from the source window. If there was another value for
2138 	 * trackingMode like XmDRAG_TRACK_WM_QUERY_FAILED we could do
2139 	 * this in DragStartWithTracking
2140 	 */
2141 
2142 	mask = _XmDRAG_EVENT_MASK(dc);
2143 	cursor = _XmDragOverGetActiveCursor((Widget)dc->drag.curDragOver);
2144 
2145 	if (XGrabPointer(XtDisplayOfObject((Widget) dc),
2146 			 RootWindowOfScreen(XtScreen(dc)),
2147 			 False,
2148 			 mask,
2149 			 GrabModeSync,
2150 			 GrabModeAsync,
2151 			 confineWindow,
2152 			 cursor,
2153 			 dc->drag.lastChangeTime) != GrabSuccess)
2154 	  Warning(MESSAGE4);
2155     }
2156 #ifdef MULTI_SCREEN_DONE
2157     if (value)
2158       XtFree((char *)value);
2159 #endif /* MULTI_SCREEN_DONE */
2160 
2161     DragStartWithTracking(dc);
2162 }
2163 
2164 
2165 /* ARGSUSED */
2166 static void
DragStart(XmDragContext dc,Widget src,XEvent * event)2167 DragStart(
2168         XmDragContext dc,
2169         Widget src,
2170         XEvent *event )
2171 {
2172     XmDisplay		dd;
2173     unsigned char 	activeProtocolStyle;
2174     unsigned int	state = event->xbutton.state;
2175     EventMask		mask;
2176     Window		saveWindow;
2177     Window		confineWindow;
2178     Cursor		cursor = None;
2179 
2180     dd = (XmDisplay)XtParent(dc);
2181     dd->display.activeDC = dc;
2182     dd->display.userGrabbed = True;
2183 
2184     dc->drag.crossingTime =
2185       dc->drag.dragStartTime =
2186         dc->drag.lastChangeTime = event->xbutton.time;
2187 
2188     dc->drag.startX = dc->core.x = event->xbutton.x_root;
2189     dc->drag.startY = dc->core.y = event->xbutton.y_root;
2190     dc->drag.curDragOver = NULL;
2191     dc->drag.origDragOver = NULL;
2192     dc->drag.srcShell = GetShell(src);
2193     dc->drag.srcWindow = XtWindow(dc->drag.srcShell);
2194     dc->drag.iccHandle = _XmAllocMotifAtom((Widget)dc, dc->drag.dragStartTime);
2195 
2196     if (dc->drag.incremental)
2197       XtOwnSelectionIncremental(dc->drag.srcShell,
2198 				dc->drag.iccHandle,
2199 				dc->drag.dragStartTime,
2200 				DropConvertIncrCallback,
2201 				DropLoseIncrSelection,
2202 				NULL, NULL, dc->drag.clientData);
2203     else
2204       XtOwnSelection(dc->drag.srcShell,
2205 		     dc->drag.iccHandle,
2206 		     dc->drag.dragStartTime,
2207 		     DropConvertCallback,
2208 		     DropLoseSelection,
2209 		     NULL);
2210 
2211 
2212     dc->drag.serverGrabbed = False;
2213     dc->drag.sourceIsExternal = False;
2214 
2215     dc->drag.activeProtocolStyle = activeProtocolStyle =
2216       _XmGetActiveProtocolStyle((Widget)dc);
2217 
2218     switch (dc->drag.activeProtocolStyle)
2219       {
2220       case XmDRAG_PREREGISTER:
2221 	dc->drag.activeProtocolStyle = XmDRAG_DYNAMIC;
2222       case XmDRAG_DYNAMIC:
2223 	break;
2224       case XmDRAG_DROP_ONLY:
2225 	dc->drag.activeProtocolStyle = XmDRAG_NONE;
2226       case XmDRAG_NONE:
2227 	break;
2228       }
2229 
2230     /* must be either DYNAMIC or NONE at this point */
2231 
2232     /*
2233      * start out with the default operations in effective operations
2234      */
2235 
2236     dc->drag.lastEventState = state;
2237     CalculateDragOperation(dc);
2238     dc->drag.sourceIsExternal = False;
2239 
2240     /*
2241      * if we're in query_pending mode then initialize the
2242      * currReceiverInfo to us
2243      */
2244     if (dc->drag.trackingMode == XmDRAG_TRACK_MOTION) {
2245 	dc->drag.activeProtocolStyle = activeProtocolStyle;
2246 #ifndef MULTI_SCREEN_DONE
2247       confineWindow = RootWindowOfScreen(XtScreen(dc));
2248 #else
2249       confineWindow = None;
2250     } else { /* XmDRAG_TRACK_WM_QUERY */
2251 	dc->drag.trackingMode = XmDRAG_TRACK_WM_QUERY_PENDING;
2252 	confineWindow = XtWindow(dc->drag.srcShell);
2253     }
2254 #endif /*  MULTI_SCREEN_DONE */
2255 
2256     if (dc->drag.trackingMode == XmDRAG_TRACK_WM_QUERY_PENDING &&
2257         activeProtocolStyle == XmDRAG_PREREGISTER) {
2258        dc->drag.blendModel = XmBLEND_NONE;
2259     }
2260 
2261     NewScreen(dc, RootWindowOfScreen(XtScreen(dc)));
2262 
2263     XtInsertEventHandler(dc->drag.srcShell, FocusChangeMask, True,
2264 			 InitiatorMsgHandler,
2265 			 (XtPointer)dc,
2266 			 XtListHead);
2267 
2268     mask = _XmDRAG_EVENT_MASK(dc);
2269 
2270     /*
2271      * we grab on the Xt pointer so that Xt doesn't interfere with us.
2272      * Also once we have the WM_QUERY capability this will work.
2273      * Otherwise we need to grab on the root so we can track the
2274      * changes in sub_window and infer the top_level crossings
2275      */
2276     /*
2277      * some more sleaze to get around the ungrab.  Since we can't rely
2278      * on the caller to have done an owner_events true (for Xt), we need to
2279      * guarantee that the release event goes to us. The grab window
2280      * must be viewable so we can't use the dc window
2281      */
2282 
2283     saveWindow = dc->core.window;
2284 
2285     cursor = _XmDragOverGetActiveCursor((Widget)dc->drag.curDragOver);
2286 
2287     dc->core.window = RootWindowOfScreen(XtScreen(dc));
2288     if ((XtGrabPointer((Widget)dc,
2289 		       False,
2290 		       (unsigned int) mask,
2291 		       GrabModeSync,
2292 		       GrabModeAsync,
2293 		       confineWindow,
2294 		       cursor,
2295 		       dc->drag.dragStartTime) != GrabSuccess) ||
2296 	(XGrabPointer(XtDisplayOfObject((Widget) dc),
2297 		      RootWindowOfScreen(XtScreen(dc)),
2298 		      False,
2299 		      mask,
2300 		      GrabModeSync,
2301 		      GrabModeAsync,
2302 		      confineWindow,
2303 		      cursor,
2304 		      dc->drag.dragStartTime) != GrabSuccess) ||
2305 	(XGrabKeyboard(XtDisplayOfObject((Widget) dc),
2306 		       RootWindowOfScreen(XtScreen(dc)),
2307 		       False,
2308 		       GrabModeSync,
2309 		       GrabModeAsync,
2310 		       dc->drag.dragStartTime) != GrabSuccess))
2311       Warning(MESSAGE4);
2312     _XmAddGrab((Widget)dc, True, False);
2313     dc->core.window = saveWindow;
2314 
2315     /* Begin fixing OSF CR 5556 */
2316     /*
2317      * Add ButtonMotionMask to the already set-up event mask for root window.
2318      * This gets reinstalled in DragContextDestroy()
2319      */
2320     {
2321       XWindowAttributes       xwa;
2322 
2323       XGetWindowAttributes(XtDisplay(dc), dc->drag.currWmRoot, &xwa);
2324       dc->drag.SaveEventMask = xwa.your_event_mask;
2325       XSelectInput(XtDisplay(dc),
2326 		   dc->drag.currWmRoot,
2327 		   xwa.your_event_mask | ButtonMotionMask);
2328     }
2329     /* End fixing OSF CR 5556 */
2330 
2331     if (dc->drag.trackingMode == XmDRAG_TRACK_WM_QUERY_PENDING) {
2332         enum { XmA_MOTIF_WM_QUERY, XmA_MOTIF_WM_ALL_CLIENTS, NUM_ATOMS };
2333 	static char *atom_names[] = {
2334 	  XmS_MOTIF_WM_QUERY, XmS_MOTIF_WM_ALL_CLIENTS };
2335 	Atom atoms[XtNumber(atom_names)];
2336 
2337 	assert(XtNumber(atom_names) == NUM_ATOMS);
2338 	XInternAtoms(XtDisplay(dc), atom_names, XtNumber(atom_names),
2339 		     False, atoms);
2340 
2341 	XtGetSelectionValue((Widget)dd,
2342 			    atoms[XmA_MOTIF_WM_QUERY],
2343 			    atoms[XmA_MOTIF_WM_ALL_CLIENTS],
2344 			    TopWindowsReceived,
2345 			    (XtPointer)dc,
2346 			    dc->drag.dragStartTime);
2347 
2348 	XAllowEvents(XtDisplayOfObject((Widget) dc->drag.srcShell),
2349 		     SyncPointer,
2350 		     dc->drag.dragStartTime);
2351     }
2352     else
2353       DragStartWithTracking(dc);
2354 
2355     XSync(XtDisplay(dc), False);
2356 
2357     XtAppAddTimeOut( XtWidgetToApplicationContext( (Widget)dc),
2358 		    0, InitiatorMainLoop,
2359 		    (XtPointer)(&dd->display.activeDC));
2360 }
2361 
2362 
2363 /* ARGSUSED */
2364 static void
DragStartWithTracking(XmDragContext dc)2365 DragStartWithTracking(
2366         XmDragContext dc)
2367 {
2368     if (dc->drag.dragFinishTime)
2369       return;
2370 
2371     if (dc->drag.trackingMode == XmDRAG_TRACK_WM_QUERY) {
2372 	EventMask	mask = _XmDRAG_EVENT_MASK(dc);
2373 	Window		confineWindow;
2374 	Cursor		cursor;
2375 
2376 #ifndef MULTI_SCREEN_DONE
2377 	confineWindow = RootWindowOfScreen(XtScreen(dc));
2378 #else
2379 	confineWindow = None;
2380 #endif
2381 	cursor = _XmDragOverGetActiveCursor((Widget)dc->drag.curDragOver);
2382 
2383 	/*
2384 	 * set owner events to true so that the crossings and motion
2385 	 * are reported relative to the destination windows. Don't
2386 	 * tell Xt about it so we can continue to get everything
2387 	 * reported to the dragContext via the spring-loaded/XtGrab
2388 	 * interaction. Blegh
2389 	 */
2390 	if (XGrabPointer(XtDisplayOfObject((Widget) dc),
2391 			 RootWindowOfScreen(XtScreen(dc)),
2392 			 True,
2393 			 mask,
2394 			 GrabModeSync,
2395 			 GrabModeAsync,
2396 			 confineWindow,
2397 			 cursor,
2398 			 dc->drag.lastChangeTime) != GrabSuccess)
2399 	  Warning(MESSAGE4);
2400     }
2401 
2402     XAllowEvents(XtDisplayOfObject((Widget) dc->drag.srcShell),
2403 		 SyncPointer,
2404 		 dc->drag.lastChangeTime);
2405 }
2406 
2407 static void
UpdateMotionBuffer(XmDragContext dc,MotionBuffer mb,XEvent * event)2408 UpdateMotionBuffer(
2409 	XmDragContext dc,
2410         MotionBuffer mb,
2411 	XEvent	     *event)
2412 {
2413     Time time ;
2414     unsigned int state;
2415     Window window, subwindow;
2416     Position x ;
2417     Position y ;
2418 
2419     if (dc->drag.currReceiverInfo == NULL)
2420       return;
2421 
2422     dc->drag.lastChangeTime = event->xmotion.time;
2423 
2424     /*
2425      * we munged the window and subwindow fields before calling
2426      * XtDispatchEvent so we could get the event thru to the
2427      * DragContext.  The subwindow field will hold the interesting
2428      * info. The window field is always set (by us) to the DC window.
2429      */
2430     switch(event->type) {
2431       case MotionNotify:
2432 	if (mb->count && ((mb->count % (STACKMOTIONBUFFERSIZE)) == 0)) {
2433 	    if (mb->count == (STACKMOTIONBUFFERSIZE)){
2434 		MotionBuffer	oldMb = mb;
2435 		Cardinal size;
2436 
2437 		size = sizeof(MotionBufferRec) +
2438 		  (STACKMOTIONBUFFERSIZE * sizeof(MotionEntryRec));
2439 		mb = (MotionBuffer) XtMalloc(size);
2440 		memcpy((char *)mb, (char *)oldMb, sizeof(MotionBufferRec));
2441 	    }
2442 	    else  {
2443 		mb = (MotionBuffer)
2444 		  XtRealloc((char *)mb,
2445 			    (sizeof(MotionBufferRec) +
2446 			     (mb->count + STACKMOTIONBUFFERSIZE) *sizeof(MotionEntryRec)));
2447 	    }
2448 	}
2449 	/*
2450 	 * for right now use the root although this wont work for
2451 	 * pseudo-roots
2452 	 */
2453 	time = event->xmotion.time;
2454 	state = event->xmotion.state;
2455 	x = event->xmotion.x_root;
2456 	y = event->xmotion.y_root;
2457 	window = event->xmotion.root;
2458 	if (dc->drag.trackingMode != XmDRAG_TRACK_MOTION) {
2459 	    subwindow = mb->currReceiverInfo->window;
2460 	}
2461 	else {
2462 	    subwindow = event->xmotion.subwindow;
2463 	}
2464 	mb->entries[mb->count].time = time;
2465 	mb->entries[mb->count].window = window;
2466 	mb->entries[mb->count].subwindow = subwindow;
2467 	mb->entries[mb->count].state = state;
2468 	mb->entries[mb->count].x = x;
2469 	mb->entries[mb->count++].y = y;
2470 	break;
2471 
2472       case EnterNotify:
2473 	if ((event->xcrossing.mode == NotifyNormal) &&
2474 	    (dc->drag.trackingMode != XmDRAG_TRACK_MOTION)) {
2475 	    XmDragReceiverInfo	rInfo;
2476 	    if ((rInfo = FindReceiverInfo(dc, event->xcrossing.subwindow))
2477 		!= NULL)
2478 	      mb->currReceiverInfo = rInfo;
2479 	}
2480 	break;
2481 
2482       case LeaveNotify:
2483 	if ((event->xcrossing.mode == NotifyNormal) &&
2484 	    (dc->drag.trackingMode != XmDRAG_TRACK_MOTION)) {
2485 	    XmDragReceiverInfo	rInfo;
2486 	    if ((rInfo = FindReceiverInfo(dc, event->xcrossing.subwindow))
2487 		!= NULL) {
2488 		if (rInfo == mb->currReceiverInfo)
2489 		  mb->currReceiverInfo = dc->drag.rootReceiverInfo;
2490 	    }
2491 	}
2492 	break;
2493       default:
2494 	break;
2495     }
2496 }
2497 
2498 
2499 static void
DragMotionProto(XmDragContext dc,Window root,Window subWindow)2500 DragMotionProto(
2501         XmDragContext dc,
2502         Window root,
2503         Window subWindow )
2504 {
2505   Boolean incrementTimestamp = False;
2506 
2507   /*
2508    * We've selected for motion on the root window. This allows us to
2509    * use the subwindow field to know whenever we have left or
2510    * entered a potential top-level window.
2511    */
2512   if ((root != dc->drag.currWmRoot) ||
2513       ((((dc->drag.trackingMode == XmDRAG_TRACK_MOTION) &&
2514 	 (dc->drag.currReceiverInfo->frame != subWindow))) ||
2515        ((dc->drag.trackingMode == XmDRAG_TRACK_WM_QUERY) &&
2516 	(dc->drag.currReceiverInfo->window != subWindow))))
2517     {
2518       if (dc->drag.currReceiverInfo->window)
2519 	{
2520 	  if ((dc->drag.activeProtocolStyle != XmDRAG_NONE) &&
2521 	      (dc->drag.activeProtocolStyle != XmDRAG_DROP_ONLY))
2522 	    {
2523 	      /*
2524 	       * Assumes the root window doesn't contain drop-sites !!!
2525 	       * Send motion to old window.
2526 	       *
2527 	       * ** Old stuff for bootstrap
2528 	       * ** if (dc->drag.currReceiverInfo->frame)
2529 	       * ** only send to non-initial windows
2530 	       */
2531 	      /*
2532 	       * if the receiver is dynamic and we've been
2533 	       * informed that we're in a drop-site then
2534 	       * generate a dropsite leave to the initiator. If
2535 	       * we haven't yet been informed of a drop-site
2536 	       * enter (due to latency) but one is in the pipes,
2537 	       * it will be ignored once it gets in based on the
2538 	       * timestamp being stale.
2539 	       *
2540 	       * We'll make sure it's stale by incrementing the
2541 	       * timestamp by one millisecond.  This is a no-no but
2542 	       * it makes it easy to identify the echo events from
2543 	       * the receiver.  Its also relatively safe until we
2544 	       * get micro-second response times :-)
2545 	       */
2546 	      if ((dc->drag.activeProtocolStyle == XmDRAG_DYNAMIC) &&
2547 		  (!dc->drag.currReceiverInfo->shell) &&
2548 		  (dc->drag.inDropSite))
2549 		{
2550 		  GenerateClientCallback(dc, XmCR_DROP_SITE_LEAVE);
2551 		  dc->drag.inDropSite = False;
2552 		  incrementTimestamp = True;
2553 		}
2554 	      SendDragMessage(dc, dc->drag.currReceiverInfo->window,
2555 			      XmDRAG_MOTION);
2556 	      SendDragMessage(dc, dc->drag.currReceiverInfo->window,
2557 			      XmTOP_LEVEL_LEAVE);
2558 	    }
2559 	  GenerateClientCallback(dc, XmCR_TOP_LEVEL_LEAVE);
2560 	}
2561 
2562       if (root != dc->drag.currWmRoot)
2563 	NewScreen(dc, root);
2564 
2565       GetDestinationInfo(dc, root, subWindow);
2566 
2567       /* we should special-case the root window */
2568       if (dc->drag.currReceiverInfo->window)
2569 	{
2570 	  if ((dc->drag.activeProtocolStyle != XmDRAG_NONE) &&
2571 	      (dc->drag.activeProtocolStyle != XmDRAG_DROP_ONLY))
2572 	    {
2573 	      SendDragMessage(dc, dc->drag.currReceiverInfo->window,
2574 			      XmTOP_LEVEL_ENTER);
2575 	    }
2576 	  /* clear iccInfo for dsm's sanity */
2577 	  dc->drag.currReceiverInfo->iccInfo = NULL;
2578 	  GenerateClientCallback(dc, XmCR_TOP_LEVEL_ENTER);
2579 	}
2580     }
2581   if (dc->drag.currReceiverInfo->window)
2582     {
2583       if ((dc->drag.activeProtocolStyle != XmDRAG_NONE) &&
2584 	  (dc->drag.activeProtocolStyle != XmDRAG_DROP_ONLY))
2585 	SendDragMessage(dc, dc->drag.currReceiverInfo->window,
2586 			XmDRAG_MOTION);
2587       else
2588 	GenerateClientCallback(dc, XmCR_DRAG_MOTION);
2589     }
2590   else
2591     GenerateClientCallback(dc, XmCR_DRAG_MOTION);
2592   if (incrementTimestamp)
2593     dc->drag.lastChangeTime++;
2594 }
2595 
2596 static void
ProcessMotionBuffer(XmDragContext dc,MotionBuffer mb)2597 ProcessMotionBuffer(
2598         XmDragContext dc,
2599         MotionBuffer mb )
2600 {
2601     Cardinal	incr, i, j, max;
2602     Window	protoWindow = None;
2603 
2604     incr = (mb->count / MOTIONFILTER);
2605     if (incr == 0) incr = 1;
2606     max = mb->count / incr;
2607     j = (mb->count + incr - 1) % incr;
2608     for (i = 0; i < max; i++, j += incr) {
2609 	dc->core.x = mb->entries[j].x;
2610 	dc->core.y = mb->entries[j].y;
2611 
2612 	if (mb->entries[j].state != dc->drag.lastEventState)
2613 	  CheckModifiers(dc, mb->entries[j].state);
2614 	if (dc->drag.currWmRoot != mb->entries[j].window) {
2615 	    /*
2616 	     * cause the callbacks to get called so the client can
2617 	     * change the dragOver visuals
2618 	     */
2619 	    DragMotionProto(dc, mb->entries[j].window, None);
2620 	    protoWindow = None;
2621 	}
2622 	else
2623 	  protoWindow = mb->entries[j].subwindow;
2624 
2625     }
2626     _XmDragOverMove((Widget)dc->drag.curDragOver, dc->core.x, dc->core.y);
2627 
2628     /* if the protoWindow gotten above is the drag window,
2629      * we can use XTranslateCoordinates to look through the
2630      * one pixel hole (which has just been moved to be under where
2631      * the pointer was), and determine what real window we are over
2632      */
2633     if (protoWindow == XtWindow(dc->drag.curDragOver))
2634       {
2635 	Window currRoot = dc->drag.currWmRoot;
2636 	int dummyx, dummyy;
2637 
2638 	(void) XTranslateCoordinates(XtDisplay(dc), currRoot, currRoot,
2639 				     dc->core.x, dc->core.y,
2640 				     &dummyx, &dummyy,
2641 				     &protoWindow);
2642       }
2643 
2644     /*
2645      * actually inform the receiver/initiator that movement has
2646      * occurred
2647      */
2648     DragMotionProto(dc, dc->drag.currWmRoot, protoWindow);
2649 
2650     if (mb->count > STACKMOTIONBUFFERSIZE)
2651       XtFree( (char *)mb);
2652 }
2653 
2654 #define IsGrabEvent(ev) \
2655   ((ev->type == ButtonPress) ||\
2656    (ev->type == ButtonRelease) ||\
2657    (ev->type == KeyPress) ||\
2658    (ev->type == KeyRelease))
2659 
2660 /* ARGSUSED */
2661 static void
DragMotion(Widget w,XEvent * event,String * params,Cardinal * numParams)2662 DragMotion(
2663         Widget w,
2664         XEvent *event,
2665         String *params,
2666         Cardinal *numParams )
2667 {
2668     XmDragContext	dc = (XmDragContext)w;
2669     MotionBufferRec	stackBuffer;
2670     MotionBuffer	motionBuffer = &stackBuffer;
2671     Boolean		grabEvent = False;
2672 
2673     stackBuffer.count = 0;
2674     stackBuffer.currReceiverInfo = dc->drag.currReceiverInfo;
2675     UpdateMotionBuffer(dc, motionBuffer,event);
2676 
2677     /*
2678      * We need to process all outstanding events of interest
2679      * inline and flush out any stale motion events.  Need to
2680      * check for state change events like modifier or button press.
2681      */
2682 
2683     /*
2684      * get any that came in after
2685      */
2686     while (!grabEvent &&
2687 	   XCheckMaskEvent(XtDisplayOfObject((Widget) w),
2688 			   _XmDRAG_EVENT_MASK(dc),
2689 			   event)) {
2690 	grabEvent = IsGrabEvent(event);
2691 	if (!grabEvent) {
2692 	    if (dc->drag.trackingMode != XmDRAG_TRACK_MOTION)
2693 	      event->xmotion.subwindow = event->xmotion.window;
2694 	    UpdateMotionBuffer(dc, motionBuffer, event);
2695 	}
2696 	else
2697 	  XPutBackEvent(XtDisplay(dc), event);
2698     }
2699     ProcessMotionBuffer(dc, motionBuffer);
2700     XFlush(XtDisplayOfObject((Widget) dc));
2701 }
2702 
2703 /* ARGSUSED */
2704 static void
DragKey(Widget w,XEvent * event,String * params,Cardinal * numParams)2705 DragKey(
2706         Widget w,
2707         XEvent *event,
2708         String *params,
2709         Cardinal *numParams )
2710 {
2711   char 		*direction;
2712   int 		dx, dy;
2713   XKeyEvent 	*keyevent = (XKeyEvent *) event;
2714   XEvent	motionEvent;
2715   XmDisplay     dd;
2716   unsigned int	state = 0;
2717 
2718   dd = (XmDisplay) XtParent(w);
2719 
2720   direction = params[0];
2721 
2722   if (event == NULL) return;
2723 
2724   if (strcmp(direction, "Up") == 0)
2725     { dx = 0; dy = -1; }
2726   else if (strcmp(direction, "Down") == 0)
2727     { dx = 0; dy = 1; }
2728   else if (strcmp(direction, "Left") == 0)
2729     { dx = -1; dy = 0; }
2730   else if (strcmp(direction, "Right") == 0)
2731     { dx = 1; dy = 0; }
2732   else { /* Update on modifier key changes */
2733     dx = 0; dy = 0;
2734     if (event -> type == KeyPress)
2735       state = keyevent -> state;
2736   }
2737 
2738   if (keyevent -> state & ControlMask)
2739     { dx *= 16; dy *= 16; }
2740 
2741   if (dd -> display.enable_warp == False) {
2742     dx = 0; dy = 0;
2743   } else {
2744     XWarpPointer(XtDisplay(w), None, None, 0, 0, 0, 0, dx, dy);
2745   }
2746 
2747   /* Send a button2 motion event so that the drag
2748      feedback will happen within DragMotion */
2749   motionEvent.xmotion.type = MotionNotify;
2750   motionEvent.xmotion.window = keyevent -> window;
2751   motionEvent.xmotion.subwindow = keyevent -> subwindow;
2752   motionEvent.xmotion.time = keyevent -> time;
2753   motionEvent.xmotion.root = keyevent -> root;
2754   motionEvent.xmotion.x = XtX(w) + dx;
2755   motionEvent.xmotion.y = XtY(w) + dy;
2756   motionEvent.xmotion.x_root = keyevent -> x_root;
2757   motionEvent.xmotion.y_root = keyevent -> y_root;
2758   motionEvent.xmotion.same_screen = keyevent -> same_screen;
2759 
2760   /* Or in the modifier bits if this is an update */
2761   motionEvent.xmotion.state = Button2Mask | state;
2762   motionEvent.xmotion.is_hint = 0;
2763 
2764   DragMotion(w, (XEvent *) &motionEvent, NULL, 0);
2765 }
2766 
2767 /*ARGSUSED*/
2768 static void
DropStartTimeout(XtPointer clientData,XtIntervalId * id)2769 DropStartTimeout(
2770         XtPointer clientData,
2771         XtIntervalId *id )
2772 {
2773     XmDragContext	dc = (XmDragContext)clientData;
2774     XmDropStartCallbackStruct	callbackRec, *callback = &callbackRec;
2775     XmDropSiteManagerObject dsm = (XmDropSiteManagerObject)
2776 		_XmGetDropSiteManagerObject((XmDisplay)(XtParent(dc)));
2777 
2778     if (dc->drag.dropStartCallback) {
2779 	callback->reason = XmCR_DROP_START;
2780 	callback->event = NULL;
2781 	callback->timeStamp = dc->drag.dragFinishTime;
2782 	callback->operation = dc->drag.operation;
2783 	callback->operations = dc->drag.operations;
2784 	callback->dropAction = XmDROP_CANCEL;
2785 	callback->dropSiteStatus = dsm->dropManager.curDropSiteStatus;
2786 	callback->x = dc->core.x;
2787 	callback->y = dc->core.y;
2788 	callback->iccHandle = dc->drag.iccHandle;
2789 	callback->window = XtWindow(dc->drag.srcShell);
2790 	XtCallCallbackList((Widget)dc, dc->drag.dropStartCallback, callback);
2791 	dc->drag.dragCompletionStatus = callback->dropAction;
2792         dsm->dropManager.curDropSiteStatus = callback->dropSiteStatus;
2793     }
2794     dc->drag.dragDropCompletionStatus = XmDROP_FAILURE;
2795     dc->drag.dropFinishTime = dc->drag.dragFinishTime;
2796 
2797     DragDropFinish(dc);
2798 }
2799 
2800 /*ARGSUSED*/
2801 static void
DropFinishTimeout(XtPointer clientData,XtIntervalId * id)2802 DropFinishTimeout(
2803         XtPointer clientData,
2804         XtIntervalId *id )
2805 {
2806     XmDragContext	dc = (XmDragContext)clientData;
2807 
2808     dc->drag.dragDropCompletionStatus = XmDROP_FAILURE;
2809     dc->drag.dropFinishTime = dc->drag.dragFinishTime;
2810 
2811     DragDropFinish(dc);
2812 }
2813 
2814 /*ARGSUSED*/
2815 static void
FinishAction(XmDragContext dc,XEvent * ev)2816 FinishAction(
2817         XmDragContext dc,
2818         XEvent *ev )
2819 {
2820     unsigned int	state = 0;
2821     Arg			args[4];
2822     Cardinal		i = 0;
2823     XmDisplay		dd = (XmDisplay) XmGetXmDisplay(XtDisplay(dc));
2824 
2825     dd->display.activeDC = NULL;
2826     dd->display.userGrabbed = False;
2827 
2828     if (ev) {
2829 	switch(ev->type) {
2830 	  case ButtonRelease:
2831 	    state = ev->xbutton.state;
2832 	    dc->drag.lastChangeTime = ev->xbutton.time;
2833 	    dc->core.x = ev->xbutton.x_root;
2834 	    dc->core.y = ev->xbutton.y_root;
2835 	    break;
2836 	  case KeyPress:
2837 	    state = ev->xkey.state;
2838 	    dc->drag.lastChangeTime = ev->xkey.time;
2839 	    dc->core.x = ev->xkey.x_root;
2840 	    dc->core.y = ev->xkey.y_root;
2841 	    break;
2842 	}
2843 
2844 	/*
2845 	 * start out with the default operations in effective operations
2846 	 */
2847   	dc->drag.lastEventState = state;
2848  	CalculateDragOperation(dc);
2849     }
2850 
2851     /*
2852      * change the dragOver to a window in so it can persist after the
2853      * ungrab
2854      */
2855     if (dc->drag.curDragOver) {
2856        unsigned char currentMode;
2857        unsigned char currentActiveMode;
2858 
2859        XtSetArg(args[0], XmNdragOverMode, &currentMode);
2860        XtSetArg(args[1], XmNdragOverActiveMode, &currentActiveMode);
2861        XtGetValues((Widget) dc->drag.curDragOver, args, 2);
2862 
2863        i = 0;
2864        XtSetArg(args[i], XmNhotX, dc->core.x); i++;
2865        XtSetArg(args[i], XmNhotY, dc->core.y); i++;
2866        if (currentActiveMode == XmCURSOR ||
2867 	   (currentMode != XmDRAG_WINDOW && currentMode != XmWINDOW) ) {
2868 	 XtSetArg(args[i], XmNdragOverMode, XmWINDOW); i++;
2869        }
2870        XtSetValues((Widget) dc->drag.curDragOver, args, i);
2871 
2872        XUngrabPointer(XtDisplayOfObject((Widget) dc), dc->drag.lastChangeTime);
2873        XtUngrabPointer((Widget) dc, dc->drag.dragFinishTime);
2874        XUngrabKeyboard(XtDisplayOfObject((Widget) dc), dc->drag.lastChangeTime);
2875 
2876 	_XmRemoveGrab((Widget)dc);
2877     }
2878 
2879     if (dc->drag.serverGrabbed)
2880       XUngrabServer(XtDisplay((Widget) dc));
2881     /*
2882      * if we're in pre-register with a non-local raeceiver then we need
2883      * to flush a top-level leave to the local dsm.
2884      */
2885     dc->drag.dragFinishTime = dc->drag.lastChangeTime;
2886 
2887     if (dc->drag.inDropSite) {
2888 	GenerateClientCallback(dc, XmCR_DROP_SITE_LEAVE);
2889 	dc->drag.inDropSite = False;
2890     }
2891 
2892     if (dc->drag.currReceiverInfo) {
2893        if (dc->drag.currReceiverInfo->window) {
2894 	  SendDragMessage(dc, dc->drag.currReceiverInfo->window,
2895 			  XmTOP_LEVEL_LEAVE);
2896 	  GenerateClientCallback(dc, XmCR_TOP_LEVEL_LEAVE);
2897 
2898 	  if ((dc->drag.activeProtocolStyle != XmDRAG_NONE) &&
2899 	      ((dc->drag.dragCompletionStatus == XmDROP) ||
2900 	       (dc->drag.dragCompletionStatus == XmDROP_HELP))) {
2901 
2902 	      XtAppContext appContext= XtWidgetToApplicationContext((Widget)dc);
2903 	      /*
2904 	       * we send the leave message in the dragDropFinish so
2905 	       * that a non-local receiver can cleanup its dc
2906 	       */
2907 	      dc->drag.dragTimerId =
2908 	        XtAppAddTimeOut(appContext,
2909 			        XtAppGetSelectionTimeout(appContext),
2910 			        DropStartTimeout,
2911 			        (XtPointer)dc);
2912 	      SendDragMessage(dc, dc->drag.currReceiverInfo->window,
2913 			      XmDROP_START);
2914 	  }
2915 	  else {
2916 	      dc->drag.dragDropCompletionStatus = XmDROP_FAILURE;
2917 	      dc->drag.dropFinishTime = dc->drag.dragFinishTime;
2918 	      DropStartTimeout((XtPointer)dc, NULL);
2919 	  }
2920 	}
2921        dc->drag.currReceiverInfo->frame = 0;
2922      } else {
2923        /* Cleanup anyway */
2924        DropStartTimeout((XtPointer)dc, NULL);
2925      }
2926 }
2927 
2928 
2929 
2930 /* ARGSUSED */
2931 static void
CheckModifiers(XmDragContext dc,unsigned int state)2932 CheckModifiers(
2933 	       XmDragContext	dc,
2934 	       unsigned int	state)
2935 {
2936     unsigned char	oldOperation = dc->drag.operation;
2937     unsigned char	oldOperations = dc->drag.operations;
2938 
2939     dc->drag.lastEventState = state;
2940     CalculateDragOperation(dc);
2941 
2942     if ((oldOperations != dc->drag.operations) ||
2943 	(oldOperation != dc->drag.operation)) {
2944 	if ((dc->drag.currReceiverInfo->window) &&
2945 	    (dc->drag.activeProtocolStyle != XmDRAG_NONE) &&
2946 	    (dc->drag.activeProtocolStyle != XmDRAG_DROP_ONLY)) {
2947 	    SendDragMessage(dc,
2948 			    dc->drag.currReceiverInfo->window,
2949 			    XmOPERATION_CHANGED);
2950 	}
2951 	else {
2952 	    GenerateClientCallback(dc, XmCR_OPERATION_CHANGED);
2953 	}
2954     }
2955 }
2956 
2957 /* ARGSUSED */
2958 static void
IgnoreButtons(Widget w,XEvent * event,String * params,Cardinal * numParams)2959 IgnoreButtons(
2960         Widget w,
2961         XEvent *event,
2962         String *params,
2963         Cardinal *numParams )
2964 {
2965     XmDragContext	dc = (XmDragContext)w;
2966 
2967     /*
2968      * the user has pressed some other buttons and caused the server
2969      * to synch up. Swallow and continue
2970      */
2971 
2972     XAllowEvents(XtDisplayOfObject((Widget) dc->drag.srcShell),
2973 		 SyncPointer,
2974 		 dc->drag.lastChangeTime);
2975 }
2976 
2977 /* ARGSUSED */
2978 static void
CancelDrag(Widget w,XEvent * event,String * params,Cardinal * numParams)2979 CancelDrag(
2980         Widget w,
2981         XEvent *event,
2982         String *params,
2983         Cardinal *numParams )
2984 {
2985     XmDragContext	dc = (XmDragContext)w;
2986 
2987     /*
2988      * only cancel if drag has not yet completed
2989      */
2990     if (dc->drag.dragFinishTime == 0) {
2991 	dc->drag.dragCompletionStatus = XmDROP_CANCEL;
2992 	FinishAction(dc, event);
2993     }
2994 }
2995 
2996 /* ARGSUSED */
2997 static void
HelpDrag(Widget w,XEvent * event,String * params,Cardinal * numParams)2998 HelpDrag(
2999         Widget w,
3000         XEvent *event,
3001         String *params,
3002         Cardinal *numParams )
3003 {
3004     XmDragContext	dc = (XmDragContext)w;
3005 
3006     dc->drag.dragCompletionStatus = XmDROP_HELP;
3007     FinishAction(dc, event);
3008 }
3009 
3010 
3011 /* ARGSUSED */
3012 static void
FinishDrag(Widget w,XEvent * event,String * params,Cardinal * numParams)3013 FinishDrag(
3014         Widget w,
3015         XEvent *event,
3016         String *params,
3017         Cardinal *numParams )
3018 {
3019     XmDragContext	dc = (XmDragContext)w;
3020 
3021     dc->drag.dragCompletionStatus = XmDROP;
3022     FinishAction(dc, event);
3023 }
3024 
3025 static void
noMoreShell(Widget w,XtPointer client,XtPointer call)3026 noMoreShell(
3027         Widget w,
3028  	XtPointer client,
3029  	XtPointer call)
3030 {
3031     Boolean *contAction = (Boolean *)client;
3032     *contAction = False;
3033 }
3034 
3035 
3036 /*ARGSUSED*/
3037 static void
InitiatorMainLoop(XtPointer clientData,XtIntervalId * id)3038 InitiatorMainLoop(
3039         XtPointer clientData,
3040         XtIntervalId *id )
3041 {
3042     XmDragContext 	*activeDC = (XmDragContext *)clientData;
3043     XtAppContext	appContext;
3044     XEvent		event;
3045     Widget		focusWidget, shell;
3046     Boolean		contAction = True;
3047 
3048     if (*activeDC) {
3049 	appContext = XtWidgetToApplicationContext((Widget) *activeDC);
3050         shell = (*activeDC)->drag.srcShell;
3051         focusWidget = XmGetFocusWidget((Widget)((*activeDC)->drag.srcShell));
3052         if (_XmGetFocusPolicy(shell) == XmEXPLICIT) {
3053 	   XtSetKeyboardFocus(shell, None);
3054         } else {
3055            XmFocusData         focusData = _XmGetFocusData(shell);
3056            if(focusData)
3057              focusData->needToFlush = False;
3058 	   /* CR 6384,  check for null focusWidget */
3059 	   if (focusWidget != (Widget) NULL) {
3060 	     if (XmIsPrimitive(focusWidget)) {
3061 	       if (((XmPrimitiveWidgetClass) XtClass(focusWidget))
3062 		   ->primitive_class.border_unhighlight)
3063 		 (*(((XmPrimitiveWidgetClass) XtClass(focusWidget))
3064 		    ->primitive_class.border_unhighlight))(focusWidget);
3065 	     } else if (XmIsGadget(focusWidget)) {
3066 	       if (((XmGadgetClass) XtClass(focusWidget))
3067 		   ->gadget_class.border_unhighlight)
3068                  (*(((XmGadgetClass) XtClass(focusWidget))
3069 		    ->gadget_class.border_unhighlight))(focusWidget);
3070 	     }
3071 	   }
3072         }
3073 	DragStartProto(*activeDC);
3074     }
3075     else return;
3076 
3077     XtAddCallback (shell, XmNdestroyCallback, noMoreShell,
3078 		   (XtPointer)&contAction);
3079 
3080     while ( (*activeDC) && (XtAppGetExitFlag(appContext) == False) ) {
3081 	XmDragContext dc = *activeDC;
3082 #ifdef XTHREADS
3083 	XtInputMask mask;
3084 
3085       while(!(mask = XtAppPending(appContext)))
3086 	; /* busy wait */
3087       if (mask & XtIMXEvent)
3088       {
3089 #endif
3090 	XtAppNextEvent(appContext, &event);
3091 	/*
3092 	 * make sure evil Focus outs don't confuse Xt and cause the
3093 	 * unhighlighting of the source hierarchy.
3094 	 */
3095 	switch(event.type) {
3096 	  case FocusIn:
3097 	  case FocusOut:
3098 	    break;
3099 	  case KeyPress:
3100 	  case KeyRelease:
3101 	  case ButtonPress:
3102 	  case ButtonRelease:
3103 	  case EnterNotify:
3104 	  case LeaveNotify:
3105 	  case MotionNotify:
3106 	    {
3107 	      /* dispatch it onto the dc */
3108 		switch(dc->drag.trackingMode) {
3109 		  case XmDRAG_TRACK_MOTION:
3110 		    break;
3111 #ifdef MULTI_SCREEN_DONE
3112 		  case XmDRAG_TRACK_WM_QUERY:
3113 		    event.xmotion.subwindow = event.xmotion.window;
3114 		    break;
3115 #endif /*  MULTI_SCREEN_DONE */
3116 		  case XmDRAG_TRACK_WM_QUERY_PENDING:
3117 		    event.xmotion.subwindow = event.xmotion.window;
3118 		    break;
3119 		}
3120 	    }
3121 	    event.xmotion.window = XtWindow(dc);
3122 	    break;
3123 	}
3124 
3125         if ((event.type == MotionNotify ||
3126              event.type == LeaveNotify ||
3127              event.type == EnterNotify) &&
3128 	     event.xmotion.state == dc->drag.lastEventState)
3129            DragMotion((Widget)dc, &event, NULL, 0);
3130         else
3131 	   XtDispatchEvent(&event);
3132 #ifdef XTHREADS
3133       }
3134       else
3135 	XtAppProcessEvent(appContext, mask);
3136 #endif
3137     }
3138     /* guard against the possibility that shell was destroyed in the last event
3139      * loop while the drag operation was going on (e.g. by a timer)
3140      */
3141     if (contAction) {
3142 	XtRemoveCallback (shell, XmNdestroyCallback, noMoreShell,
3143 			  (XtPointer)&contAction);
3144 	if (_XmGetFocusPolicy(shell) == XmEXPLICIT) {
3145 	    XtSetKeyboardFocus(shell, focusWidget);
3146 	}
3147     }
3148 }
3149 
3150 
3151 
3152 Widget
XmDragStart(Widget w,XEvent * event,ArgList args,Cardinal numArgs)3153 XmDragStart(
3154         Widget w,
3155         XEvent *event,
3156         ArgList args,
3157         Cardinal numArgs )
3158 {
3159     XmDragContext	dc;
3160     XmDisplay		dd = (XmDisplay) XmGetXmDisplay(XtDisplay(w));
3161     Arg			lclArgs[1];
3162     Arg			*mergedArgs;
3163     XmDragStartCallbackStruct	cb;
3164     _XmWidgetToAppContext(w);
3165 
3166     _XmAppLock(app);
3167     if (dd->display.dragInitiatorProtocolStyle == XmDRAG_NONE) {
3168       _XmAppUnlock(app);
3169       return(NULL);
3170     }
3171 
3172     if (event->type != ButtonPress &&
3173 	event->type != ButtonRelease &&
3174 	event->type != KeyRelease &&
3175 	event->type != KeyPress &&
3176 	event->type != MotionNotify ) {
3177 	XmeWarning(w, MESSAGE6);
3178 	_XmAppUnlock(app);
3179 	return NULL;
3180     }
3181 
3182     cb.reason = XmCR_DRAG_START;
3183     cb.event = event;
3184     cb.widget = w;
3185     cb.doit = True;
3186     XtCallCallbackList((Widget)dd, dd->display.dragStartCallback,
3187 		       (XtPointer) &cb);
3188 
3189     if (!cb.doit) {
3190 	_XmAppUnlock(app);
3191 	return NULL;
3192     }
3193 
3194     /*
3195      * check if the menu system is already active
3196      */
3197     if (dd->display.userGrabbed) {
3198 #ifdef DEBUG
3199 	Warning("can't drag; menu system active\n");
3200 #endif
3201 	_XmAppUnlock(app);
3202 	return NULL;
3203     }
3204 
3205     XtSetArg(lclArgs[0], XmNsourceWidget, w);
3206 
3207     if (numArgs) {
3208 	mergedArgs = XtMergeArgLists(args, numArgs, lclArgs, 1);
3209     }
3210     else {
3211 	mergedArgs = lclArgs;
3212     }
3213     dc = (XmDragContext)
3214       XtCreateWidget("dragContext", xmDragContextClass,
3215 		     (Widget) dd, mergedArgs, numArgs + 1);
3216     XtAddCallback(w, XmNdestroyCallback, cancelDrag, (XtPointer)dc);
3217     _XmDragStart(dc, w, event);
3218 
3219     if (numArgs)
3220       XtFree( (char *)mergedArgs);
3221     _XmAppUnlock(app);
3222     return (Widget)dc;
3223 }
3224 
3225 
3226 static void
DragCancel(XmDragContext dc)3227 DragCancel(
3228         XmDragContext dc )
3229 {
3230     dc->drag.dragCompletionStatus = XmDROP_CANCEL;
3231     FinishAction(dc, NULL);
3232 }
3233 
3234 void
XmDragCancel(Widget dragContext)3235 XmDragCancel(
3236         Widget dragContext )
3237 {
3238     _XmWidgetToAppContext(dragContext);
3239     _XmAppLock(app);
3240     DragCancel((XmDragContext)dragContext);
3241     _XmAppUnlock(app);
3242 }
3243 
3244 
3245 /*ARGSUSED*/
3246 Boolean
XmTargetsAreCompatible(Display * dpy,Atom * exportTargets,Cardinal numExportTargets,Atom * importTargets,Cardinal numImportTargets)3247 XmTargetsAreCompatible(
3248         Display *dpy,
3249         Atom *exportTargets,
3250         Cardinal numExportTargets,
3251         Atom *importTargets,
3252         Cardinal numImportTargets )
3253 {
3254     Cardinal		j, k;
3255     _XmDisplayToAppContext(dpy);
3256 
3257     _XmAppLock(app);
3258     for (j = 0; j < numExportTargets; j++)
3259       for (k = 0; k < numImportTargets; k++)
3260 	if (exportTargets[j] == importTargets[k]) {
3261 	  _XmAppUnlock(app);
3262 	  return True;
3263 	}
3264     _XmAppUnlock(app);
3265     return False;
3266 }
3267 
3268 
3269 unsigned char
_XmGetActiveProtocolStyle(Widget w)3270 _XmGetActiveProtocolStyle(
3271         Widget w )
3272 {
3273   unsigned char initiator = XmDRAG_NONE,
3274     receiver = XmDRAG_NONE,
3275     active = XmDRAG_NONE;
3276   XmDragContext	dc = (XmDragContext)w;
3277   XmDisplay		xmDisplay = (XmDisplay)XtParent(dc);
3278 
3279   initiator = xmDisplay->display.dragInitiatorProtocolStyle;
3280   receiver = xmDisplay->display.dragReceiverProtocolStyle;
3281 
3282   if (!dc->drag.sourceIsExternal)
3283     {
3284       /* We are the initiator.  Find the receiver. */
3285       if (dc->drag.currReceiverInfo)
3286 	{
3287 	  receiver = dc->drag.currReceiverInfo->dragProtocolStyle;
3288 	}
3289       else
3290 	{
3291 	  /*
3292 	   * This function is sometimes called before we have
3293 	   * set up the receiver info struct on the dc.  In these
3294 	   * cases, we are still in the initiating client, and so
3295 	   * we will use the initiating client's receiver protocol
3296 	   * style.  In order to do this we have to emulate the
3297 	   * protocol style decision made in GetDestinationInfo.
3298 	   * But we can't, since we don't really know the shell
3299 	   * widget--the particular shell widget may not have a dnd
3300 	   * property attached to it.
3301 	   *
3302 	   * There are a number of different guesses that we could
3303 	   * make.  None of them is substantially better than
3304 	   * not guessing at all.  Not guessing only messes up if the
3305 	   * shell really doesn't have any drop sites--we should be
3306 	   * returning NONE, but we might return something else.
3307 	   */
3308 	  /*EMPTY*/
3309 	}
3310 
3311       active = protocolMatrix[initiator][receiver];
3312     }
3313   else
3314     {
3315       /* We are the receiver, so we can't be preregister.  (Since
3316        * the receiver doesn't hear about the drag during the drag,
3317        * and so get ACTIVE protocol makes no sense.)
3318        */
3319       switch(receiver)
3320 	{
3321 	case XmDRAG_NONE:
3322 	  active = XmDRAG_NONE;
3323 	  break;
3324 	case XmDRAG_DROP_ONLY:
3325 	  /* this must be post drop emulation of drag */
3326 	case XmDRAG_PREREGISTER:
3327 	case XmDRAG_DYNAMIC:
3328 	case XmDRAG_PREFER_DYNAMIC:
3329 	case XmDRAG_PREFER_PREREGISTER:
3330 	case XmDRAG_PREFER_RECEIVER:
3331 	  active = XmDRAG_DYNAMIC;
3332 	  break;
3333 	}
3334     }
3335   return active;
3336 }
3337 
3338 static void
CalculateDragOperation(XmDragContext dc)3339 CalculateDragOperation(XmDragContext dc)
3340 {
3341   /*
3342    * Re-set to the initial settings of operation and operations
3343    */
3344   dc->drag.operations = dc->drag.dragOperations;
3345   if ((dc->drag.lastEventState & ShiftMask) &&
3346       (dc->drag.lastEventState & ControlMask)) {
3347     dc->drag.operations =
3348       dc->drag.operation =  (unsigned char)
3349 	(XmDROP_LINK & dc->drag.dragOperations);
3350   }
3351   else if (dc->drag.lastEventState & ShiftMask) {
3352     dc->drag.operations =
3353       dc->drag.operation =  (unsigned char)
3354 	(XmDROP_MOVE & dc->drag.dragOperations);
3355   }
3356   else if (dc->drag.lastEventState & ControlMask) {
3357     dc->drag.operations =
3358       dc->drag.operation = (unsigned char)
3359 	(XmDROP_COPY & dc->drag.dragOperations);
3360   }
3361   else if (XmDROP_MOVE &dc->drag.dragOperations)
3362     dc->drag.operation = (unsigned char)XmDROP_MOVE;
3363   else if (XmDROP_COPY &dc->drag.dragOperations)
3364     dc->drag.operation = (unsigned char)XmDROP_COPY;
3365   else if (XmDROP_LINK &dc->drag.dragOperations)
3366     dc->drag.operation = (unsigned char)XmDROP_LINK;
3367   else {
3368     dc->drag.operations = dc->drag.operation = 0;
3369   }
3370 }
3371