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: DragOverS.c /main/18 1999/08/11 15:53:11 mgreess $"
26 #endif
27 #endif
28 
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32 
33 
34 /************************************************************************
35  *
36  *  This module dynamically blends and manages the dragover visual using
37  *  the XmDragOverShell widget and the following API:
38  *
39  *	_XmDragOverHide()
40  *	_XmDragOverShow()
41  *	_XmDragOverMove()
42  *	_XmDragOverChange()
43  *	_XmDragOverFinish()
44  *	_XmDragOverGetActiveCursor()
45  *	_XmDragOverSetInitialPosition()
46  *
47  *  The XmDragOverShellPart structure has the following members:
48  *
49  *	Position hotX, hotY -- the coordinates of the dragover visual's
50  *		hotspot.  These are settable resources and are maintained
51  *		through the _XmDragOverMove() interface.
52  *
53  *	Position initialX, initialY -- the initial coordinates of the
54  *		dragover visual's hotspot.  These are set in the
55  *		XmDragOverShell's initialization and also through the
56  *		_XmDragOverSetInitialPosition() interface.  These are
57  *		used as the zap-back position in the zap-back dropFinish
58  *		effect.
59  *
60  *	unsigned char mode -- one of {XmPIXMAP, XmCURSOR, XmWINDOW}.
61  *		XmPIXMAP indicates the current drag protocol style is
62  *		pre-register and indicates that either a pixmap or a
63  *		cursor can be used for the dragover visual.  XmCURSOR
64  *		indicates dynamic protocol style is in effect and that
65  *		a cursor must be used for the dragover visual.  XmWINDOW
66  *		is used during dropFinish processing so that the dragover
67  *		visual can persist even without the server grabbed.
68  *
69  *	unsigned char activeMode -- one of {XmPIXMAP, XmCURSOR, XmWINDOW}.
70  *		Determined by the value of mode and the capabilities of
71  *		the hardware.  Indicates how the dragover visual is being
72  *		rendered.  XmCURSOR indicates that the hardware cursor is
73  *		being used.  XmPIXMAP indicates that a pixmap is being
74  *		dragged.  XmWINDOW indicates that the XmDragOverShell's
75  *		window is popped up and is being dragged.
76  *
77  *	Cursor activeCursor -- if activeMode == XmCURSOR, contains the
78  *		cursor being used to render the dragover visual.
79  *		Otherwise, contains a null cursor.
80  *
81  *	unsigned char cursorState -- set within _XmDragOverChange(),
82  *		and one of {XmVALID_DROP_SITE, XmINVALID_DROP_SITE,
83  *		XmNO_DROP_SITE}, indicates the status of the current
84  *		dropsite.
85  *
86  *	Pixel cursorForeground, cursorBackground -- indicates the current
87  *		foreground and background colors of the dragover visual.
88  *		Can depend on the cursorState and the screen's default
89  *		colormap.
90  *
91  *	XmDragIconObject stateIcon, opIcon -- indicates, respectively, the
92  *		current state and operation icons being blended to the
93  *		source icon to form the dragover visual.  If a state or
94  *		operation icon is not being blended, the corresponding
95  *		icon here is NULL.
96  *
97  *	XmDragOverBlendRec cursorBlend, rootBlend -- cursorBlend contains
98  *		the blended icon data for XmCURSOR activeMode and rootBlend
99  *		contains the blended icon data for XmPIXMAP and XmWINDOW
100  *		activeMode.  The blended icon data consists of
101  *
102  *			XmDragIconObject sourceIcon --	the source icon.
103  *			Position sourceX, sourceY -- the source location
104  *				within the blended icon (dragover visual).
105  *			XmDragIconObject mixedIcon -- the blended icon.
106  *			GC gc -- the gc used to create the blended icon.
107  *				the rootBlend gc is also used to render
108  *				the blended icon to the display.
109  *
110  *	Boolean isVisible -- indicates whether the dragover visual is
111  *		visible.  Used to avoid unnecessary computation.
112  *
113  *	XmBackingRec backing -- contains the backing store needed during
114  *		pixmap dragging (XmPIXMAP activeMode) and the dropFinish
115  *		effects.  Consists of an (x,y) position in root coordinates
116  *		and a pixmap.
117  *
118  *	Pixmap tmpPix, tmpBit -- scratch pixmap and bitmap used during
119  *		pixmap dragging (XmPIXMAP activeMode) to reduce screen
120  *		flashing.
121  *
122  *	Cursor ncCursor -- the cursor id of the last noncached cursor
123  *		used.  Needed so the cursor can be freed when it is no
124  *		longer needed.
125  *
126  *
127  *
128  *  NOTE:  This module directly accesses three members of the
129  *         XmDragContext structure:
130  *
131  *	dc->drag.origDragOver
132  *	dc->drag.operation
133  *	dc->drag.lastChangeTime
134  *
135  ***********************************************************************/
136 
137 #include <stdio.h>
138 #include <X11/IntrinsicP.h>
139 #include <X11/Shell.h>
140 #include <X11/ShellP.h>
141 #include <X11/StringDefs.h>
142 #include <X11/Xatom.h>
143 #include <X11/Xos.h>
144 #include <X11/cursorfont.h>
145 #include <X11/extensions/shape.h>
146 #include <Xm/DragCP.h>
147 #include <Xm/VendorSEP.h>
148 #include <Xm/XmP.h>
149 #include <Xm/XmosP.h>
150 #include "DragCI.h"
151 #include "DragICCI.h"
152 #include "DragIconI.h"
153 #include "DragOverSI.h"
154 #include "MessagesI.h"
155 #include "RegionI.h"
156 #include "ScreenI.h"
157 #include "XmI.h"
158 
159 #define MESSAGE1	_XmMMsgDragOverS_0000
160 #define MESSAGE2	_XmMMsgDragOverS_0001
161 #define MESSAGE3	_XmMMsgDragOverS_0002
162 #define MESSAGE4	_XmMMsgDragOverS_0003
163 
164 #define PIXMAP_MAX_WIDTH	128
165 #define PIXMAP_MAX_HEIGHT	128
166 
167 #define BackingPixmap(dos)	(dos->drag.backing.pixmap)
168 #define BackingX(dos)		(dos->drag.backing.x)
169 #define BackingY(dos)		(dos->drag.backing.y)
170 
171 #define ZAP_TIME	50000L
172 #define MELT_TIME	50000L
173 
174 /********    Static Function Declarations    ********/
175 
176 static void DoZapEffect(
177                         XtPointer clientData,
178                         XtIntervalId *id) ;
179 static void DoMeltEffect(
180                         XtPointer clientData,
181                         XtIntervalId *id) ;
182 static void GetIconPosition(
183                         XmDragOverShellWidget dos,
184                         XmDragIconObject icon,
185                         XmDragIconObject sourceIcon,
186                         Position *iconX,
187                         Position *iconY) ;
188 static void BlendIcon(  XmDragOverShellWidget dos,
189                         XmDragIconObject icon,
190                         XmDragIconObject mixedIcon,
191 #if NeedWidePrototypes
192                         int iconX,
193                         int iconY,
194 #else
195                         Position iconX,
196                         Position iconY,
197 #endif /* NeedWidePrototypes */
198                         GC maskGC,
199                         GC pixmapGC) ;
200 static void MixedIconSize(
201                         XmDragOverShellWidget dos,
202                         XmDragIconObject sourceIcon,
203                         XmDragIconObject stateIcon,
204                         XmDragIconObject opIcon,
205                         Dimension *width,
206                         Dimension *height) ;
207 static void DestroyMixedIcon(
208                         XmDragOverShellWidget dos,
209                         XmDragIconObject mixedIcon) ;
210 static void MixIcons(
211                         XmDragOverShellWidget dos,
212                         XmDragIconObject sourceIcon,
213                         XmDragIconObject stateIcon,
214                         XmDragIconObject opIcon,
215                         XmDragOverBlendRec *blendPtr,
216 #if NeedWidePrototypes
217                         int clip) ;
218 #else
219                         Boolean clip) ;
220 #endif /* NeedWidePrototypes */
221 static Boolean FitsInCursor(
222                         XmDragOverShellWidget dos,
223                         XmDragIconObject sourceIcon,
224                         XmDragIconObject stateIcon,
225                         XmDragIconObject opIcon) ;
226 static Boolean GetDragIconColors(
227                         XmDragOverShellWidget dos) ;
228 static Cursor GetDragIconCursor(
229                         XmDragOverShellWidget dos,
230                         XmDragIconObject sourceIcon,
231                         XmDragIconObject stateIcon,
232                         XmDragIconObject opIcon,
233 #if NeedWidePrototypes
234 			int clip,
235                         int dirty) ;
236 #else
237                         Boolean clip,
238                         Boolean dirty) ;
239 #endif /* NeedWidePrototypes */
240 static void Initialize(
241                         Widget req,
242                         Widget new_w,
243                         ArgList args,
244                         Cardinal *numArgs) ;
245 static Boolean SetValues(
246                         Widget current,
247                         Widget req,
248                         Widget new_w,
249                         ArgList args,
250                         Cardinal *num_args) ;
251 static void DrawIcon(
252                         XmDragOverShellWidget dos,
253                         XmDragIconObject icon,
254                         Window window,
255 #if NeedWidePrototypes
256                         int x,
257                         int y) ;
258 #else
259                         Position x,
260                         Position y) ;
261 #endif /* NeedWidePrototypes */
262 static void Redisplay(
263                         Widget wid,
264                         XEvent *event,
265                         Region region) ;
266 static void Destroy(
267                         Widget w) ;
268 static void ChangeActiveMode(
269                         XmDragOverShellWidget dos,
270 #if NeedWidePrototypes
271                         unsigned int newActiveMode) ;
272 #else
273                         unsigned char newActiveMode) ;
274 #endif /* NeedWidePrototypes */
275 static void ChangeDragWindow(
276 			XmDragOverShellWidget dos) ;
277 static void FindColormapShell(XmDragOverShellWidget dw) ;
278 static void InstallColormap(XmDragOverShellWidget dw) ;
279 static void UninstallColormap(XmDragOverShellWidget dw) ;
280 static void DragOverShellPunchHole(Widget w) ;
281 static void DragOverShellColormapWidget(Widget ds, Widget cw) ;
282 /********    End Static Function Declarations    ********/
283 
284 #undef Offset
285 #define Offset(x) (XtOffsetOf(XmDragOverShellRec, x))
286 
287 static XtResource resources[]=
288 {
289     {
290 	XmNoverrideRedirect, XmCOverrideRedirect,
291 	XmRBoolean, sizeof(Boolean), Offset(shell.override_redirect),
292 	XtRImmediate, (XtPointer)True,
293     },
294     {
295         XmNsaveUnder, XmCSaveUnder,
296 	XmRBoolean, sizeof(Boolean), Offset(shell.save_under),
297 	XtRImmediate, (XtPointer)True,
298     },
299     {
300 	XmNhotX, XmCHot, XmRPosition,
301         sizeof(Position), Offset(drag.hotX),
302         XmRImmediate, (XtPointer)0,
303     },
304     {
305 	XmNhotY, XmCHot, XmRPosition,
306         sizeof(Position), Offset(drag.hotY),
307         XmRImmediate, (XtPointer)0,
308     },
309     {
310 	XmNdragOverMode, XmCDragOverMode, XtRUnsignedChar,
311         sizeof(unsigned char), Offset(drag.mode),
312         XmRImmediate, (XtPointer)XmCURSOR,
313     },
314     {
315 	XmNdragOverActiveMode, XmCDragOverActiveMode, XtRUnsignedChar,
316         sizeof(unsigned char), Offset(drag.activeMode),
317         XmRImmediate, (XtPointer)XmCURSOR,
318     },
319     {
320 	XmNinstallColormap, XmCInstallColormap,	XmRBoolean,
321 	sizeof(Boolean), Offset(drag.installColormap),
322 	XmRImmediate, (XtPointer)FALSE,
323     },
324 
325 };
326 
327 #undef Offset
328 
329 /***************************************************************************
330  *
331  * DragOverShell class record
332  *
333  ***************************************************************************/
334 
335 externaldef(xmdragovershellclassrec)
336 XmDragOverShellClassRec xmDragOverShellClassRec = {
337     {					/* core class record */
338 	(WidgetClass) &vendorShellClassRec,	/* superclass */
339 	"XmDragOverShell",	 	/* class_name */
340 	sizeof(XmDragOverShellRec),	/* widget_size */
341 	(XtProc)NULL,			/* class_initialize proc */
342 	(XtWidgetClassProc)NULL,	/* class_part_initialize proc */
343 	FALSE, 				/* class_inited flag */
344 	Initialize,	 		/* instance initialize proc */
345 	(XtArgsProc)NULL, 		/* init_hook proc */
346 	XtInheritRealize,		/* realize widget proc */
347 	NULL,				/* action table for class */
348 	0,				/* num_actions */
349 	resources,			/* resource list of class */
350 	XtNumber(resources),		/* num_resources in list */
351 	NULLQUARK, 			/* xrm_class ? */
352 	FALSE, 				/* don't compress_motion */
353         XtExposeCompressSeries |        /* compressed exposure */
354 	    XtExposeNoRegion,
355 	FALSE, 				/* do compress enter-leave */
356 	FALSE, 				/* do have visible_interest */
357 	Destroy,			/* destroy widget proc */
358 	XtInheritResize, 		/* resize widget proc */
359 	Redisplay,			/* expose proc */
360 	SetValues, 			/* set_values proc */
361 	(XtArgsFunc)NULL, 		/* set_values_hook proc */
362 	XtInheritSetValuesAlmost, 	/* set_values_almost proc */
363 	(XtArgsProc)NULL, 		/* get_values_hook */
364 	(XtAcceptFocusProc)NULL, 	/* accept_focus proc */
365 	XtVersion, 			/* current version */
366 	NULL, 				/* callback offset    */
367 	NULL,		 		/* default translation table */
368 	XtInheritQueryGeometry, 	/* query geometry widget proc */
369 	(XtStringProc)NULL, 		/* display accelerator    */
370 	NULL,				/* extension record      */
371     },
372      { 					/* composite class record */
373 	XtInheritGeometryManager,	/* geometry_manager */
374 	XtInheritChangeManaged,		/* change_managed		*/
375 	XtInheritInsertChild,		/* insert_child			*/
376 	XtInheritDeleteChild,		/* from the shell */
377 	NULL, 				/* extension record      */
378     },
379     { 					/* shell class record */
380 	NULL, 				/* extension record      */
381     },
382     { 					/* wm shell class record */
383 	NULL, 				/* extension record      */
384     },
385     { 					/* vendor shell class record */
386 	NULL, 				/* extension record      */
387     },
388     { 					/* dragOver shell class record */
389 	NULL,				/* extension record      */
390     },
391 };
392 externaldef(xmDragOvershellwidgetclass) WidgetClass xmDragOverShellWidgetClass =
393 	(WidgetClass) (&xmDragOverShellClassRec);
394 
395 typedef struct _MixedIconCache
396 {
397 	Cardinal		depth;
398 	Dimension		width;
399 	Dimension		height;
400 	Pixel                   cursorForeground;
401 	Pixel                   cursorBackground;
402 	Position		sourceX;
403 	Position		sourceY;
404 	Position		stateX;
405 	Position		stateY;
406 	Position		opX;
407 	Position		opY;
408 	Pixmap			sourcePixmap;
409 	Pixmap			statePixmap;
410 	Pixmap			opPixmap;
411 	Pixmap			sourceMask;
412 	Pixmap			stateMask;
413 	Pixmap			opMask;
414 	XmDragIconObject        mixedIcon;
415 	struct _MixedIconCache *next;
416 } MixedIconCache;
417 
418 static MixedIconCache * mixed_cache = NULL;
419 
420 static Boolean
CacheMixedIcon(XmDragOverShellWidget dos,Cardinal depth,Dimension width,Dimension height,XmDragIconObject sourceIcon,XmDragIconObject stateIcon,XmDragIconObject opIcon,Position sourceX,Position sourceY,Position stateX,Position stateY,Position opX,Position opY,XmDragIconObject mixedIcon)421 CacheMixedIcon(
422 	XmDragOverShellWidget	dos,
423 	Cardinal		depth,
424 	Dimension		width,
425 	Dimension		height,
426 	XmDragIconObject	sourceIcon,
427 	XmDragIconObject	stateIcon,
428 	XmDragIconObject	opIcon,
429 	Position		sourceX,
430 	Position		sourceY,
431 	Position		stateX,
432 	Position		stateY,
433 	Position		opX,
434 	Position		opY,
435 	XmDragIconObject	mixedIcon)
436 {
437     register MixedIconCache * cache_ptr;
438 
439     if (mixedIcon == NULL) return False;
440 
441     cache_ptr = XtNew (MixedIconCache);
442     _XmProcessLock();
443     cache_ptr->next = mixed_cache;
444     mixed_cache = cache_ptr;
445     _XmProcessUnlock();
446 
447     cache_ptr->depth = depth;
448     cache_ptr->width = width;
449     cache_ptr->height = height;
450     cache_ptr->cursorForeground = dos->drag.cursorForeground;
451     cache_ptr->cursorBackground = dos->drag.cursorBackground;
452     cache_ptr->sourcePixmap = sourceIcon->drag.pixmap;
453     cache_ptr->sourceMask = sourceIcon->drag.mask;
454     cache_ptr->sourceX = sourceX;
455     cache_ptr->sourceY = sourceY;
456 
457     if (stateIcon) {
458     	cache_ptr->statePixmap = stateIcon->drag.pixmap;
459     	cache_ptr->stateMask = stateIcon->drag.mask;
460     	cache_ptr->stateX = stateX;
461     	cache_ptr->stateY = stateY;
462     } else {
463     	cache_ptr->statePixmap = 0;
464     }
465 
466     if (opIcon) {
467        cache_ptr->opPixmap = opIcon->drag.pixmap;
468        cache_ptr->opMask = opIcon->drag.mask;
469        cache_ptr->opX = opX;
470        cache_ptr->opY = opY;
471     } else {
472        cache_ptr->opPixmap = 0;
473     }
474 
475     cache_ptr->mixedIcon = mixedIcon;
476 
477     return True;
478 }
479 
480 
481 static XmDragIconObject
GetMixedIcon(XmDragOverShellWidget dos,Cardinal depth,Dimension width,Dimension height,XmDragIconObject sourceIcon,XmDragIconObject stateIcon,XmDragIconObject opIcon,Position sourceX,Position sourceY,Position stateX,Position stateY,Position opX,Position opY)482 GetMixedIcon(
483 	XmDragOverShellWidget	dos,
484 	Cardinal		depth,
485 	Dimension		width,
486 	Dimension		height,
487 	XmDragIconObject	sourceIcon,
488 	XmDragIconObject	stateIcon,
489 	XmDragIconObject	opIcon,
490 	Position		sourceX,
491 	Position		sourceY,
492 	Position		stateX,
493 	Position		stateY,
494 	Position		opX,
495 	Position		opY)
496 {
497     register MixedIconCache * cache_ptr;
498 
499     for (cache_ptr = mixed_cache; cache_ptr; cache_ptr = cache_ptr->next)
500     {
501 	if (cache_ptr->depth == depth &&
502 	    cache_ptr->width == width &&
503 	    cache_ptr->height == height &&
504 	    cache_ptr->cursorForeground == dos->drag.cursorForeground &&
505 	    cache_ptr->cursorBackground == dos->drag.cursorBackground &&
506 	    cache_ptr->sourcePixmap == sourceIcon->drag.pixmap &&
507 	    cache_ptr->sourceMask == sourceIcon->drag.mask &&
508 	    cache_ptr->sourceX == sourceX &&
509 	    cache_ptr->sourceY == sourceY &&
510             ((cache_ptr->statePixmap == 0 && !stateIcon) ||
511              (stateIcon && cache_ptr->statePixmap == stateIcon->drag.pixmap &&
512 			   cache_ptr->stateMask == stateIcon->drag.mask &&
513 	    		   cache_ptr->stateX == stateX &&
514 	    		   cache_ptr->stateY == stateY)) &&
515             ((cache_ptr->opPixmap == 0 && !opIcon) ||
516              (opIcon && cache_ptr->opPixmap == opIcon->drag.pixmap &&
517 			   cache_ptr->opMask == opIcon->drag.mask &&
518 	    		   cache_ptr->opX == opX &&
519 	    		   cache_ptr->opY == opY)))
520 	{
521            return (cache_ptr->mixedIcon);
522         }
523      }
524      return ((XmDragIconObject)NULL);
525 }
526 
527 
528 /************************************************************************
529  *
530  *  DoZapEffect()
531  *
532  ***********************************************************************/
533 
534 /*ARGSUSED*/
535 static void
DoZapEffect(XtPointer clientData,XtIntervalId * id)536 DoZapEffect(
537     XtPointer		clientData,
538     XtIntervalId	*id)	/* unused */
539 {
540   XmDragOverShellWidget	dos = (XmDragOverShellWidget)clientData;
541   Display		*display = XtDisplay((Widget) dos);
542   XSegment	 	segments[4];
543   int 			j;
544   int 			i = 0;
545   int 			rise, run;
546   int 			centerX, centerY;
547   GC			draw_gc = dos->drag.rootBlend.gc;
548   XGCValues		v;
549   unsigned long		vmask;
550   Window		root = RootWindowOfScreen(XtScreen(dos));
551 
552   for (j = 0; j < 4; j++)
553     {
554       segments[j].x1 = dos->drag.initialX;
555       segments[j].y1 = dos->drag.initialY;
556     }
557   segments[0].x2 = dos->core.x;
558   segments[0].y2 = dos->core.y;
559   segments[1].x2 = dos->core.x;
560   segments[1].y2 = dos->core.y + dos->core.height;
561   segments[2].x2 = dos->core.x + dos->core.width;
562   segments[2].y2 = dos->core.y + dos->core.height;
563   segments[3].x2 = dos->core.x + dos->core.width;
564   segments[3].y2 = dos->core.y;
565 
566   centerX = dos->core.x + dos->core.width/2;
567   centerY = dos->core.y + dos->core.height/2;
568   rise = (dos->drag.initialY - centerY) / 5;
569   run = (dos->drag.initialX - centerX) / 5;
570 
571   /*
572    *  Draw the lines and add the timeout.
573    */
574   v.foreground = dos->drag.cursorForeground;
575   v.function = GXxor;
576   v.clip_mask = None;
577   vmask = GCForeground|GCFunction|GCClipMask;
578   XChangeGC (display, draw_gc, vmask, &v);
579   XDrawSegments (display, root, draw_gc, segments, 4);
580   XFlush(display);
581 
582   /*
583    * Do an abbreviated zap effect if the rise and run are both small.
584    */
585   if (((rise <= 3) && (rise >= -3)) && ((run <= 3) && (run >= -3))) {
586     i = 5;
587   }
588 
589   for (; ; i++ )
590     {
591       /* wait */
592       XmeMicroSleep (ZAP_TIME);
593 
594       /*
595        *  Erase the previously drawn lines and restore the root.
596        */
597 
598       XDrawSegments (display, root, draw_gc, segments, 4);
599 
600       if (dos->drag.activeMode != XmDRAG_WINDOW) {
601 	v.foreground = dos->drag.cursorForeground;
602 	v.function = GXcopy;
603 	vmask = GCForeground|GCFunction;
604 	XChangeGC (display, draw_gc, vmask, &v);
605 	XCopyArea (display, BackingPixmap(dos), root,
606 		   draw_gc,
607 		   0, 0, dos->core.width, dos->core.height,
608 		   segments[0].x2, segments[0].y2);
609       }
610 
611       /* Here is where we always leave the loop */
612       if (i == 5) break;
613 
614       /*
615        *  Compute the new position.
616        *  Save the root.
617        *  Draw the pixmap (mixedIcon exists) and new lines.
618        */
619 
620       segments[0].x2 += run;
621       segments[0].y2 += rise;
622       segments[1].x2 += run;
623       segments[1].y2 += rise;
624       segments[2].x2 += run;
625       segments[2].y2 += rise;
626       segments[3].x2 += run;
627       segments[3].y2 += rise;
628 
629       if (dos->drag.activeMode == XmDRAG_WINDOW) {
630 	XtMoveWidget((Widget) dos, segments[0].x2, segments[0].y2);
631       } else {
632 	XCopyArea (display, root, BackingPixmap(dos), draw_gc,
633 		   segments[0].x2, segments[0].y2,
634 		   dos->core.width, dos->core.height, 0, 0);
635 	DrawIcon (dos,
636 		  (dos->drag.rootBlend.mixedIcon ?
637 		   dos->drag.rootBlend.mixedIcon :
638 		   dos->drag.cursorBlend.mixedIcon),
639 		  root, segments[0].x2, segments[0].y2);
640       }
641 
642       v.foreground = 1;
643       v.function = GXxor;
644       vmask = GCForeground|GCFunction;
645       XChangeGC (display, draw_gc, vmask, &v);
646       XDrawSegments (display, root, draw_gc, segments, 4);
647       XFlush (display);
648     }
649   XFlush (display);
650 }
651 
652 /************************************************************************
653  *
654  *  DoMeltEffect()
655  *
656  *   This function is responsible for restoring the display after a
657  *   drop has occurred in a receptive area.  It uses a timeout to create
658  *   a venetian blind effect as it removes the drag pixmap, and restores
659  *   the original root window contents.
660  ***********************************************************************/
661 
662 /*ARGSUSED*/
663 static void
DoMeltEffect(XtPointer clientData,XtIntervalId * id)664 DoMeltEffect(
665     XtPointer		clientData,
666     XtIntervalId	*id)	/* unused */
667 {
668   XmDragOverShellWidget	dos = (XmDragOverShellWidget)clientData;
669   int 			iterations;
670   int 			i = 0;
671   int 			xClipOffset;
672   int 			yClipOffset;
673   XRectangle 		rects[4];
674 
675   if (dos->drag.activeMode == XmDRAG_WINDOW) {
676     XRectangle 			rect;
677     Dimension			width = XtWidth(dos);
678     Dimension			height = XtHeight(dos);
679 
680     /*
681      *  Determine how much to shrink on each pass.
682      */
683     if ((xClipOffset = (width / 16)) <= 0) {
684 	xClipOffset = 1;
685     }
686     if ((yClipOffset = (height / 16)) <= 0) {
687 	yClipOffset = 1;
688     }
689 
690     iterations = MIN(width/(2*xClipOffset), height/(2*yClipOffset));
691     /*
692      *  Generate the clipping rectangles.
693      *  We converge on the center of the cursor.
694      */
695 
696     rect.x = 0;
697     rect.y = 0;
698     rect.width = width;
699     rect.height = height;
700 
701     for (i = 0; i < iterations; i++)
702     {
703 	XShapeCombineRectangles(XtDisplay(dos), XtWindow(dos),
704 				ShapeBounding, 0, 0,
705 				&rect, 1, ShapeSet, YXSorted);
706 	XFlush (XtDisplay((Widget) dos));
707 
708 	rect.x += xClipOffset;
709 	rect.width -= 2*xClipOffset;
710 	rect.y += yClipOffset;
711 	rect.height -= 2*yClipOffset;
712 
713 	/* wait */
714 	XmeMicroSleep (MELT_TIME);
715     }
716   } else {
717     XmDragIconObject    	sourceIcon;
718     XmDragOverBlend		blend;
719     GC 				draw_gc = dos->drag.rootBlend.gc;
720 
721     /*
722      *  Blend a new mixedIcon using only the source icon.
723      *  Place the new mixedIcon to preserve the source icon location.
724      *  The current mixedIcon data is valid.
725      */
726     if (dos->drag.rootBlend.sourceIcon) {
727       sourceIcon = dos->drag.rootBlend.sourceIcon;
728       blend = &dos->drag.rootBlend;
729     } else {
730       sourceIcon = dos->drag.cursorBlend.sourceIcon;
731       blend = &dos->drag.cursorBlend;
732     }
733 
734     /*
735      *  Determine how much to shrink on each pass.
736      */
737 
738     if ((xClipOffset = (sourceIcon->drag.width / 16)) <= 0) {
739       xClipOffset = 1;
740     }
741     if ((yClipOffset = (sourceIcon->drag.height / 16)) <= 0) {
742       yClipOffset = 1;
743     }
744 
745     iterations = MIN(sourceIcon->drag.width/(2*xClipOffset),
746 		     sourceIcon->drag.height/(2*yClipOffset));
747     /*
748      *  Generate the clipping rectangles.
749      *  We converge on the center of the cursor.
750      */
751 
752     rects[0].x = dos->core.x;
753     rects[0].y = dos->core.y;
754     rects[0].width = dos->core.width;
755     rects[0].height = blend->sourceY + yClipOffset;
756 
757     rects[1].x = rects[0].x + blend->sourceX + sourceIcon->drag.width -
758       xClipOffset;
759     rects[1].y = rects[0].y + yClipOffset + blend->sourceY;
760     rects[1].width = dos->core.width - (rects[1].x - rects[0].x);
761     rects[1].height = dos->core.height - ((yClipOffset * 2) + blend->sourceY);
762 
763     rects[2].x = rects[0].x;
764     rects[2].y = rects[0].y + blend->sourceY + sourceIcon->drag.height -
765       yClipOffset;
766     rects[2].width = rects[0].width;
767     rects[2].height = dos->core.height - (rects[2].y - rects[0].y);
768 
769     rects[3].x = rects[0].x;
770     rects[3].y = rects[0].y + yClipOffset + blend->sourceY;
771     rects[3].width = xClipOffset + blend->sourceX;
772     rects[3].height = rects[1].height;
773 
774     for (i = 0; i < iterations; i++)
775       {
776 	XSetClipRectangles (XtDisplay((Widget)dos),
777 			    draw_gc, 0, 0, rects, 4, Unsorted);
778 	XCopyArea (XtDisplay((Widget)dos),
779 		   BackingPixmap(dos),
780 		   RootWindowOfScreen(XtScreen(dos)),
781 		   draw_gc,
782 		   0, 0, dos->core.width, dos->core.height,
783 		   dos->core.x, dos->core.y);
784 	XFlush (XtDisplay((Widget)dos));
785 
786 	rects[0].height += yClipOffset;
787 	rects[1].x -= xClipOffset;
788 	rects[1].width += xClipOffset;
789 	rects[2].y -= yClipOffset;
790 	rects[2].height += yClipOffset;
791 	rects[3].width += xClipOffset;
792 
793 	/* wait */
794 	XmeMicroSleep (MELT_TIME);
795       }
796 
797     XSetClipMask (XtDisplay((Widget)dos), draw_gc, None);
798     XCopyArea (XtDisplay((Widget)dos),
799 	       BackingPixmap(dos),
800 	       RootWindowOfScreen(XtScreen(dos)),
801 	       draw_gc,
802 	       0, 0, dos->core.width, dos->core.height,
803 	       dos->core.x, dos->core.y);
804 
805     XFlush (XtDisplay((Widget)dos));
806   }
807 }
808 
809 /************************************************************************
810  *
811  *  GetIconPosition ()
812  *
813  *  Get the state or operation icon position, relative to the source.
814  ***********************************************************************/
815 
816 static void
GetIconPosition(XmDragOverShellWidget dos,XmDragIconObject icon,XmDragIconObject sourceIcon,Position * iconX,Position * iconY)817 GetIconPosition(
818     XmDragOverShellWidget	dos,
819     XmDragIconObject		icon,
820     XmDragIconObject		sourceIcon,
821     Position			*iconX,
822     Position			*iconY)
823 {
824     switch ((int) icon->drag.attachment) {
825 
826 	    default:
827 		XmeWarning ((Widget) icon, MESSAGE2); /* cast ok here */
828             case XmATTACH_NORTH_WEST:
829                 *iconX = icon->drag.offset_x;
830                 *iconY = icon->drag.offset_y;
831 	        break;
832 
833             case XmATTACH_NORTH:
834                 *iconX = ((Position) sourceIcon->drag.width/2)
835 			 + icon->drag.offset_x;
836                 *iconY = icon->drag.offset_y;
837 	        break;
838 
839             case XmATTACH_NORTH_EAST:
840                 *iconX = ((Position) sourceIcon->drag.width)
841 			 + icon->drag.offset_x;
842                 *iconY = icon->drag.offset_y;
843 	        break;
844 
845             case XmATTACH_EAST:
846                 *iconX = ((Position) sourceIcon->drag.width)
847 			 + icon->drag.offset_x;
848                 *iconY = ((Position) sourceIcon->drag.height/2)
849 			 + icon->drag.offset_y;
850 	        break;
851 
852             case XmATTACH_SOUTH_EAST:
853                 *iconX = ((Position) sourceIcon->drag.width)
854 			 + icon->drag.offset_x;
855                 *iconY = ((Position) sourceIcon->drag.height)
856 			 + icon->drag.offset_y;
857 	        break;
858 
859             case XmATTACH_SOUTH:
860                 *iconX = ((Position) sourceIcon->drag.width/2)
861 			 + icon->drag.offset_x;
862                 *iconY = ((Position) sourceIcon->drag.height)
863 			 + icon->drag.offset_y;
864 	        break;
865 
866             case XmATTACH_SOUTH_WEST:
867                 *iconX = icon->drag.offset_x;
868                 *iconY = ((Position) sourceIcon->drag.height)
869 			 + icon->drag.offset_y;
870 	        break;
871 
872             case XmATTACH_WEST:
873                 *iconX = icon->drag.offset_x;
874                 *iconY = ((Position) sourceIcon->drag.height/2)
875 			 + icon->drag.offset_y;
876 	        break;
877 
878             case XmATTACH_CENTER:
879                 *iconX = ((Position) sourceIcon->drag.width/2)
880 			 + icon->drag.offset_x;
881                 *iconY = ((Position) sourceIcon->drag.height/2)
882 			 + icon->drag.offset_y;
883 	        break;
884 
885             case XmATTACH_HOT:
886 	        {
887 		    XmDragContext	dc = (XmDragContext)XtParent (dos);
888 		    Window		root, child;
889 		    int			rootX, rootY, winX, winY;
890 		    unsigned int	modMask;
891 		    XmDragOverShellWidget ref;
892 
893 		    /*
894 		     *  This code is only applicable for the stateIcon.
895 		     *  If the opIcon is XmATTACH_HOT, its hotspot should
896 		     *  be placed at the stateIcon's hotspot.
897 		     *
898 		     *  If this is the first time we are blending the
899 		     *  stateIcon, we will place its hotspot at the
900 		     *  same source icon position as the pointer's
901 		     *  position within the reference widget.
902 		     *
903 		     *  Otherwise, we want to keep the icon fixed relative
904 		     *  to the source.  To do this, we need the mixedIcon
905 		     *  data to be current.  This means the cursorCache
906 		     *  must not be used with stateIcon XmATTACH_HOT.
907 		     */
908 
909 		    ref = (dc->drag.origDragOver != NULL) ?
910 		          dc->drag.origDragOver : dos;
911 
912 		    if (ref->drag.rootBlend.mixedIcon) {
913                         *iconX = ref->drag.rootBlend.mixedIcon->drag.hot_x
914                                  - ref->drag.rootBlend.sourceX
915 				 - icon->drag.hot_x;
916                         *iconY = ref->drag.rootBlend.mixedIcon->drag.hot_y
917                                  - ref->drag.rootBlend.sourceY
918 				 - icon->drag.hot_y;
919                     }
920 		    else if (ref->drag.cursorBlend.mixedIcon) {
921                         *iconX = ref->drag.cursorBlend.mixedIcon->drag.hot_x
922                                  - ref->drag.cursorBlend.sourceX
923 				 - icon->drag.hot_x;
924                         *iconY = ref->drag.cursorBlend.mixedIcon->drag.hot_y
925                                  - ref->drag.cursorBlend.sourceY
926 				 - icon->drag.hot_y;
927                     }
928                     else {
929 			Widget		sourceWidget;
930 			Dimension	borderW = 0;
931 			Dimension	highlightT = 0;
932 			Dimension	shadowT = 0;
933 			Cardinal	ac;
934 			Arg		al[3];
935 
936 			/*
937 			 *  First time:  get position from pointer,
938 			 *  adjusting for sourceWidget's border, highlight,
939 			 *  and shadow.
940 			 */
941 
942 			sourceWidget = dc->drag.sourceWidget;
943 
944 			ac = 0;
945 			XtSetArg (al[ac], XmNborderWidth, &borderW); ac++;
946 			XtSetArg (al[ac], XmNhighlightThickness,
947 				  &highlightT); ac++;
948 			XtSetArg (al[ac], XmNshadowThickness,
949 				  &shadowT); ac++;
950 			XtGetValues (sourceWidget, al, ac);
951 
952 		        XQueryPointer (XtDisplay (dos),
953 			               XtWindow (sourceWidget),
954 			               &root, &child, &rootX, &rootY,
955 			               &winX, &winY, &modMask);
956 
957                         *iconX = winX - icon->drag.hot_x -
958                                  borderW - highlightT - shadowT;
959                         *iconY = winY - icon->drag.hot_y -
960 				 borderW - highlightT - shadowT;
961 		    }
962 	        }
963 	        break;
964     }
965 }
966 
967 /************************************************************************
968  *  BlendIcon ()
969  *
970  *  Blend the icon mask and pixmap into mixedIcon.
971  ***********************************************************************/
972 
973 static void
BlendIcon(XmDragOverShellWidget dos,XmDragIconObject icon,XmDragIconObject mixedIcon,int iconX,int iconY,GC maskGC,GC pixmapGC)974 BlendIcon(
975     XmDragOverShellWidget dos,
976     XmDragIconObject	icon,
977     XmDragIconObject	mixedIcon,
978 #if NeedWidePrototypes
979     int			iconX,
980     int			iconY,
981 #else
982     Position		iconX,
983     Position		iconY,
984 #endif /* NeedWidePrototypes */
985     GC			maskGC,
986     GC			pixmapGC)
987 {
988   Display		*display = XtDisplay(dos);
989   Position		sourceX = 0;
990   Position		sourceY = 0;
991   Position		destX = iconX;
992   Position		destY = iconY;
993   Dimension		destWidth = icon->drag.width;
994   Dimension		destHeight = icon->drag.height;
995   XGCValues		v;
996   unsigned long		vmask;
997 
998   if (icon->drag.pixmap != XmUNSPECIFIED_PIXMAP) {
999 
1000     /* Clip to the destination drawable. */
1001     if (destX < 0) {
1002       sourceX -= destX;	/* > 0 */
1003       destX = 0;
1004       if (destWidth <= (Dimension) sourceX) {
1005 	return;
1006       }
1007       destWidth -= sourceX;
1008     }
1009     if (destX + destWidth > mixedIcon->drag.width) {
1010       if ((Dimension) destX >= mixedIcon->drag.width) {
1011 	return;
1012       }
1013       destWidth = mixedIcon->drag.width - destX;
1014     }
1015 
1016     if (destY < 0) {
1017       sourceY -= destY;	/* > 0 */
1018       destY = 0;
1019       if (destHeight <= (Dimension) sourceY) {
1020 	return;
1021       }
1022       destHeight -= sourceY;
1023     }
1024     if (destY + destHeight > mixedIcon->drag.height) {
1025       if ((Dimension) destY >= mixedIcon->drag.height) {
1026 	return;
1027       }
1028       destHeight = mixedIcon->drag.height - destY;
1029     }
1030 
1031     v.clip_mask = None;
1032     vmask = GCClipMask;
1033 
1034     if (icon->drag.mask != XmUNSPECIFIED_PIXMAP) {
1035       /* Union the masks */
1036       v.function = GXor;
1037       vmask |= GCFunction;
1038       XChangeGC(display, maskGC, vmask, &v);
1039       XCopyArea(display, icon->drag.mask,
1040 		mixedIcon->drag.mask, maskGC,
1041 		sourceX, sourceY,
1042 		mixedIcon->drag.width,
1043 		mixedIcon->drag.height,
1044 		destX, destY);
1045       v.clip_mask = icon->drag.mask;
1046       v.clip_x_origin = destX;
1047       v.clip_y_origin = destY;
1048       vmask = GCClipMask|GCClipXOrigin|GCClipYOrigin;
1049     } else {
1050       /* Create empty mask if we're masking and the blend icon
1051 	 has no mask */
1052       if (mixedIcon->drag.mask != XmUNSPECIFIED_PIXMAP){
1053 	v.function = GXset;
1054 	vmask |= GCFunction;
1055 	XChangeGC (display, maskGC, vmask, &v);
1056 	XFillRectangle (display, mixedIcon->drag.mask, maskGC,
1057 			destX, destY, destWidth, destHeight);
1058       }
1059     }
1060 
1061     /* Join the regions if they both have them,  otherwise,
1062        remove the region */
1063     if (icon->drag.region != NULL && mixedIcon->drag.region != NULL) {
1064       if (icon->drag.x_offset || icon->drag.y_offset)
1065 	XOffsetRegion(icon->drag.region, -icon->drag.x_offset,
1066 		      -icon->drag.y_offset);
1067 
1068       XOffsetRegion(icon->drag.region, destX, destY);
1069       icon->drag.x_offset = destX;
1070       icon->drag.y_offset = destY;
1071 
1072       XUnionRegion(mixedIcon->drag.region, icon->drag.region,
1073 		   mixedIcon->drag.region);
1074     } else {
1075       if (mixedIcon->drag.region != NULL)
1076 	XDestroyRegion(mixedIcon->drag.region);
1077       mixedIcon->drag.region = NULL;
1078     }
1079 
1080     /*
1081      *  Copy the pixmap.
1082      */
1083     if (mixedIcon->drag.depth > 1) {
1084       v.foreground = dos->drag.cursorForeground;
1085       v.background = dos->drag.cursorBackground;
1086     } else {
1087       /* Else B & W */
1088       v.foreground = 1;
1089       v.background = 0;
1090     }
1091     v.function = GXcopy;
1092     vmask |= GCFunction|GCForeground|GCBackground;
1093     XChangeGC (display, pixmapGC, vmask, &v);
1094 
1095     if (icon->drag.depth == 1) {
1096       XCopyPlane (display, icon->drag.pixmap,
1097 		  mixedIcon->drag.pixmap, pixmapGC,
1098 		  sourceX, sourceY,
1099 		  icon->drag.width,
1100 		  icon->drag.height,
1101 		  destX, destY,
1102 		  1L);
1103     } else if (icon->drag.depth == mixedIcon->drag.depth) {
1104       XCopyArea (display, icon->drag.pixmap,
1105 		 mixedIcon->drag.pixmap, pixmapGC,
1106 		 sourceX, sourceY,
1107 		 icon->drag.width,
1108 		 icon->drag.height,
1109 		 destX, destY);
1110     } else {
1111       XmeWarning ((Widget) icon, MESSAGE1); /* cast ok here */
1112     }
1113   }
1114 }
1115 
1116 /************************************************************************
1117  *
1118  *  MixedIconSize ()
1119  *
1120  *  Determine the dimensions of the mixedIcon.
1121  ***********************************************************************/
1122 
1123 static void
MixedIconSize(XmDragOverShellWidget dos,XmDragIconObject sourceIcon,XmDragIconObject stateIcon,XmDragIconObject opIcon,Dimension * width,Dimension * height)1124 MixedIconSize(
1125     XmDragOverShellWidget	dos,
1126     XmDragIconObject		sourceIcon,
1127     XmDragIconObject		stateIcon,
1128     XmDragIconObject		opIcon,
1129     Dimension			*width,
1130     Dimension			*height)
1131 {
1132     Position		sourceX = 0, sourceY = 0;
1133     Position		minX = 0, minY = 0;
1134     Position		stateX = 0, stateY = 0;
1135     Position		opX, opY;
1136     Position		maxX, maxY;
1137 
1138     if (stateIcon) {
1139 	GetIconPosition (dos, stateIcon, sourceIcon, &stateX, &stateY);
1140         minX = MIN(stateX, minX);
1141         minY = MIN(stateY, minY);
1142     }
1143 
1144     if (opIcon) {
1145 	if (opIcon->drag.attachment == XmATTACH_HOT && stateIcon) {
1146 	    opX = stateX + stateIcon->drag.hot_x - opIcon->drag.hot_x;
1147 	    opY = stateY + stateIcon->drag.hot_y - opIcon->drag.hot_y;
1148 	}
1149 	else {
1150 	    GetIconPosition (dos, opIcon, sourceIcon, &opX, &opY);
1151 	}
1152         minX = MIN(opX, minX);
1153         minY = MIN(opY, minY);
1154     }
1155 
1156     sourceX -= minX;	/* >= 0 */
1157     sourceY -= minY;	/* >= 0 */
1158 
1159     maxX = sourceX + sourceIcon->drag.width;
1160     maxY = sourceY + sourceIcon->drag.height;
1161 
1162     if (stateIcon) {
1163 	stateX -= minX;
1164 	stateY -= minY;
1165         maxX = MAX(stateX + ((Position) stateIcon->drag.width), maxX);
1166         maxY = MAX(stateY + ((Position) stateIcon->drag.height), maxY);
1167     }
1168 
1169     if (opIcon) {
1170 	opX -= minX;
1171 	opY -= minY;
1172         maxX = MAX(opX + ((Position) opIcon->drag.width), maxX);
1173         maxY = MAX(opY + ((Position) opIcon->drag.height), maxY);
1174     }
1175 
1176     *width = maxX;
1177     *height = maxY;
1178 }
1179 
1180 /************************************************************************
1181  *
1182  *  DestroyMixedIcon ()
1183  *
1184  *  The MixedIcon's pixmap and mask, if present, were scratch pixmaps,
1185  *  and not from the Xm pixmap cache.  Therefore, they need to be freed
1186  *  separately and reset to XmUNSPECIFIED_PIXMAP.
1187  ***********************************************************************/
1188 
1189 static void
DestroyMixedIcon(XmDragOverShellWidget dos,XmDragIconObject mixedIcon)1190 DestroyMixedIcon(
1191     XmDragOverShellWidget	dos,
1192     XmDragIconObject		mixedIcon)
1193 {
1194     XmScreen		xmScreen = (XmScreen) XmGetXmScreen(XtScreen(dos));
1195     MixedIconCache 	*cache_ptr;
1196     MixedIconCache 	*prev_cache_ptr = NULL;
1197 
1198     if (mixedIcon->drag.pixmap != XmUNSPECIFIED_PIXMAP) {
1199         _XmFreeScratchPixmap (xmScreen, mixedIcon->drag.pixmap);
1200         mixedIcon->drag.pixmap = XmUNSPECIFIED_PIXMAP;
1201     }
1202 
1203     if (mixedIcon->drag.mask != XmUNSPECIFIED_PIXMAP) {
1204 	_XmFreeScratchPixmap (xmScreen, mixedIcon->drag.mask);
1205         mixedIcon->drag.mask = XmUNSPECIFIED_PIXMAP;
1206     }
1207 
1208     _XmProcessLock();
1209     cache_ptr = mixed_cache;
1210 
1211     while(cache_ptr) {
1212       MixedIconCache *next_cache_ptr = cache_ptr -> next;
1213 
1214       if (cache_ptr->mixedIcon == mixedIcon) {
1215 	if (cache_ptr == mixed_cache) {
1216 	  prev_cache_ptr = mixed_cache = cache_ptr->next;
1217 	} else {
1218 	  prev_cache_ptr->next = cache_ptr->next;
1219 	}
1220 	XtFree((char *) cache_ptr);
1221       } else {
1222 	prev_cache_ptr = cache_ptr;
1223       }
1224 
1225       cache_ptr = next_cache_ptr;
1226     }
1227     _XmProcessUnlock();
1228 
1229     XtDestroyWidget ((Widget) mixedIcon);
1230 }
1231 
1232 /************************************************************************
1233  *
1234  *  MixIcons ()
1235  *
1236  ***********************************************************************/
1237 
1238 static void
MixIcons(XmDragOverShellWidget dos,XmDragIconObject sourceIcon,XmDragIconObject stateIcon,XmDragIconObject opIcon,XmDragOverBlendRec * blendPtr,int clip)1239 MixIcons(
1240     XmDragOverShellWidget	dos,
1241     XmDragIconObject		sourceIcon,
1242     XmDragIconObject		stateIcon,
1243     XmDragIconObject		opIcon,
1244     XmDragOverBlendRec		*blendPtr,
1245 #if NeedWidePrototypes
1246     int				clip)
1247 #else
1248     Boolean			clip)
1249 #endif /* NeedWidePrototypes */
1250 {
1251     Display		*display = XtDisplay(dos);
1252     XmScreen		xmScreen = (XmScreen) XmGetXmScreen(XtScreen(dos));
1253     XmDragIconObject	mixedIcon = blendPtr->mixedIcon;
1254     XmDragOverBlendRec	*cursorBlend = &dos->drag.cursorBlend;
1255     Arg			al[8];
1256     Cardinal		ac;
1257     Pixmap		pixmap, mask;
1258     Position		sourceX = 0, sourceY = 0;
1259     Position		stateX = 0, stateY = 0;
1260     Position		opX = 0, opY = 0;
1261     Position		minX = 0, minY = 0;
1262     Position		maxX, maxY;
1263     Position		hotX, hotY;
1264     Dimension		width, height;
1265     Cardinal		depth;
1266     Boolean		need_mask = True;
1267     Boolean		do_cache = True;
1268     XGCValues		v;
1269     unsigned long	vmask;
1270 
1271     dos->drag.holePunched = False; /* Force update */
1272 
1273     /*
1274      *  Determine the dimensions of the blended icon and the positions
1275      *  of each component within it.
1276      */
1277 
1278     if (stateIcon) {
1279 	GetIconPosition (dos, stateIcon, sourceIcon, &stateX, &stateY);
1280         minX = MIN(stateX, minX);
1281         minY = MIN(stateY, minY);
1282     }
1283 
1284     /*
1285      *  If the opIcon's attachment is XmATTACH_HOT, attach its hotspot
1286      *  to the stateIcon's hotspot -- the blended icon's hotspot will be
1287      *  there, and the blended icon will be positioned so that the blended
1288      *  hotspot is placed at the cursor position.
1289      */
1290 
1291     if (opIcon) {
1292 	if (opIcon->drag.attachment == XmATTACH_HOT && stateIcon) {
1293 	    opX = stateX + stateIcon->drag.hot_x - opIcon->drag.hot_x;
1294 	    opY = stateY + stateIcon->drag.hot_y - opIcon->drag.hot_y;
1295 	}
1296 	else {
1297 	    GetIconPosition (dos, opIcon, sourceIcon, &opX, &opY);
1298 	}
1299         minX = MIN(opX, minX);
1300         minY = MIN(opY, minY);
1301     }
1302 
1303     sourceX -= minX;	/* >= 0 */
1304     sourceY -= minY;	/* >= 0 */
1305 
1306     maxX = sourceX + sourceIcon->drag.width;
1307     maxY = sourceY + sourceIcon->drag.height;
1308 
1309     if (stateIcon) {
1310 	stateX -= minX;
1311 	stateY -= minY;
1312         maxX = MAX(stateX + ((Position) stateIcon->drag.width), maxX);
1313         maxY = MAX(stateY + ((Position) stateIcon->drag.height), maxY);
1314         hotX = stateX + stateIcon->drag.hot_x;
1315 	hotY = stateY + stateIcon->drag.hot_y;
1316     }
1317     else {
1318 	hotX = sourceX + sourceIcon->drag.hot_x;
1319 	hotY = sourceY + sourceIcon->drag.hot_y;
1320     }
1321 
1322     if (opIcon) {
1323 	opX -= minX;
1324 	opY -= minY;
1325         maxX = MAX(opX + ((Position) opIcon->drag.width), maxX);
1326         maxY = MAX(opY + ((Position) opIcon->drag.height), maxY);
1327     }
1328 
1329     width = maxX;
1330     height = maxY;
1331 
1332     depth = ((blendPtr == cursorBlend) ? 1 : dos->core.depth);
1333 
1334     /*
1335      *  If we are clipping the blended icon to fit within a cursor,
1336      *  we clip it around the hotspot.
1337      */
1338 
1339     if (clip) {
1340         Dimension	maxWidth, maxHeight;
1341 
1342 	XmeQueryBestCursorSize((Widget) dos, &maxWidth, &maxHeight);
1343 
1344 	/* Pick new bounds to get the maximum icon possible while
1345 	   including the hotspot within the icon bounds */
1346 	if (width > maxWidth) {
1347 	  minX = MAX(0, hotX - ((Position) maxWidth) / 2);
1348 	  minX = MIN(minX, width - ((Position) maxWidth));
1349 	  hotX -= minX;
1350 	  sourceX -= minX;
1351 	  stateX -= minX;
1352 	  opX -= minX;
1353 	  width = maxWidth;
1354 	}
1355 	if (height > maxHeight) {
1356 	  minY = MAX(0, hotY - ((Position) maxHeight) / 2);
1357 	  minY = MIN(minY, height - ((Position) maxHeight));
1358 	  hotY -= minY;
1359 	  sourceY -= minY;
1360 	  stateY -= minY;
1361 	  opY -= minY;
1362 	  height = maxHeight;
1363 	}
1364     }
1365 
1366      mixedIcon = GetMixedIcon(dos, depth, width, height, sourceIcon, stateIcon,
1367 			    opIcon, sourceX, sourceY, stateX, stateY, opX, opY);
1368     /*
1369      *  Create the blended XmDragIcon object or use the current one
1370      *  if it is the correct size and depth.
1371      */
1372 
1373     if (mixedIcon != NULL) {
1374        blendPtr->mixedIcon = mixedIcon;
1375        do_cache = False;
1376     }
1377 
1378     /*
1379      *  The blended icon needs a mask unless none of its component icons
1380      *  has a mask and its component icons completely cover it.
1381      */
1382 
1383     if ((sourceIcon->drag.mask == XmUNSPECIFIED_PIXMAP) &&
1384 	(!stateIcon || stateIcon->drag.mask == XmUNSPECIFIED_PIXMAP) &&
1385 	(!opIcon || opIcon->drag.mask == XmUNSPECIFIED_PIXMAP)) {
1386 
1387 	XRectangle	rect;
1388 	Region		source = XCreateRegion();
1389 	Region		dest = XCreateRegion();
1390 	Region		tmp;
1391 
1392 	rect.x = (short) sourceX;
1393 	rect.y = (short) sourceY;
1394 	rect.width = (unsigned short) sourceIcon->drag.width;
1395 	rect.height = (unsigned short) sourceIcon->drag.height;
1396 	XUnionRectWithRegion (&rect, source, dest);
1397 
1398 	if (stateIcon) {
1399 	    tmp = source;
1400 	    source = dest;
1401 	    dest = tmp;
1402 
1403 	    rect.x = (short) stateX;
1404 	    rect.y = (short) stateY;
1405 	    rect.width = (unsigned short) stateIcon->drag.width;
1406 	    rect.height = (unsigned short) stateIcon->drag.height;
1407 	    XUnionRectWithRegion (&rect, source, dest);
1408 	}
1409 
1410 	if (opIcon) {
1411 	    tmp = source;
1412 	    source = dest;
1413 	    dest = tmp;
1414 
1415 	    rect.x = (short) opX;
1416 	    rect.y = (short) opY;
1417 	    rect.width = (unsigned short) opIcon->drag.width;
1418 	    rect.height = (unsigned short) opIcon->drag.height;
1419 	    XUnionRectWithRegion (&rect, source, dest);
1420 	}
1421 
1422 	if (RectangleIn == XRectInRegion (dest, 0, 0, width, height)) {
1423 	    need_mask = False;
1424 	}
1425 
1426 	XDestroyRegion (source);
1427 	XDestroyRegion (dest);
1428     }
1429 
1430     if (mixedIcon == NULL) {
1431 	pixmap = _XmAllocScratchPixmap (xmScreen, depth, width, height);
1432 
1433         mask = XmUNSPECIFIED_PIXMAP;
1434 
1435 	ac = 0;
1436 	XtSetArg(al[ac], XmNpixmap, pixmap); ac++;
1437 	XtSetArg(al[ac], XmNmask, mask); ac++;
1438 	XtSetArg(al[ac], XmNdepth, depth); ac++;
1439 	XtSetArg(al[ac], XmNwidth, width); ac++;
1440 	XtSetArg(al[ac], XmNheight, height); ac++;
1441 	XtSetArg(al[ac], XmNhotX, hotX); ac++;
1442 	XtSetArg(al[ac], XmNhotY, hotY); ac++;
1443 	mixedIcon = blendPtr->mixedIcon = (XmDragIconObject)
1444 	        XmCreateDragIcon ((Widget) xmScreen, "mixedIcon", al, ac);
1445 
1446 	if (need_mask) {
1447 	   mask = mixedIcon->drag.mask = _XmAllocScratchPixmap (xmScreen, 1,
1448 							        width, height);
1449 	}
1450     }
1451     else {
1452 	pixmap = mixedIcon->drag.pixmap;
1453 	mixedIcon->drag.hot_x = hotX;
1454 	mixedIcon->drag.hot_y = hotY;
1455 	if (need_mask && mixedIcon->drag.mask == XmUNSPECIFIED_PIXMAP) {
1456 	    mixedIcon->drag.mask =
1457 	        _XmAllocScratchPixmap (xmScreen, 1, width, height);
1458 	}
1459 	mask = mixedIcon->drag.mask;
1460     }
1461 
1462     if (sourceIcon->drag.region != NULL) {
1463        if (mixedIcon->drag.region != NULL)
1464           XDestroyRegion(mixedIcon->drag.region);
1465 
1466        mixedIcon->drag.region = XCreateRegion();
1467     }
1468 
1469     /*
1470      *  Get the cursorBlend GC if needed (the root GC already exists).
1471      *  Set the pixmap to its background color.
1472      *  Clear any mask.
1473      */
1474 
1475     if (blendPtr->gc == NULL) {
1476 	v.background = 0;
1477 	v.foreground = 1;
1478 	v.function = GXset;
1479 	v.graphics_exposures = False;
1480 	v.subwindow_mode = IncludeInferiors;
1481 	v.clip_mask = None;
1482         v.clip_x_origin = 0;	/* pedantic */
1483         v.clip_y_origin = 0;	/* pedantic */
1484 	vmask = GCBackground|GCForeground|GCFunction|
1485 	        GCClipXOrigin|GCClipYOrigin|GCClipMask|
1486 		GCGraphicsExposures|GCSubwindowMode;
1487 	blendPtr->gc = XtAllocateGC((Widget) dos, mixedIcon -> drag.depth,
1488 				    vmask, &v, vmask, 0L);
1489     }
1490     else {
1491 	v.clip_mask = None;
1492 	v.function = GXset;
1493 	vmask = GCClipMask|GCFunction;
1494         XChangeGC (display, blendPtr->gc, vmask, &v);
1495     }
1496 
1497     XFillRectangle (display, pixmap, blendPtr->gc,
1498 		    0, 0, mixedIcon->drag.width, mixedIcon->drag.height);
1499 
1500     if (mask != XmUNSPECIFIED_PIXMAP) {
1501 	if (cursorBlend->gc == NULL) {
1502 	    v.background = 0;
1503 	    v.foreground = 1;
1504 	    v.function = GXclear;
1505 	    v.graphics_exposures = False;
1506 	    v.subwindow_mode = IncludeInferiors;
1507 	    v.clip_mask = None;
1508             v.clip_x_origin = 0;	/* pedantic */
1509             v.clip_y_origin = 0;	/* pedantic */
1510 	    vmask = GCBackground|GCForeground|GCFunction|
1511 	            GCClipXOrigin|GCClipYOrigin|GCClipMask|
1512 		    GCGraphicsExposures|GCSubwindowMode;
1513 	    cursorBlend->gc = XtAllocateGC((Widget) dos, 1,
1514 					   vmask, &v, vmask, 0L);
1515 	}
1516 	else {
1517 	    v.function = GXclear;
1518 	    vmask = GCFunction;
1519 	    if (cursorBlend->gc != blendPtr->gc) {
1520 	       v.clip_mask = None;
1521 	       vmask |= GCClipMask;
1522             }
1523             XChangeGC (display, cursorBlend->gc, vmask, &v);
1524         }
1525 
1526 	XFillRectangle (display, mixedIcon->drag.mask, cursorBlend->gc,
1527 			0, 0, mixedIcon->drag.width, mixedIcon->drag.height);
1528     }
1529 
1530     /*
1531      *  Blend the icons into mixedIcon.
1532      */
1533 
1534     BlendIcon (dos, sourceIcon, mixedIcon,
1535 	       sourceX, sourceY, cursorBlend->gc, blendPtr->gc);
1536     blendPtr->sourceX = sourceX;
1537     blendPtr->sourceY = sourceY;
1538 
1539     if (stateIcon) {
1540         BlendIcon (dos, stateIcon, mixedIcon,
1541 		   stateX, stateY, cursorBlend->gc, blendPtr->gc);
1542     }
1543 
1544     if (opIcon) {
1545         BlendIcon (dos, opIcon, mixedIcon,
1546 		   opX, opY, cursorBlend->gc, blendPtr->gc);
1547     }
1548 
1549     if (mixedIcon->drag.region != NULL) {
1550        XRectangle rect;
1551 
1552        if (mixedIcon->drag.restore_region != NULL)
1553           XDestroyRegion(mixedIcon->drag.restore_region);
1554 
1555        mixedIcon->drag.restore_region = XCreateRegion();
1556 
1557        rect.x = 0;
1558        rect.y = 0;
1559        rect.width = mixedIcon->drag.width;
1560        rect.height = mixedIcon->drag.height;
1561 
1562        XUnionRectWithRegion(&rect, mixedIcon->drag.restore_region,
1563                             mixedIcon->drag.restore_region);
1564        XSubtractRegion(mixedIcon->drag.restore_region, mixedIcon->drag.region,
1565                        mixedIcon->drag.restore_region);
1566     }
1567 
1568     if (do_cache) {
1569       CacheMixedIcon(dos, depth, width, height, sourceIcon, stateIcon, opIcon,
1570 		     sourceX, sourceY, stateX, stateY, opX, opY, mixedIcon);
1571     } /* do_cache */
1572 }
1573 
1574 /************************************************************************
1575  *
1576  *  FitsInCursor ()
1577  *
1578  ***********************************************************************/
1579 
1580 static Boolean
FitsInCursor(XmDragOverShellWidget dos,XmDragIconObject sourceIcon,XmDragIconObject stateIcon,XmDragIconObject opIcon)1581 FitsInCursor(
1582     XmDragOverShellWidget	dos,
1583     XmDragIconObject		sourceIcon,
1584     XmDragIconObject		stateIcon,
1585     XmDragIconObject		opIcon)
1586 {
1587     Dimension		maxWidth, maxHeight;
1588     Dimension		width, height;
1589 
1590     if (((sourceIcon->drag.depth != 1) ||
1591 	 (sourceIcon->drag.pixmap == XmUNSPECIFIED_PIXMAP))) {
1592 	return False;
1593     }
1594 
1595     MixedIconSize (dos, sourceIcon, stateIcon, opIcon, &width, &height);
1596     XmeQueryBestCursorSize((Widget)dos, &maxWidth, &maxHeight);
1597 
1598     if (width > maxWidth || height > maxHeight) {
1599 	return False;
1600     }
1601     return True;
1602 }
1603 
1604 /************************************************************************
1605  *
1606  *  GetDragIconColors ()
1607  *
1608  *  Gets the cursor colors.  Creates or recolors the root's gc.
1609  ***********************************************************************/
1610 
1611 static Boolean
GetDragIconColors(XmDragOverShellWidget dos)1612 GetDragIconColors(
1613     XmDragOverShellWidget	dos )
1614 {
1615     XmDragContext	dc = (XmDragContext)XtParent(dos);
1616     Screen		*screen = XtScreen(dos);
1617     Display		*display = XtDisplay(dos);
1618     Boolean		doChange = False;
1619     Pixel		fg;
1620     Pixel		bg;
1621     XGCValues	        v;
1622     unsigned long	vmask;
1623     XColor 		colors[2];
1624     Colormap		colormap;
1625 
1626     colormap = dc->core.colormap;
1627     bg = dc->drag.cursorBackground;
1628     switch ((int) dos->drag.cursorState) {
1629 
1630 	case XmVALID_DROP_SITE:
1631             fg = dc->drag.validCursorForeground;
1632 	    break;
1633 
1634 	case XmINVALID_DROP_SITE:
1635             fg = dc->drag.invalidCursorForeground;
1636 	    break;
1637 
1638 	default:
1639 	    XmeWarning ((Widget) dos, MESSAGE3);
1640 	case XmNO_DROP_SITE:
1641             fg = dc->drag.noneCursorForeground;
1642 	    break;
1643     }
1644 
1645     /*
1646      *  Find the best RGB fit for fg and bg on the current screen.
1647      *  If XAllocColor() fails or if the fitted fg and bg are the same on the
1648      *  current screen, use black and white respectively.
1649      */
1650 
1651     colors[0].pixel = fg;
1652     colors[1].pixel = bg;
1653     XQueryColors(display, colormap, colors, 2);
1654 
1655     fg = BlackPixelOfScreen(screen);
1656     bg = WhitePixelOfScreen(screen);
1657     if (XAllocColor(display, DefaultColormapOfScreen(screen), &colors[0]) &&
1658         XAllocColor(display, DefaultColormapOfScreen(screen), &colors[1])) {
1659 	fg = colors[0].pixel;
1660 	bg = colors[1].pixel;
1661 
1662     	if (fg == bg) {
1663     	    fg = BlackPixelOfScreen(screen);
1664     	    bg = WhitePixelOfScreen(screen);
1665     	}
1666     }
1667 
1668     /*
1669      *  Create or recolor the root's gc.
1670      *  The cursorForeground and cursorBackground are first set
1671      *  when the root's gc is created.
1672      */
1673 
1674     if (dos->drag.rootBlend.gc == NULL) {
1675 	doChange = True;
1676 	v.background = dos->drag.cursorBackground = bg;
1677 	v.foreground = dos->drag.cursorForeground = fg;
1678 	v.graphics_exposures = False;
1679 	v.subwindow_mode = IncludeInferiors;
1680 	v.clip_mask = None;
1681         v.clip_x_origin = 0;	/* pedantic */
1682         v.clip_y_origin = 0;	/* pedantic */
1683 	vmask = GCBackground|GCForeground|
1684 	        GCClipXOrigin|GCClipYOrigin|GCClipMask|
1685 	        GCGraphicsExposures|GCSubwindowMode;
1686 	dos->drag.rootBlend.gc = XtAllocateGC ((Widget) dos,
1687 					       DefaultDepthOfScreen(screen),
1688 					       vmask, &v, vmask, 0L);
1689     }
1690     else if (dos->drag.cursorBackground != bg ||
1691 	     dos->drag.cursorForeground != fg) {
1692 	doChange = True;
1693 	v.background = dos->drag.cursorBackground = bg;
1694 	v.foreground = dos->drag.cursorForeground = fg;
1695 	vmask = GCBackground|GCForeground;
1696 	XChangeGC (display, dos->drag.rootBlend.gc, vmask, &v);
1697     }
1698     return (doChange);
1699 }
1700 
1701 /************************************************************************
1702  *
1703  *  GetDragIconCursor ()
1704  *
1705  *  Tries to create a pixmap cursor with correct colors.
1706  *  Creates and/or colors the root's gc.
1707  ***********************************************************************/
1708 
1709 static Cursor
GetDragIconCursor(XmDragOverShellWidget dos,XmDragIconObject sourceIcon,XmDragIconObject stateIcon,XmDragIconObject opIcon,int clip,int dirty)1710 GetDragIconCursor(
1711     XmDragOverShellWidget	dos,
1712     XmDragIconObject		sourceIcon,
1713     XmDragIconObject		stateIcon,
1714     XmDragIconObject		opIcon,
1715 #if NeedWidePrototypes
1716     int				clip,
1717     int				dirty)
1718 #else
1719     Boolean			clip,
1720     Boolean			dirty)
1721 #endif /* NeedWidePrototypes */
1722 {
1723     Screen			*screen = XtScreen(dos);
1724     Display			*display = XtDisplay(dos);
1725     XmDragCursorCache		*cursorCachePtr= NULL;
1726     register XmDragCursorCache	cursorCache = NULL;
1727     XColor 			colors[2];
1728     Boolean			useCache = True;
1729     Cursor			cursor;
1730     XmDragIconObject		dirtysourceIcon = NULL;
1731     XmDragIconObject		dirtystateIcon = NULL;
1732     XmDragIconObject		dirtyopIcon = NULL;
1733 
1734     /*
1735      *  If the cursor doesn't fit and we cannot clip, return None.
1736      *  Don't look in the cursorCache -- the cursor would only be there
1737      *    if clipping were allowed.
1738      */
1739 
1740     if (!clip && !FitsInCursor (dos, sourceIcon, stateIcon, opIcon)) {
1741 	return None;
1742     }
1743 
1744     /*
1745      *  Don't use the cursorCache with stateIcon attachment XmATTACH_HOT
1746      *  (opIcon attachment XmATTACH_HOT is OK).
1747      */
1748 
1749     colors[0].pixel = dos->drag.cursorForeground;
1750     colors[1].pixel = dos->drag.cursorBackground;
1751     XQueryColors(display, DefaultColormapOfScreen(screen), colors, 2);
1752 
1753     /*
1754      * Fix for CR 4817 - If one of the icons is dirty, check the cache to see
1755      *                   which cursors use the dirty icon.  When found, mark
1756      *                   the cache as dirty.
1757      */
1758     cursorCachePtr = _XmGetDragCursorCachePtr((XmScreen)XmGetXmScreen(screen));
1759     if (dirty)
1760       {
1761 	cursorCache = *cursorCachePtr;
1762 	if (sourceIcon->drag.isDirty)
1763 	  dirtysourceIcon = sourceIcon;
1764 	if (stateIcon && (stateIcon->drag.isDirty))
1765 	  dirtystateIcon = stateIcon;
1766 	if (opIcon && (opIcon->drag.isDirty))
1767 	  dirtyopIcon = opIcon;
1768 
1769 	while (cursorCache)
1770 	  {
1771 	    if ((dirtystateIcon && (cursorCache->stateIcon == dirtystateIcon)) ||
1772 		(dirtysourceIcon && (cursorCache->sourceIcon == dirtysourceIcon)) ||
1773 		(dirtyopIcon && (cursorCache->opIcon == dirtyopIcon)))
1774 	      cursorCache->dirty = True;
1775 	    cursorCache = cursorCache->next;
1776 	  }
1777       }
1778     /*
1779      * End Fix for CR 4817
1780      */
1781 
1782     if (stateIcon && stateIcon->drag.attachment == XmATTACH_HOT) {
1783 	useCache = False;
1784     }
1785     else {
1786 	cursorCachePtr =
1787 	    _XmGetDragCursorCachePtr((XmScreen)XmGetXmScreen(screen));
1788 
1789 	cursorCache = *cursorCachePtr;
1790 	while (cursorCache) {
1791             if ((cursorCache->stateIcon == stateIcon) &&
1792                 (cursorCache->opIcon == opIcon) &&
1793 	        (cursorCache->sourceIcon == sourceIcon)) {
1794 
1795 		/*
1796 		 *  Found a cursorCache match.
1797 		 *  If any of the icons were dirty, replace this cursor.
1798 		 *  Otherwise, use it.
1799 		 */
1800 
1801 		if (cursorCache -> dirty) {
1802 		    break;
1803 		}
1804 
1805 	        /* recolor the cursor */
1806 	        XRecolorCursor (display, cursorCache->cursor,
1807 			        &colors[0], /* foreground_color */
1808 			        &colors[1]  /* background_color */);
1809 	        return cursorCache->cursor;
1810 	    }
1811 	    else {
1812 	        cursorCache = cursorCache->next;
1813 	    }
1814 	}
1815     }
1816 
1817     /*
1818      *  We didn't find a valid match in the cursorCache.
1819      *  Blend the icons and create a pixmap cursor.
1820      */
1821 
1822     MixIcons (dos, sourceIcon, stateIcon, opIcon,
1823 	      &dos->drag.cursorBlend, clip);
1824 
1825     cursor =
1826 	XCreatePixmapCursor (display,
1827 			     dos->drag.cursorBlend.mixedIcon->drag.pixmap,
1828 	((dos->drag.cursorBlend.mixedIcon->drag.mask == XmUNSPECIFIED_PIXMAP) ?
1829 		None : dos->drag.cursorBlend.mixedIcon->drag.mask),
1830 			     &colors[0], /* foreground_color */
1831 			     &colors[1], /* background_color */
1832 			     dos->drag.cursorBlend.mixedIcon->drag.hot_x,
1833 			     dos->drag.cursorBlend.mixedIcon->drag.hot_y);
1834 
1835     /*
1836      *  Cache the cursor if using the cursorCache.  If the cached cursor
1837      *    was dirty, replace it.  Otherwise, create a new cursorCache entry
1838      *    at the head of the cache.
1839      *  Otherwise, save it and free any previously saved cursor.
1840      */
1841 
1842     if (useCache) {
1843 	if (cursorCache) {
1844 	    XFreeCursor (display, cursorCache->cursor);
1845 	}
1846 	else {
1847 	    cursorCache = XtNew(XmDragCursorRec);
1848 	    cursorCache->sourceIcon = sourceIcon;
1849 	    cursorCache->stateIcon = stateIcon;
1850 	    cursorCache->opIcon = opIcon;
1851 	    cursorCache->next = *cursorCachePtr;
1852 	    *cursorCachePtr = cursorCache;
1853 	}
1854         cursorCache->dirty = False;
1855 	cursorCache->cursor = cursor;
1856     }
1857     else {
1858         if (dos->drag.ncCursor != None) {
1859 	    XFreeCursor (display, dos->drag.ncCursor);
1860         }
1861         dos->drag.ncCursor = cursor;
1862     }
1863 
1864     return cursor;
1865 }
1866 
1867 /************************************************************************
1868  *
1869  *  Initialize ()
1870  *
1871  ***********************************************************************/
1872 
1873 /*ARGSUSED*/
1874 static void
Initialize(Widget req,Widget new_w,ArgList args,Cardinal * numArgs)1875 Initialize(
1876     Widget	req,		/* unused */
1877     Widget	new_w,
1878     ArgList	args,		/* unused */
1879     Cardinal	*numArgs)	/* unused */
1880 {
1881     XmDragOverShellWidget	dos = (XmDragOverShellWidget)new_w;
1882 
1883     /* Assure that *geometry will never affect this widget,  CR 5778 */
1884     dos->shell.geometry = NULL;
1885 
1886     dos->drag.opIcon = dos->drag.stateIcon = NULL;
1887     dos->drag.cursorBlend.gc =
1888 	dos->drag.rootBlend.gc = NULL;
1889     dos->drag.cursorBlend.sourceIcon =
1890 	dos->drag.cursorBlend.mixedIcon =
1891 	    dos->drag.rootBlend.sourceIcon =
1892 		dos->drag.rootBlend.mixedIcon = NULL;
1893     dos->drag.backing.pixmap = dos->drag.tmpPix =
1894 	dos->drag.tmpBit = XmUNSPECIFIED_PIXMAP;
1895 
1896     dos->drag.initialX = dos->drag.hotX;
1897     dos->drag.initialY = dos->drag.hotY;
1898     dos->drag.ncCursor = None;
1899     dos->drag.isVisible = False;
1900     dos->drag.activeCursor = None;
1901 
1902     /*
1903      *  Width/height are valid only in XmPIXMAP and XmWINDOW active modes.
1904      */
1905 
1906     dos->core.width = 0;
1907     dos->core.height = 0;
1908 
1909     dos->drag.activeMode = XmCURSOR;
1910 
1911     /*
1912      * Get the DragOverShell out of the business of adding and removing
1913      * grabs for shell modality.
1914      */
1915     XtRemoveAllCallbacks( new_w, XmNpopupCallback) ;
1916     XtRemoveAllCallbacks( new_w, XmNpopdownCallback) ;
1917 
1918     /* Setup information for window dragging */
1919     dos->drag.holePunched = FALSE;
1920     dos->drag.colormapShell = (Widget) NULL;
1921     dos->drag.colormapWidget = (Widget) NULL;
1922     DragOverShellColormapWidget(new_w, XtParent(new_w));
1923 
1924     _XmDragOverChange (new_w, XmNO_DROP_SITE);
1925 }
1926 
1927 /************************************************************************
1928  *
1929  *  SetValues
1930  *
1931  ************************************************************************/
1932 
1933 /*ARGSUSED*/
1934 static Boolean
SetValues(Widget current,Widget req,Widget new_w,ArgList args,Cardinal * num_args)1935 SetValues(
1936     Widget	current,
1937     Widget	req,		/* unused */
1938     Widget	new_w,
1939     ArgList	args,		/* unused */
1940     Cardinal	*num_args)	/* unused */
1941 {
1942     XmDragOverShellWidget	dos = (XmDragOverShellWidget) new_w;
1943     XmDragOverShellWidget	oldDos = (XmDragOverShellWidget) current;
1944     XmDragContext		dc = (XmDragContext)XtParent(dos);
1945 
1946     /* If the hotspot or geometry changes we'll need to punch a
1947        new hole in the shaped window */
1948     if (oldDos->drag.hotX != dos->drag.hotX ||
1949 	oldDos->drag.hotY != dos->drag.hotY ||
1950 	oldDos->core.width != dos->core.width ||
1951 	oldDos->core.height != dos->core.height)
1952       dos->drag.holePunched = FALSE;
1953 
1954     /*
1955      *  A mode change handles a change in hotspot automatically.
1956      *  If we are in XmPIXMAP mode and we haven't yet done a root blend,
1957      *  try XmCURSOR active mode.
1958      */
1959 
1960     if (oldDos->drag.mode != dos->drag.mode &&
1961 	dc->drag.blendModel != XmBLEND_NONE) {
1962 	if ((dos->drag.mode == XmPIXMAP ||
1963 	     dos->drag.mode == XmDRAG_WINDOW) &&
1964 	    (dos->drag.rootBlend.sourceIcon == NULL)) {
1965 	    ChangeActiveMode(dos, XmCURSOR);
1966 	}
1967 	else {
1968 	    ChangeActiveMode(dos, dos->drag.mode);
1969 	}
1970     }
1971     else if ((dos->drag.hotX != oldDos->drag.hotX) ||
1972              (dos->drag.hotY != oldDos->drag.hotY)) {
1973 	_XmDragOverMove (new_w, dos->drag.hotX, dos->drag.hotY);
1974     }
1975     return False;
1976 }
1977 
1978 /************************************************************************
1979  *
1980  *  DrawIcon ()
1981  *
1982  ************************************************************************/
1983 
1984 static void
DrawIcon(XmDragOverShellWidget dos,XmDragIconObject icon,Window window,int x,int y)1985 DrawIcon(
1986     XmDragOverShellWidget	dos,
1987     XmDragIconObject		icon,
1988     Window			window,
1989 #if NeedWidePrototypes
1990     int				x,
1991     int				y)
1992 #else
1993     Position			x,
1994     Position			y)
1995 #endif /* NeedWidePrototypes */
1996 {
1997     GC		draw_gc = dos->drag.rootBlend.gc;
1998     Boolean	clipped = False;
1999     XGCValues	        v;
2000     unsigned long	vmask;
2001     Display * 	display = XtDisplay((Widget)dos);
2002 
2003     v.function = GXcopy;
2004     vmask = GCFunction;
2005 
2006     if (icon->drag.region == NULL &&
2007         icon->drag.mask != XmUNSPECIFIED_PIXMAP) {
2008 	v.clip_mask = icon->drag.mask;
2009 	v.clip_x_origin = x;
2010 	v.clip_y_origin = y;
2011 	vmask |= GCClipMask|GCClipXOrigin|GCClipYOrigin;
2012 	XChangeGC (display, draw_gc, vmask, &v);
2013 	clipped = True;
2014     }
2015     else {
2016         if (icon->drag.region != NULL) {
2017 	   XSetRegion(display, draw_gc, icon->drag.region);
2018 	   v.clip_x_origin = x;
2019 	   v.clip_y_origin = y;
2020 	   vmask |= GCClipXOrigin|GCClipYOrigin;
2021 	   XChangeGC (display, draw_gc, vmask, &v);
2022 	   clipped = True;
2023         }
2024         else {
2025 	   v.clip_mask = None;
2026 	   vmask |= GCClipMask;
2027 	   XChangeGC (display, draw_gc, vmask, &v);
2028         }
2029     }
2030 
2031     /*
2032      *  If the icon is from the cursorBlend, treat the icon as a bitmap
2033      *  and use XCopyPlane.  Otherwise, treat it as a pixmap and use
2034      *  XCopyArea.  The distinction is important -- the icon data are
2035      *  treated differently by XCopyPlane and XCopyArea.
2036      */
2037 
2038     if (icon == dos->drag.cursorBlend.mixedIcon) {
2039 	XCopyPlane(display,
2040 		   icon->drag.pixmap, window, draw_gc,
2041 		   0, 0,
2042 		   dos->core.width, dos->core.height,
2043 		   x, y, 1L);
2044     }
2045     else if (icon->drag.depth == dos->core.depth) {
2046 	XCopyArea(display,
2047 		  icon->drag.pixmap, window, draw_gc,
2048 		  0, 0,
2049 		  dos->core.width, dos->core.height,
2050 		  x, y);
2051     }
2052     else {
2053 	XmeWarning ((Widget) icon, MESSAGE1); /* cast ok here */
2054     }
2055 
2056     if (clipped) {
2057         XSetClipMask (display, draw_gc, None);
2058     }
2059 }
2060 
2061 /************************************************************************
2062  *
2063  *  Redisplay ()
2064  *
2065  *  Called in XmWINDOW mode only.
2066  ***********************************************************************/
2067 
2068 /*ARGSUSED*/
2069 static void
Redisplay(Widget wid,XEvent * event,Region region)2070 Redisplay(
2071     Widget wid,
2072     XEvent *event,		/* unused */
2073     Region region)		/* unused */
2074 {
2075     XmDragOverShellWidget	dos = (XmDragOverShellWidget)wid;
2076 
2077     DrawIcon (dos,
2078 	      (dos->drag.rootBlend.mixedIcon ?
2079 	       dos->drag.rootBlend.mixedIcon :
2080                dos->drag.cursorBlend.mixedIcon),
2081 	      XtWindow(dos), 0, 0);
2082 }
2083 
2084 /************************************************************************
2085  *
2086  *  _XmDragOverHide ()
2087  *
2088  ***********************************************************************/
2089 
2090 void
_XmDragOverHide(Widget w,int clipOriginX,int clipOriginY,XmRegion clipRegion)2091 _XmDragOverHide(
2092     Widget	w,
2093 #if NeedWidePrototypes
2094     int		clipOriginX,
2095     int		clipOriginY,
2096 #else
2097     Position	clipOriginX,
2098     Position	clipOriginY,
2099 #endif /* NeedWidePrototypes */
2100     XmRegion	clipRegion )
2101 {
2102     XmDragOverShellWidget	dos = (XmDragOverShellWidget) w;
2103     XmDragContext	dc = (XmDragContext)XtParent(dos);
2104     Boolean		clipped = False;
2105 
2106     if (dos->drag.isVisible &&
2107 	dc->drag.blendModel != XmBLEND_NONE &&
2108 	dos->drag.activeMode != XmCURSOR) {
2109 
2110 	if (dos->drag.activeMode == XmWINDOW ||
2111 	    dos->drag.activeMode == XmDRAG_WINDOW) {
2112 	    XtPopdown(w);
2113 	    if (dos->drag.installColormap)
2114 	      UninstallColormap(dos);
2115 	}
2116 
2117 	if (dos->drag.activeMode != XmWINDOW) {
2118 	  if (clipRegion != None) {
2119 	    clipped = True;
2120 	    _XmRegionSetGCRegion (XtDisplay(w),
2121                                   dos->drag.rootBlend.gc,
2122 				  clipOriginX, clipOriginY, clipRegion);
2123 	  }
2124 	  else {
2125 	    XSetClipMask (XtDisplay(w),
2126                           dos->drag.rootBlend.gc, None);
2127 	  }
2128 
2129 	  if (BackingPixmap(dos) != XmUNSPECIFIED_PIXMAP) {
2130 	    XCopyArea (XtDisplay(w),
2131 	               BackingPixmap(dos),
2132 	               RootWindowOfScreen(XtScreen(w)),
2133 		       dos->drag.rootBlend.gc,
2134 	               0, 0, dos->core.width, dos->core.height,
2135 	               BackingX(dos), BackingY(dos));
2136 	  }
2137 
2138 	  if (clipped) {
2139             XSetClipMask (XtDisplay(w),
2140 		          dos->drag.rootBlend.gc, None);
2141 	  }
2142 	}
2143 
2144 	dos->drag.isVisible = False;
2145     }
2146 }
2147 
2148 /************************************************************************
2149  *
2150  *  _XmDragOverShow ()
2151  *
2152  ***********************************************************************/
2153 
2154 void
_XmDragOverShow(Widget w,int clipOriginX,int clipOriginY,XmRegion clipRegion)2155 _XmDragOverShow(
2156     Widget w,
2157 #if NeedWidePrototypes
2158     int clipOriginX,
2159     int clipOriginY,
2160 #else
2161     Position clipOriginX,
2162     Position clipOriginY,
2163 #endif /* NeedWidePrototypes */
2164     XmRegion			clipRegion )
2165 {
2166     XmDragOverShellWidget	dos = (XmDragOverShellWidget) w;
2167     Display		*display = XtDisplay(w);
2168     XmDragContext	dc = (XmDragContext)XtParent(dos);
2169     Boolean		clipped = False;
2170 
2171     if (!dos->drag.isVisible &&
2172 	dc->drag.blendModel != XmBLEND_NONE &&
2173 	dos->drag.activeMode != XmCURSOR) {
2174 
2175 	if (dos->drag.activeMode != XmWINDOW && clipRegion != None) {
2176 	    clipped = True;
2177 	    _XmRegionSetGCRegion (display, dos->drag.rootBlend.gc,
2178 	                          clipOriginX - BackingX(dos),
2179 	                          clipOriginY - BackingY(dos),
2180 				  clipRegion);
2181 	}
2182 	else {
2183 	    XSetClipMask (display, dos->drag.rootBlend.gc, None);
2184 	}
2185 
2186 	if (dos->drag.activeMode == XmPIXMAP) {
2187 	  XCopyArea (display, RootWindowOfScreen(XtScreen(w)),
2188 		     BackingPixmap(dos),
2189 		     dos->drag.rootBlend.gc,
2190 		     BackingX(dos), BackingY(dos),
2191 		     dos->core.width, dos->core.height,
2192 		     0, 0);
2193 	}
2194 
2195         if (clipped) {
2196             XSetClipMask (display, dos->drag.rootBlend.gc, None);
2197         }
2198 
2199 	if (dos->drag.activeMode == XmPIXMAP) {
2200 	  DrawIcon (dos,
2201 		    (dos->drag.rootBlend.mixedIcon ?
2202 		     dos->drag.rootBlend.mixedIcon :
2203 		     dos->drag.cursorBlend.mixedIcon),
2204 		    RootWindowOfScreen(XtScreen(w)),
2205 		    dos->core.x, dos->core.y);
2206 	} else {
2207 	  XtPopup(w, XtGrabNone);
2208 	  /*
2209 	   * don't call thru class record since VendorS bug may be
2210 	   * causing override
2211 	   */
2212 	  if (dos->drag.activeMode == XmDRAG_WINDOW) {
2213 	    Arg args[1];
2214 	    if (!dos->drag.holePunched)
2215 	      DragOverShellPunchHole(w);
2216 	    if (dos->drag.installColormap)
2217 	      InstallColormap(dos);
2218 	    XtSetArg(args[0], XmNbackgroundPixmap,
2219 		     dos->drag.rootBlend.mixedIcon->drag.pixmap);
2220 	    XtSetValues((Widget) dos, args, 1);
2221 	  } else {
2222 	    Redisplay(w, NULL, NULL);
2223 	  }
2224 	}
2225 	dos->drag.isVisible = True;
2226     }
2227 }
2228 
2229 /************************************************************************
2230  *
2231  *  Destroy ()
2232  *
2233  *  Destroy method for the XmDragOverShellClass.
2234  *  Hide the XmDragOverShell before destroying it.
2235  ***********************************************************************/
2236 
2237 static void
Destroy(Widget w)2238 Destroy(
2239     Widget	w)
2240 {
2241     XmDragOverShellWidget	dos = (XmDragOverShellWidget)w;
2242     Display			*display = XtDisplay((Widget)dos);
2243     XmScreen			xmScreen =
2244 				    (XmScreen) XmGetXmScreen(XtScreen(dos));
2245 
2246     _XmDragOverHide (w, 0, 0, None);
2247 
2248     if (dos->drag.rootBlend.mixedIcon) {
2249 	DestroyMixedIcon (dos, dos->drag.rootBlend.mixedIcon);
2250     }
2251     if (dos->drag.rootBlend.gc) {
2252         XtReleaseGC((Widget) dos, dos->drag.rootBlend.gc);
2253     }
2254 
2255     if (dos->drag.cursorBlend.mixedIcon) {
2256 	DestroyMixedIcon (dos, dos->drag.cursorBlend.mixedIcon);
2257     }
2258     if (dos->drag.cursorBlend.gc) {
2259         XtReleaseGC ((Widget) dos, dos->drag.cursorBlend.gc);
2260     }
2261     if (BackingPixmap(dos) != XmUNSPECIFIED_PIXMAP) {
2262 	_XmFreeScratchPixmap (xmScreen, BackingPixmap(dos));
2263     }
2264     if (dos->drag.tmpPix != XmUNSPECIFIED_PIXMAP) {
2265 	_XmFreeScratchPixmap (xmScreen, dos->drag.tmpPix);
2266     }
2267     if (dos->drag.tmpBit != XmUNSPECIFIED_PIXMAP) {
2268 	_XmFreeScratchPixmap (xmScreen, dos->drag.tmpBit);
2269     }
2270 
2271     if (dos->drag.ncCursor != None) {
2272 	XFreeCursor (display, dos->drag.ncCursor);
2273     }
2274 }
2275 
2276 /************************************************************************
2277  *
2278  *  ChangeActiveMode ()
2279  *
2280  ***********************************************************************/
2281 
2282 static void
ChangeActiveMode(XmDragOverShellWidget dos,unsigned int newActiveMode)2283 ChangeActiveMode(
2284     XmDragOverShellWidget	dos,
2285 #if NeedWidePrototypes
2286     unsigned int		newActiveMode)
2287 #else
2288     unsigned char		newActiveMode)
2289 #endif /* NeedWidePrototypes */
2290 {
2291   Display		*display = XtDisplay((Widget)dos);
2292   XmDragContext	dc = (XmDragContext)XtParent(dos);
2293   GC			draw_gc = dos->drag.rootBlend.gc;
2294 
2295   /*
2296    *  Remove the effects of the current active mode.
2297    */
2298 
2299   if (dos->drag.activeMode == XmCURSOR) {
2300     if (newActiveMode != XmCURSOR) {
2301       dos->drag.activeCursor = XmeGetNullCursor((Widget)dos);
2302       XChangeActivePointerGrab (display,
2303 				(unsigned int) _XmDRAG_EVENT_MASK(dc),
2304 				dos->drag.activeCursor,
2305 				dc->drag.lastChangeTime);
2306     }
2307   }
2308   else {
2309     /*
2310      *  BackingPixmap was created and core.width/height were set
2311      *  the first time we entered XmPIXMAP or XmWINDOW active mode.
2312      */
2313 
2314     if (dos->drag.activeMode == XmWINDOW ||
2315 	dos->drag.activeMode == XmDRAG_WINDOW) {
2316       XtPopdown((Widget)dos);
2317     }
2318     XSetClipMask (display, draw_gc, None);
2319     if (BackingPixmap(dos) != XmUNSPECIFIED_PIXMAP) {
2320       XCopyArea (display, BackingPixmap(dos),
2321 		 RootWindowOfScreen(XtScreen(dos)), draw_gc,
2322 		 0, 0,
2323 		 dos->core.width, dos->core.height,
2324 		 BackingX(dos), BackingY(dos));
2325     }
2326   }
2327   dos->drag.isVisible = False;
2328 
2329   /*
2330    *  Add the effects of the new active mode.
2331    */
2332   if ((dos->drag.activeMode = newActiveMode) == XmCURSOR) {
2333     _XmDragOverChange ((Widget)dos, dos->drag.cursorState);
2334   } else {
2335     XmScreen		xmScreen = (XmScreen)
2336       XmGetXmScreen(XtScreen(dos));
2337     XmDragIconObject	sourceIcon;
2338     XmDragOverBlend		blend;
2339 
2340     /*
2341      *  (Re)generate a mixedIcon, in case we have a state
2342      *  change, or we have used the cursor cache up to this
2343      *  point.  Place the new mixedIcon so as to preserve the
2344      *  hotspot location.
2345      */
2346 
2347     if (dos->drag.rootBlend.sourceIcon) {
2348       sourceIcon = dos->drag.rootBlend.sourceIcon;
2349       blend = &dos->drag.rootBlend;
2350     } else {
2351       sourceIcon = dos->drag.cursorBlend.sourceIcon;
2352       blend = &dos->drag.cursorBlend;
2353     }
2354     MixIcons (dos, sourceIcon, dos->drag.stateIcon, dos->drag.opIcon,
2355 	      blend, False);
2356 
2357     /*
2358      *  Compute the new location and handle an icon size change.
2359      */
2360 
2361     BackingX(dos) = dos->core.x =
2362       dos->drag.hotX - blend->mixedIcon->drag.hot_x;
2363     BackingY(dos) = dos->core.y =
2364       dos->drag.hotY - blend->mixedIcon->drag.hot_y;
2365 
2366     if (dos->core.width != blend->mixedIcon->drag.width ||
2367 	dos->core.height != blend->mixedIcon->drag.height) {
2368       dos->core.width = blend->mixedIcon->drag.width;
2369       dos->core.height = blend->mixedIcon->drag.height;
2370       if (BackingPixmap(dos) != XmUNSPECIFIED_PIXMAP) {
2371 	_XmFreeScratchPixmap (xmScreen, BackingPixmap(dos));
2372 	BackingPixmap(dos) = XmUNSPECIFIED_PIXMAP;
2373       }
2374       if (dos->drag.tmpPix != XmUNSPECIFIED_PIXMAP) {
2375 	_XmFreeScratchPixmap (xmScreen, dos->drag.tmpPix);
2376 	dos->drag.tmpPix = XmUNSPECIFIED_PIXMAP;
2377       }
2378       if (dos->drag.tmpBit != XmUNSPECIFIED_PIXMAP) {
2379 	_XmFreeScratchPixmap (xmScreen, dos->drag.tmpBit);
2380 	dos->drag.tmpBit = XmUNSPECIFIED_PIXMAP;
2381       }
2382     }
2383 
2384     if (dos->drag.activeMode == XmDRAG_WINDOW &&
2385 	BackingPixmap(dos) != XmUNSPECIFIED_PIXMAP) {
2386       _XmFreeScratchPixmap (xmScreen, BackingPixmap(dos));
2387       BackingPixmap(dos) = XmUNSPECIFIED_PIXMAP;
2388     }
2389 
2390 
2391     /*
2392      *  Save the obscured root in backing.
2393      */
2394 
2395     if (dos->drag.activeMode == XmPIXMAP) {
2396       if (BackingPixmap(dos) == XmUNSPECIFIED_PIXMAP) {
2397 	BackingPixmap(dos) =
2398 	  _XmAllocScratchPixmap (xmScreen, dos->core.depth,
2399 				 dos->core.width, dos->core.height);
2400       }
2401 
2402       XSetClipMask (display, draw_gc, None);
2403       XCopyArea (display, RootWindowOfScreen(XtScreen(dos)),
2404 		 BackingPixmap(dos), draw_gc,
2405 		 BackingX(dos), BackingY(dos),
2406 		 dos->core.width, dos->core.height, 0, 0);
2407       DrawIcon (dos, blend->mixedIcon,
2408 		RootWindowOfScreen(XtScreen(dos)),
2409 		dos->core.x, dos->core.y);
2410     } else if (dos->drag.activeMode == XmWINDOW) {
2411       XSetWindowAttributes  xswa;
2412       XtPopup((Widget)dos, XtGrabNone);
2413       xswa.cursor = XmeGetNullCursor((Widget)dos);
2414       xswa.do_not_propagate_mask = _XmDRAG_EVENT_MASK(dc);
2415       XChangeWindowAttributes (display, XtWindow(dos),
2416 			       CWCursor|CWDontPropagate, &xswa);
2417       /*
2418        * don't call thru class record since VendorS bug may be
2419        * causing override
2420        */
2421       Redisplay((Widget)dos, NULL, NULL);
2422     } else { /* XmDRAG_WINDOW */
2423       /* Reposition before popping up */
2424       if (XtWindow(dos) != None)
2425 	XMoveWindow(XtDisplay(dos), XtWindow(dos),
2426 		    dos->core.x, dos->core.y);
2427       XtPopup((Widget)dos, XtGrabNone);
2428       if (dos->drag.activeMode == XmDRAG_WINDOW) {
2429 	Arg args[1];
2430 	if (!dos->drag.holePunched)
2431 	  DragOverShellPunchHole((Widget) dos);
2432 	if (dos->drag.installColormap)
2433 	  InstallColormap(dos);
2434 	XtSetArg(args[0], XmNbackgroundPixmap,
2435 		 dos->drag.rootBlend.mixedIcon->drag.pixmap);
2436 	XtSetValues((Widget) dos, args, 1);
2437       } else {
2438 	Redisplay((Widget) dos, NULL, NULL);
2439       }
2440     }
2441     dos->drag.isVisible = True;
2442   }
2443 }
2444 
2445 /************************************************************************
2446  *
2447  *  ChangeDragWindow ()
2448  *
2449  ***********************************************************************/
2450 
2451 static void
ChangeDragWindow(XmDragOverShellWidget dos)2452 ChangeDragWindow(XmDragOverShellWidget	dos)
2453 {
2454   Display		*display = XtDisplay((Widget)dos);
2455   Window		win = XtWindow((Widget)dos);
2456   GC			draw_gc = dos->drag.rootBlend.gc;
2457   XmScreen		xmScreen = (XmScreen) XmGetXmScreen(XtScreen(dos));
2458   XmDragIconObject	sourceIcon;
2459   XmDragOverBlend	blend;
2460   XmDragIconObject    mixedIcon;
2461   XmDragOverBlendRec	*cursorBlend = &dos->drag.cursorBlend;
2462   XGCValues           v;
2463   unsigned long       vmask;
2464 
2465     /*
2466      *  Blend a new mixedIcon using only the source icon.
2467      *  Place the new mixedIcon to preserve the source icon location.
2468      *  The current mixedIcon data is valid.
2469      */
2470 
2471   if (dos->drag.rootBlend.sourceIcon) {
2472     sourceIcon = dos->drag.rootBlend.sourceIcon;
2473     blend = &dos->drag.rootBlend;
2474   } else {
2475     sourceIcon = dos->drag.cursorBlend.sourceIcon;
2476     blend = &dos->drag.cursorBlend;
2477   }
2478   mixedIcon = blend->mixedIcon;
2479 
2480   XSetFunction (display, blend->gc, GXset);
2481   XFillRectangle (display, mixedIcon->drag.pixmap, blend->gc,
2482 		  0, 0, mixedIcon->drag.width, mixedIcon->drag.height);
2483 
2484   if (mixedIcon->drag.mask != XmUNSPECIFIED_PIXMAP) {
2485     if (cursorBlend->gc == NULL) {
2486       v.background = 0;
2487       v.foreground = 1;
2488       v.function = GXclear;
2489       v.graphics_exposures = False;
2490       v.subwindow_mode = IncludeInferiors;
2491       v.clip_mask = None;
2492       v.clip_x_origin = 0;	/* pedantic */
2493       v.clip_y_origin = 0;	/* pedantic */
2494       vmask = GCBackground|GCForeground|GCFunction|
2495 	GCClipXOrigin|GCClipYOrigin|GCClipMask|
2496 	  GCGraphicsExposures|GCSubwindowMode;
2497       cursorBlend->gc = XtAllocateGC((Widget) dos, 1,
2498 				     vmask, &v, vmask, 0L);
2499     } else {
2500       v.clip_mask = None;
2501       v.function = GXclear;
2502       vmask = GCClipMask|GCFunction;
2503       XChangeGC (display, cursorBlend->gc, vmask, &v);
2504     }
2505     XFillRectangle (display, mixedIcon->drag.mask, cursorBlend->gc,
2506 		    0, 0, mixedIcon->drag.width, mixedIcon->drag.height);
2507   }
2508 
2509   BlendIcon (dos, sourceIcon, mixedIcon, blend->sourceX,
2510 	     blend->sourceY, cursorBlend->gc, blend->gc);
2511 
2512   /*
2513    *  Remove the current drag window.
2514    */
2515   XUnmapWindow(display, win);
2516 
2517   /*
2518    *  Handle an icon size change.
2519    */
2520 
2521   if (dos->core.width != blend->mixedIcon->drag.width ||
2522       dos->core.height != blend->mixedIcon->drag.height) {
2523     if (BackingPixmap(dos) != XmUNSPECIFIED_PIXMAP) {
2524       _XmFreeScratchPixmap (xmScreen, BackingPixmap(dos));
2525       BackingPixmap(dos) = XmUNSPECIFIED_PIXMAP;
2526     }
2527     if (dos->drag.tmpPix != XmUNSPECIFIED_PIXMAP) {
2528       _XmFreeScratchPixmap (xmScreen, dos->drag.tmpPix);
2529       dos->drag.tmpPix = XmUNSPECIFIED_PIXMAP;
2530     }
2531     if (dos->drag.tmpBit != XmUNSPECIFIED_PIXMAP) {
2532       _XmFreeScratchPixmap (xmScreen, dos->drag.tmpBit);
2533       dos->drag.tmpBit = XmUNSPECIFIED_PIXMAP;
2534     }
2535   }
2536 
2537   /*
2538    *  Save the obscured root in backing.
2539    */
2540 
2541   if (BackingPixmap(dos) == XmUNSPECIFIED_PIXMAP) {
2542     BackingPixmap(dos) =
2543       _XmAllocScratchPixmap (xmScreen, dos->core.depth,
2544 			     dos->core.width, dos->core.height);
2545   }
2546   BackingX(dos) = dos->core.x;
2547   BackingY(dos) = dos->core.y;
2548 
2549   XSetClipMask (display, draw_gc, None);
2550   XCopyArea (display, RootWindowOfScreen(XtScreen(dos)),
2551 	     BackingPixmap(dos), draw_gc,
2552 	     BackingX(dos), BackingY(dos),
2553 	     dos->core.width, dos->core.height, 0, 0);
2554 
2555   /*
2556    *  Move, resize, and remap the drag window.
2557    *  This is an override_redirect window.
2558    */
2559   XMoveResizeWindow(display, win, dos->core.x, dos->core.y,
2560 		    dos->core.width, dos->core.height);
2561   XMapWindow(display, win);
2562 
2563   /*
2564    * don't call thru class record since VendorS bug may be
2565    * causing override
2566    */
2567   Redisplay((Widget)dos, NULL, NULL);
2568 }
2569 
2570 /************************************************************************
2571  *
2572  *  _XmDragOverMove ()
2573  *
2574  *  This method is less efficient than the obvious method of copying the
2575  *  backing to the root, saving the new icon destination in the backing,
2576  *  and copying the icon to the root.  However, it results in a smoother
2577  *  appearance.
2578  ***********************************************************************/
2579 
2580 void
_XmDragOverMove(Widget w,int x,int y)2581 _XmDragOverMove(
2582     Widget	w,
2583 #if NeedWidePrototypes
2584     int		x,
2585     int		y)
2586 #else
2587     Position	x,
2588     Position	y)
2589 #endif /* NeedWidePrototypes */
2590 {
2591     XmDragOverShellWidget	dos = (XmDragOverShellWidget) w;
2592     XmDragContext	dc = (XmDragContext)XtParent(dos);
2593     Display		*display = XtDisplay(w);
2594     XmScreen		xmScreen = (XmScreen) XmGetXmScreen(XtScreen(w));
2595     Window		root = RootWindowOfScreen(XtScreen(w));
2596     Pixmap		old_backing = BackingPixmap(dos);
2597     Pixmap		new_backing;
2598     GC			draw_gc = dos->drag.rootBlend.gc;
2599     XmDragIconObject	mixedIcon;
2600     XGCValues           v;
2601     unsigned long       vmask;
2602 
2603     dos->drag.hotX = x;
2604     dos->drag.hotY = y;
2605 
2606     if (!dos->drag.isVisible ||
2607 	dc->drag.blendModel == XmBLEND_NONE ||
2608 	dos->drag.activeMode == XmCURSOR) {
2609         return;
2610     }
2611 
2612     if (dos->drag.rootBlend.mixedIcon) {
2613         mixedIcon = dos->drag.rootBlend.mixedIcon;
2614     } else {	/* exists */
2615         mixedIcon = dos->drag.cursorBlend.mixedIcon;
2616     }
2617 
2618     dos -> core.x = x -= mixedIcon->drag.hot_x;
2619     dos -> core.y = y -= mixedIcon->drag.hot_y;
2620 
2621     if (dos->drag.activeMode == XmWINDOW ||
2622 	dos->drag.activeMode == XmDRAG_WINDOW) {
2623       /* this is an override_redirect window */
2624       XMoveWindow(display, XtWindow (w), x, y);
2625       return;
2626     }
2627 
2628     /*
2629      *  From here on, the active mode is XmPIXMAP.
2630      */
2631 
2632     if (dos->drag.tmpPix == XmUNSPECIFIED_PIXMAP) {
2633         dos->drag.tmpPix =
2634 	    _XmAllocScratchPixmap (xmScreen, dos->core.depth,
2635 	                           dos->core.width, dos->core.height);
2636     }
2637     new_backing = dos->drag.tmpPix;
2638 
2639     /*
2640      *  Save the area where the new icon is to go.
2641      */
2642 
2643     v.clip_mask = None;
2644     v.function = GXcopy;
2645     vmask = GCClipMask|GCFunction;
2646     XChangeGC (display, draw_gc, vmask, &v);
2647     XCopyArea (display, root, new_backing, draw_gc,
2648 	       x, y, dos->core.width, dos->core.height, 0, 0);
2649 
2650     if (x + ((Position) dos->core.width) > BackingX(dos) &&
2651 	x < BackingX(dos) + ((Position) dos->core.width) &&
2652 	y + ((Position) dos->core.height) > BackingY(dos) &&
2653 	y < BackingY(dos) + ((Position) dos->core.height)) {
2654 
2655 	XRectangle 	rect, rect1, rect2;
2656 	XPoint 		pt;
2657 
2658 	/*
2659 	 *  Have overlap:
2660 	 *
2661 	 *  Calculate the intersection between the 2 areas and
2662 	 *  copy the non-overlapping old area in the window.
2663 	 *
2664          *  If the icon has a mask, create a mask through which we will
2665 	 *  copy the old backing to the root.
2666 	 *  Otherwise, use one or two rectangles.
2667 	 */
2668 
2669         if (mixedIcon->drag.region == NULL &&
2670 	    mixedIcon->drag.mask != XmUNSPECIFIED_PIXMAP) {
2671 
2672 	    Pixmap	root_mask;
2673 	    GC		mask_gc = dos->drag.cursorBlend.gc;
2674 
2675 	    if (dos->drag.tmpBit == XmUNSPECIFIED_PIXMAP) {
2676 		dos->drag.tmpBit =
2677 		    _XmAllocScratchPixmap (xmScreen, 1, dos->core.width,
2678 					   dos->core.height);
2679 	    }
2680 	    root_mask = dos->drag.tmpBit;
2681 
2682     	    v.clip_mask = None;
2683     	    v.function = GXset;
2684     	    vmask = GCClipMask|GCFunction;
2685     	    XChangeGC (display, mask_gc, vmask, &v);
2686 	    XFillRectangle (display, root_mask, mask_gc,
2687 		            0, 0, dos->core.width, dos->core.height);
2688 
2689 	    XSetFunction (display, mask_gc, GXandInverted);
2690             XCopyArea (display, mixedIcon->drag.mask, root_mask, mask_gc,
2691 	               0, 0, mixedIcon->drag.width, mixedIcon->drag.height,
2692 	               x - BackingX(dos), y - BackingY(dos));
2693 
2694 	    /*
2695 	     *  Copy the icon into the new area and refresh the root.
2696 	     */
2697 
2698 	    DrawIcon (dos, mixedIcon, root, x, y);
2699 
2700     	    v.clip_mask = root_mask;
2701     	    v.clip_x_origin = BackingX(dos);
2702     	    v.clip_y_origin = BackingY(dos);
2703     	    vmask = GCClipMask|GCClipXOrigin|GCClipYOrigin;
2704     	    XChangeGC (display, draw_gc, vmask, &v);
2705             XCopyArea (display, old_backing, root, draw_gc,
2706 	               0, 0, dos->core.width, dos->core.height,
2707 	               BackingX(dos), BackingY(dos));
2708 	    XSetClipMask (display, draw_gc, None);
2709 	}
2710 	else {
2711 
2712 	    /*
2713 	     *  Copy the icon into the new area.
2714 	     */
2715 
2716 	    DrawIcon (dos, mixedIcon, root, x, y);
2717 
2718 	    /*
2719 	     *  Use rectangles to refresh exposed root.
2720 	     *  The first rectangle (horizontal movement).
2721 	     */
2722 
2723 	    if (x > BackingX(dos)) {
2724 	        rect1.x = 0;
2725 	        rect1.width = x - BackingX(dos);
2726 	    }
2727 	    else {
2728 	        rect1.width = BackingX(dos) - x;
2729 	        rect1.x = dos->core.width - rect1.width;
2730 	    }
2731 
2732 	    rect1.y = 0;
2733 	    rect1.height = dos->core.height;
2734 	    pt.x = BackingX(dos) + rect1.x;
2735 	    pt.y = BackingY(dos);
2736 
2737 	    if (rect1.width > 0) {
2738                 XCopyArea (display, old_backing, root, draw_gc,
2739 	                   rect1.x, rect1.y, rect1.width, rect1.height,
2740 		           pt.x, pt.y);
2741 	    }
2742 
2743 	    /*
2744 	     *  The second rectangle (vertical movement).
2745 	     */
2746 
2747 	    if (y > BackingY(dos)) {
2748 	        rect2.y = 0;
2749 	        rect2.height = y - BackingY(dos);
2750 	    }
2751 	    else {
2752 	        rect2.height = BackingY(dos) - y;
2753 	        rect2.y = dos->core.height - rect2.height;
2754 	    }
2755 
2756 	    rect2.x = 0;
2757 	    rect2.width = dos->core.width;
2758 	    pt.x = BackingX(dos);
2759 	    pt.y = BackingY(dos) + rect2.y;
2760 
2761 	    if (rect2.height > 0) {
2762                 XCopyArea (display, old_backing, root, draw_gc,
2763 	                   rect2.x, rect2.y, rect2.width, rect2.height,
2764 		           pt.x, pt.y);
2765 	    }
2766 	}
2767 
2768 	/*
2769 	 *  Copy the overlapping area between old_backing and
2770 	 *  new_backing into new_backing to be used for the
2771 	 *  next cursor move.
2772 	 */
2773 
2774 	if (x > BackingX(dos)) {
2775 	    rect.x = x - BackingX(dos);
2776 	    pt.x = 0;
2777 	    rect.width = dos->core.width - rect.x;
2778 	}
2779 	else {
2780 	    rect.x = 0;
2781 	    pt.x = BackingX(dos) - x;
2782 	    rect.width = dos->core.width - pt.x;
2783 	}
2784 
2785 	if (y > BackingY(dos)) {
2786 	    rect.y = y - BackingY(dos);
2787 	    pt.y = 0;
2788 	    rect.height = dos->core.height - rect.y;
2789 	}
2790 	else {
2791 	    rect.y = 0;
2792 	    pt.y = BackingY(dos) - y;
2793 	    rect.height = dos->core.height - pt.y;
2794 	}
2795 
2796 	XCopyArea (display, old_backing, new_backing, draw_gc,
2797 		   rect.x, rect.y, rect.width, rect.height, pt.x, pt.y);
2798 
2799         if (mixedIcon->drag.restore_region) {
2800             XSetRegion(display, draw_gc, mixedIcon->drag.restore_region);
2801             XSetClipOrigin(display, draw_gc, x, y);
2802             XCopyArea (display, new_backing, root,
2803                        draw_gc, 0, 0, dos->core.width,
2804                        dos->core.height, x, y);
2805             XSetClipMask(display, draw_gc, None);
2806         }
2807     }
2808     else {
2809 
2810 	/*
2811 	 *  No overlap:  refresh the root from old_backing.
2812 	 *  new_backing is valid.
2813 	 */
2814 
2815         XCopyArea (display, old_backing, root, draw_gc,
2816 	           0, 0, dos->core.width, dos->core.height,
2817 	           BackingX(dos), BackingY(dos));
2818 
2819 	DrawIcon (dos, mixedIcon, root, x, y);
2820     }
2821 
2822     /*  Update the variables needed for the next loop  */
2823 
2824     BackingX(dos) = x;
2825     BackingY(dos) = y;
2826     BackingPixmap(dos) = new_backing;
2827     dos->drag.tmpPix = old_backing;
2828 }
2829 
2830 /************************************************************************
2831  *
2832  *  _XmDragOverChange ()
2833  *
2834  *  Make dragover changes to track changes in component icons or colors.
2835  ***********************************************************************/
2836 
2837 void
_XmDragOverChange(Widget w,unsigned int dropSiteStatus)2838 _XmDragOverChange(
2839     Widget		w,
2840 #if NeedWidePrototypes
2841     unsigned int	dropSiteStatus)
2842 #else
2843     unsigned char	dropSiteStatus)
2844 #endif /* NeedWidePrototypes */
2845 {
2846     XmDragOverShellWidget	dos = (XmDragOverShellWidget) w;
2847     XmDragContext	dc = (XmDragContext)XtParent(dos);
2848     XmDragIconObject	sourceIcon = NULL;
2849     XmDragIconObject	opIcon = NULL;
2850     XmDragIconObject	stateIcon = NULL;
2851     Boolean		doChange, dirty = False;
2852     Boolean		usedSrcPixIcon = True;
2853 
2854     dos->drag.cursorState = dropSiteStatus;
2855 
2856     if (dos->drag.mode == XmWINDOW) {
2857       return;
2858     }
2859 
2860     if (dc->drag.blendModel == XmBLEND_NONE) {
2861 	return;
2862     }
2863 
2864     /*
2865      *  Get the sourceIcon.
2866      *  If we are in XmPIXMAP mode use the XmNsourcePixmapIcon if:
2867      *    1. it exists,
2868      *    2. it has the same screen as dos, and
2869      *    3. it has depth 1 or the same depth as dos.
2870      *  Otherwise, use the XmNsourceCursorIcon if:
2871      *    1. it exists,
2872      *    2. it has the same screen as dos, and
2873      *    3. is a bitmap.
2874      *  Otherwise, use the XmNdefaultSourceCursorIcon.
2875      */
2876 
2877     if (dos->drag.mode == XmPIXMAP ||
2878 	dos->drag.mode == XmDRAG_WINDOW ||
2879 	dos->drag.mode == XmWINDOW) {
2880       sourceIcon = dc->drag.sourcePixmapIcon;
2881     }
2882 
2883     if (sourceIcon == NULL ||
2884         XtScreenOfObject(XtParent(sourceIcon)) != XtScreen(w) ||
2885 	((sourceIcon->drag.depth != dos->core.depth) &&
2886 	 (sourceIcon->drag.depth != 1))) {
2887 
2888 	usedSrcPixIcon = False;
2889         sourceIcon = dc->drag.sourceCursorIcon;
2890 
2891 	if (sourceIcon == NULL ||
2892             XtScreenOfObject(XtParent(sourceIcon)) != XtScreen(w) ||
2893 	    sourceIcon->drag.depth != 1) {
2894 	    sourceIcon = _XmScreenGetSourceIcon (w); /* nonNULL */
2895 	}
2896     }
2897 
2898     /*
2899      *  Get the state and operation icons, according to the blending model.
2900      */
2901 
2902     switch ((int) dc->drag.blendModel) {
2903 
2904 	default:
2905 	    XmeWarning( (Widget) dc, MESSAGE4);
2906 	case XmBLEND_ALL:
2907 	    /*
2908 	     *  Get the operation icon bitmap.
2909 	     */
2910 
2911             opIcon = dc->drag.operationCursorIcon;
2912 
2913 	    if (opIcon == NULL || opIcon->drag.depth != 1 ||
2914 			XtScreenOfObject(XtParent(opIcon)) != XtScreen(w)) {
2915 	    	opIcon = _XmScreenGetOperationIcon (w,
2916 					            dc->drag.operation);
2917 	        if (opIcon && opIcon->drag.depth != 1) {
2918 	            opIcon = NULL;
2919 	        }
2920 	    }
2921 
2922 	    /* fall through */
2923 
2924 	case XmBLEND_STATE_SOURCE:
2925 	    /*
2926 	     *  Get the state icon bitmap.
2927 	     */
2928 
2929             stateIcon = dc->drag.stateCursorIcon;
2930 
2931 	    if (stateIcon == NULL || stateIcon->drag.depth != 1 ||
2932 			XtScreenOfObject(XtParent(stateIcon)) != XtScreen(w)) {
2933 	    	stateIcon = _XmScreenGetStateIcon (w,
2934 						   dropSiteStatus);
2935 	        if (stateIcon && stateIcon->drag.depth != 1) {
2936 	            stateIcon = NULL;
2937 	        }
2938 	    }
2939 	    break;
2940 
2941 	case XmBLEND_JUST_SOURCE:
2942 	    break;
2943     }
2944 
2945     /*
2946      *  Determine the cursor colors and create or recolor the root's gc.
2947      *  Record that a change is necessary if the cursor colors or any
2948      *  of the component icons have changed.
2949      */
2950 
2951     dirty = (_XmDragIconIsDirty (sourceIcon) ||
2952              (opIcon && _XmDragIconIsDirty (opIcon)) ||
2953 	     (stateIcon && _XmDragIconIsDirty (stateIcon)));
2954 
2955     doChange = GetDragIconColors (dos) ||
2956 	       dos->drag.opIcon != opIcon ||
2957                dos->drag.stateIcon != stateIcon ||
2958                dos->drag.rootBlend.sourceIcon != sourceIcon ||
2959 	       dirty;
2960 
2961     /*
2962      *  If we are not using the XmNsourcePixmapIcon, then try to create
2963      *  a cursor from the specified icons.  If we are successful, we will
2964      *  use the cursor in both cursor and pixmap mode.
2965      *  Remember:  XmNsourcePixmapIcon is only used in XmPIXMAP mode.
2966      */
2967 
2968     dos->drag.opIcon = opIcon;
2969     dos->drag.stateIcon = stateIcon;
2970     dos->drag.cursorBlend.sourceIcon = sourceIcon;
2971 
2972     if (!usedSrcPixIcon &&
2973         (dos->drag.activeCursor =
2974 	     GetDragIconCursor (dos, sourceIcon, stateIcon, opIcon,
2975 				False /* no clip */, dirty))
2976 	     != None) {
2977 	/*
2978 	 *  We have created a new cursor:  clean the icons.
2979 	 */
2980 
2981 	_XmDragIconClean (sourceIcon, stateIcon, opIcon);
2982 
2983 	if (dos->drag.activeMode != XmCURSOR) {
2984 	    _XmDragOverHide (w, 0, 0, None);
2985 	    dos->drag.activeMode = XmCURSOR;
2986 	}
2987 	XChangeActivePointerGrab (XtDisplay(w),
2988 				  (unsigned int) _XmDRAG_EVENT_MASK(dc),
2989 				  dos->drag.activeCursor,
2990 				  dc->drag.lastChangeTime);
2991 
2992 	/*
2993 	 *  We will use XmCURSOR active mode:  destroy any previously
2994 	 *  used rootBlend icon.
2995 	 */
2996 
2997 	dos->drag.rootBlend.sourceIcon = NULL;
2998 	if (dos->drag.rootBlend.mixedIcon) {
2999 	    DestroyMixedIcon (dos, dos->drag.rootBlend.mixedIcon);
3000 	    dos->drag.rootBlend.mixedIcon = NULL;
3001 	}
3002 	return;
3003     }
3004 
3005     /*
3006      *  Am using XmNsourcePixmapIcon or the cursor was too big.
3007      *  Save the sourceIcon for non-XmCURSOR active mode.
3008      */
3009 
3010     dos->drag.rootBlend.sourceIcon = sourceIcon;
3011 
3012     if (dos->drag.mode == XmCURSOR) {
3013 
3014     	/*
3015 	 *  XmCURSOR mode:  the cursor was too large for the hardware; clip
3016 	 *  it to the maximum hardware cursor size.
3017 	 */
3018 
3019 	dos->drag.activeCursor =
3020 	    GetDragIconCursor (dos, sourceIcon, stateIcon, opIcon,
3021 				True /* clip */, dirty);
3022 
3023 	_XmDragIconClean (sourceIcon, stateIcon, opIcon);
3024 	if (dos->drag.activeMode != XmCURSOR) {
3025 	    _XmDragOverHide (w, 0, 0, None);
3026 	    dos->drag.activeMode = XmCURSOR;
3027 	}
3028 	XChangeActivePointerGrab (XtDisplay(w),
3029 				  (unsigned int) _XmDRAG_EVENT_MASK(dc),
3030 				  dos->drag.activeCursor,
3031 				  dc->drag.lastChangeTime);
3032     }
3033 
3034     /*
3035      *  Else unable to use XmCURSOR activeMode in XmPIXMAP mode.
3036      *  Change activeMode to XmPIXMAP or XmDRAG_WINDOW.
3037      */
3038 
3039     else if (dos->drag.mode == XmPIXMAP) {
3040       if (doChange || dos->drag.activeMode != XmPIXMAP) {
3041 	_XmDragIconClean (sourceIcon, stateIcon, opIcon);
3042 	ChangeActiveMode (dos, XmPIXMAP);
3043       }
3044     } else /* DRAG_WINDOW */
3045       if (doChange || dos->drag.activeMode != XmDRAG_WINDOW) {
3046       _XmDragIconClean (sourceIcon, stateIcon, opIcon);
3047       ChangeActiveMode (dos, XmDRAG_WINDOW);
3048     }
3049 }
3050 
3051 /************************************************************************
3052  *
3053  *  _XmDragOverFinish ()
3054  *
3055  ***********************************************************************/
3056 
3057 void
_XmDragOverFinish(Widget w,unsigned int completionStatus)3058 _XmDragOverFinish(
3059     Widget		w,
3060 #if NeedWidePrototypes
3061     unsigned int	completionStatus)
3062 #else
3063     unsigned char	completionStatus)
3064 #endif /* NeedWidePrototypes */
3065 {
3066     XmDragOverShellWidget	dos = (XmDragOverShellWidget) w;
3067     XmDragContext	dc = (XmDragContext)XtParent(dos);
3068 /*
3069     GC			draw_gc = dos->drag.rootBlend.gc;
3070 */
3071 
3072     if (dc->drag.blendModel != XmBLEND_NONE) {
3073 
3074 /* If there could be some way to only do this code when we know that
3075  * there is animation being done under the drag over effects.  Maybe
3076  * add a XmDROP_ANIMATE completionStatus type?  XmDROP_ANIMATE would
3077  * be the same as XmDROP_SUCCESS, but it would also indicate that
3078  * animation is being done.  This code causes unecessary flashing
3079  * when animation is not being done.  It also fixes a bug the make
3080  * the melt effects look correct when the area under the icons has
3081  * changed.
3082 
3083 	XFlush (XtDisplay((Widget)dos));
3084         XSetClipMask (XtDisplay((Widget)dos), draw_gc, None);
3085 	XtPopdown(w);
3086         XCopyArea (XtDisplay((Widget)dos), RootWindowOfScreen(XtScreen(dos)),
3087 	           BackingPixmap(dos), draw_gc,
3088 	           BackingX(dos), BackingY(dos),
3089 	           dos->core.width, dos->core.height, 0, 0);
3090     	XtPopup(w, XtGrabNone);
3091 */
3092 	XGrabServer(XtDisplay(w));
3093 
3094 	/*
3095 	 *  Create and draw a source-only mixedIcon.
3096 	 *  Do not recolor it, even though the state is no longer used.
3097 	 *  Place the source-only mixedIcon so the source doesn't move.
3098 	 *
3099 	 *  The current active mode is XmWINDOW, so the blend data is valid.
3100 	 *  However, the backing may not be, since the server was ungrabbed.
3101 	 *  We keep the active mode as XmWINDOW and delay XtPopDown until
3102 	 *  the finish effects are finished to force the server to generate
3103 	 *  an expose event at the initial mixedIcon location.
3104 	 */
3105 
3106 	ChangeDragWindow (dos);
3107 
3108 	if (completionStatus == XmDROP_FAILURE) {
3109 	    /* generate zap back effects */
3110 	    DoZapEffect((XtPointer)dos, (XtIntervalId *)NULL);
3111 	}
3112 	else {
3113 	    /* generate melt effects */
3114 	    DoMeltEffect((XtPointer)dos, (XtIntervalId *)NULL);
3115 	}
3116 
3117 	XtPopdown(w);
3118 	dos->drag.isVisible = False;
3119 	XUngrabServer(XtDisplay(w));
3120     }
3121 }
3122 
3123 /************************************************************************
3124  *
3125  *  _XmDragOverGetActiveCursor ()
3126  *
3127  ***********************************************************************/
3128 
3129 Cursor
_XmDragOverGetActiveCursor(Widget w)3130 _XmDragOverGetActiveCursor(
3131     Widget	w)
3132 {
3133     XmDragOverShellWidget	dos = (XmDragOverShellWidget) w;
3134     return dos->drag.activeCursor;
3135 }
3136 
3137 /************************************************************************
3138  *
3139  *  _XmDragOverSetInitialPosition ()
3140  *
3141  ***********************************************************************/
3142 
3143 void
_XmDragOverSetInitialPosition(Widget w,int initialX,int initialY)3144 _XmDragOverSetInitialPosition(
3145     Widget	w,
3146 #if NeedWidePrototypes
3147     int		initialX,
3148     int		initialY)
3149 #else
3150     Position	initialX,
3151     Position	initialY)
3152 #endif /* NeedWidePrototypes */
3153 {
3154     XmDragOverShellWidget	dos = (XmDragOverShellWidget) w;
3155     dos->drag.initialX = initialX;
3156     dos->drag.initialY = initialY;
3157 }
3158 
3159 /* search up the tree to find the parent shell for whom colormapWidget
3160  * is a child widget. This is the shell on which the colormap is to be
3161  * installed.
3162  */
3163 static void
FindColormapShell(XmDragOverShellWidget dw)3164 FindColormapShell(XmDragOverShellWidget dw)
3165 {
3166     Widget cw = dw->drag.colormapWidget;
3167     Arg args[1];
3168 
3169     while (cw && !XtIsShell(cw))
3170 	cw = XtParent(cw);
3171     dw->drag.colormapShell = cw;
3172 
3173     /* find out if this shell is override redirect */
3174     XtSetArg(args[0], XmNoverrideRedirect, &dw->drag.colormapOverride);
3175     XtGetValues(cw, args, 1);
3176 }
3177 
3178 /* set the WmColormapWindows property on the parent shell to include dw's
3179  * colormap
3180  */
3181 static void
InstallColormap(XmDragOverShellWidget dw)3182 InstallColormap(XmDragOverShellWidget dw)
3183 {
3184     Status status;
3185     Window *windowsReturn;
3186     int countReturn;
3187 
3188     if (!dw->drag.colormapShell)
3189 	FindColormapShell(dw);
3190     if (dw->drag.colormapShell)
3191     {
3192 	/* check to see if there is a property */
3193 	status = XGetWMColormapWindows(XtDisplay(dw),
3194 				       XtWindow(dw->drag.colormapShell),
3195 				       &windowsReturn, &countReturn);
3196 	/* if no property, just create one */
3197 	if (!status)
3198 	{
3199 	    Window windows[2];
3200 	    windows[0] = XtWindow(dw);
3201 	    windows[1] = XtWindow(dw->drag.colormapShell);
3202 	    XSetWMColormapWindows(XtDisplay(dw),
3203 				  XtWindow(dw->drag.colormapShell),
3204 				  windows, 2);
3205 	}
3206 	/* there was a property, add myself to the beginning */
3207 	else
3208 	{
3209 	    Window *windows = (Window *)XtMalloc((sizeof(Window))*(countReturn+1));
3210 	    register int i;
3211 	    windows[0] = XtWindow(dw);
3212 	    for (i=0; i<countReturn; i++)
3213 		windows[i+1] = windowsReturn[i];
3214 	    XSetWMColormapWindows(XtDisplay(dw),
3215 				  XtWindow(dw->drag.colormapShell),
3216 				  windows, countReturn+1);
3217 	    XtFree((char*)windows);
3218 	    XtFree((char*)windowsReturn);
3219 	}
3220 	/* The window manager can't install colormaps for override redirect
3221 	 * windows.  So we have to do it ourselves using XInstallColormap.
3222 	 * This can confuse the window manager, so we save the current
3223 	 * colormap and reinstall it when we're done.
3224 	 *
3225 	 * Note this code does not work with twm, who will kick us out
3226 	 * upon seeing that we have installed a colormap.  But there
3227 	 * is nothing we can do about that until the consortium tells
3228 	 * us how to correctly install override redirect colormaps
3229 	 */
3230 	if (dw->drag.colormapOverride)
3231 	{
3232 	    dw->drag.savedColormaps = XListInstalledColormaps(
3233 					  XtDisplay(dw), XtWindow(dw),
3234 					  &dw->drag.numSavedColormaps);
3235 	    XInstallColormap(XtDisplay(dw), dw->core.colormap);
3236 	}
3237     }
3238 }
3239 
3240 /* set the WmColormapWindows property on the parent shell to exclude dw's
3241  * colormap
3242  */
3243 static void
UninstallColormap(XmDragOverShellWidget dos)3244 UninstallColormap(XmDragOverShellWidget dos)
3245 {
3246     Status status;
3247     Window *windowsReturn;
3248     int countReturn;
3249     register int i;
3250 
3251     if (!dos->drag.colormapShell)
3252 	FindColormapShell(dos);
3253     if (dos->drag.colormapShell)
3254     {
3255 	/* check to see if there is a property */
3256 	status = XGetWMColormapWindows(XtDisplay(dos),
3257 				       XtWindow(dos->drag.colormapShell),
3258 				       &windowsReturn, &countReturn);
3259 	/* if no property, just return.  If there was a property, continue */
3260 	if (status)
3261 	{
3262 	    /* search for a match */
3263 	    for (i=0; i<countReturn; i++)
3264 	    {
3265 		if (windowsReturn[i] == XtWindow(dos))
3266 		{
3267 		    /* we found a match, now copu the rest down */
3268 		    for (i++; i<countReturn; i++)
3269 		    {
3270 			windowsReturn[i-1] = windowsReturn[i];
3271 		    }
3272 		    XSetWMColormapWindows(XtDisplay(dos),
3273 					  XtWindow(dos->drag.colormapShell),
3274 					  windowsReturn, countReturn-1);
3275 		    break;	/* from outer for */
3276 		}
3277 	    }
3278 	    XtFree((char*)windowsReturn);
3279 	}
3280 	/* if this was an override window, we installed our own colormaps.
3281 	 * put them back.  (See comments in installColormap for more details
3282 	 */
3283 	if (dos->drag.colormapOverride)
3284 	{
3285 	    register int i;
3286 
3287 	    for (i=0; i<dos->drag.numSavedColormaps; i++)
3288 		XInstallColormap(XtDisplay(dos),
3289 				 dos->drag.savedColormaps[i]);
3290 	    XFree((char *)dos->drag.savedColormaps);
3291 	}
3292     }
3293 }
3294 
3295 /* The following function relies on the shape extension. */
3296 
3297 static void
DragOverShellPunchHole(Widget w)3298 DragOverShellPunchHole(Widget w)
3299 {
3300     static XmConst XRectangle pixelPunch = { 0, 0, 1, 1 };
3301     XmDragOverShellWidget dos = (XmDragOverShellWidget)w;
3302     XmDragIconObject icon = (dos->drag.rootBlend.mixedIcon ?
3303 			     dos->drag.rootBlend.mixedIcon :
3304 			     dos->drag.cursorBlend.mixedIcon);
3305 
3306     /* The following code requires an XtWindow, so we force the widget
3307      * to be realized if it isn't already
3308      */
3309     XtRealizeWidget(w);
3310 
3311     /* clear effects of previous shaping */
3312     XShapeCombineMask (XtDisplay(dos), XtWindow(dos),
3313 		       ShapeBounding,
3314 		       0, 0, None, ShapeSet);
3315 
3316     /* shape the outside of the window */
3317     if (icon && icon -> drag.mask)
3318     {
3319         if (icon -> drag.mask)
3320             XShapeCombineMask (XtDisplay(dos), XtWindow(dos),
3321 			 ShapeBounding, 0, 0,
3322 			 icon -> drag.mask, ShapeSet);
3323 
3324         /* punch a hole in the window */
3325         XShapeCombineRectangles (XtDisplay(dos), XtWindow(dos),
3326 			     ShapeBounding,
3327 			     icon->drag.hot_x, icon->drag.hot_y,
3328 			     (XRectangle*)&pixelPunch, 1,
3329 			     ShapeSubtract, YXBanded);
3330 
3331         dos->drag.holePunched = TRUE;
3332     }
3333 }
3334 
3335 static void
DragOverShellColormapWidget(Widget ds,Widget cw)3336 DragOverShellColormapWidget(Widget ds, Widget cw)
3337 {
3338     XmDragOverShellWidget dos = (XmDragOverShellWidget) ds;
3339 
3340     if (dos->drag.colormapWidget != cw)
3341     {
3342 	dos->drag.colormapWidget = cw;
3343 	dos->drag.colormapShell = NULL;
3344 	FindColormapShell(dos);
3345     }
3346 }
3347