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